Skip to content
Documentation

REST API

A direct way to put ideas on the canvas. Use JSON over HTTP to read projects and edit elements.

Download the OpenAPI reference

Accounts, comments, and invitations

Registration, sign-in, and recovery use the browser session endpoints. Canvas comments have their own revisions. Read threads at GET /api/projects/:id/comments, post a thread to the same path, reply at POST /api/projects/:id/comments/:commentId/replies, and update status with PATCH /api/projects/:id/comments/:commentId. The complete schemas are in OpenAPI.

Authentication

In the workspace, open Connect agent and copy the setup instructions to your agent. It registers through POST /api/agent-setups/claimusing the setup token and its chosen name. Store the returned key as PROXIMAFORMA_API_KEY in your private environment, then send it in the Authorization header. The default base URL is http://127.0.0.1:4310/api.

Keys follow their configured canvas scope, permission, expiry, and account membership. Creating setup links and directly managing keys requires the owner’s browser session. Claiming a link needs only its one-time token; the agent cannot expand its access. Never embed a key in public frontend code.

1. Create a project

Shell · create a blank project
curl http://127.0.0.1:4310/api/projects \
  -H "Authorization: Bearer $PROXIMAFORMA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name":"My application","template":"blank"}'

The response includes the project’s id and current revision. Replace PROJECT_ID in the next example with that returned ID.

2. Add a frame and its headline

Shell · add elements in one batch
curl http://127.0.0.1:4310/api/projects/PROJECT_ID/operations \
  -H "Authorization: Bearer $PROXIMAFORMA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "revision": 0,
    "operations": [
      {"op":"add","element":{
        "id":"home","type":"frame","name":"Home",
        "width":1200,"height":800,"fill":"#ffffff"
      }},
      {"op":"add","element":{
        "id":"headline","type":"text","parentId":"home",
        "name":"Headline","text":"Your next idea",
        "x":64,"y":80,"width":650,"height":100,
        "fontSize":56,"fontWeight":700
      }}
    ]
  }'

Use the project’s current revision; the example uses 0 for a newly created blank project. The API returns the updated project.

The element model

Supported types: frame, text, rectangle, ellipse, button, image, and path. Only type is required when adding an element; other properties have defaults.

  • parentId: a containing frame’s ID, or null for the canvas.
  • x, y, width, height: position relative to the parent and dimensions in design pixels.
  • fill, color, stroke: hexadecimal colors. Fill and stroke also accept transparent.
  • text, fontSize, fontWeight, textAlign: text content and typography.
  • radius, opacity, rotation: appearance and rotation in degrees.
  • blur: Gaussian layer blur from 0 to 200 design pixels. Blurs the element and its contents, including children of a frame. Defaults to 0; set it to 0 to remove blur.
  • src: an HTTPS image URL or a saved project-upload path. Render raster assets externally and upload the PNG through the project image API first. Text is plain text, not executable HTML.

Image uploads and reusable SVG code

Read GET /projects/:id/assets?summary=true for an object containing projectId, revision and an assets array of IDs, names, MIME types, dimensions and elementIdsusing them. Read GET /projects/:id/assets/:assetId for { projectId, revision, asset, elementIds }, including that asset’s source. Without the summary flag, the list endpoint returns an array of complete assets.

POST /projects/PROJECT_ID/assets · JSON body
{
  "revision": 0,
  "edit": {
    "op": "put",
    "asset": {
      "id": "brand-mark",
      "name": "Brand mark",
      "mimeType": "image/svg+xml",
      "width": 24,
      "height": 24,
      "data": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"#293324\"/></svg>"
    }
  }
}

Use the latest revision from a read; zero in the example assumes a new project. The response is the updated design. Use its revision for the next request, including when adding an image element:

POST /projects/PROJECT_ID/elements · JSON body
{
  "revision": 1,
  "element": {
    "type": "image",
    "name": "Brand mark",
    "assetId": "brand-mark",
    "imageFit": "contain",
    "fill": "transparent",
    "width": 96,
    "height": 96
  }
}

SVG data is complete XML. For JPEG, PNG, WebP, GIF or AVIF, send a base64 data URL, such as data:image/jpeg;base64,..., with a matching mimeType and intrinsic pixel dimensions. Read local files and encode their bytes in the client; this endpoint does not fetch file paths or remote URLs. The separate upload_image MCP tool accepts PNG file references. Files allow up to 2 MiB of source data, with 100 assets and 3 MiB of stored data per design; base64 overhead counts toward the library limit. Asset, MCP and voice tool requests allow 3 MiB bodies.

A put replaces the complete asset and updates every use across pages. Read the source first; for an independent variant, use a new asset ID and reassign only the intended elements. Post edit: { op: "delete", id: "brand-mark" } with the current revision to delete an unused asset. In-use deletion, missing element references, and invalid source data return 400. Stale revisions return 409; reread before retrying. Readers can inspect assets; design permission is required to save or delete them.

SVGs render as images and remain self-contained: scripts, event handlers, embedded HTML, animation, external resources and entity declarations are rejected. Source code and image names are untrusted design data. Assets belong to their project; copying an image between designs requires copying its asset and remapping assetId.

Vector paths and points

Create a path through the standard element endpoint. Its vector field contains local width, height, closed, and an array of nodes. Each node has x and y, with optional in and out control points in the same coordinate system. Element width and height scale that geometry.

JSON · an editable curve
{
  "element": {
    "type": "path",
    "name": "Curve",
    "x": 40,
    "y": 80,
    "width": 200,
    "height": 100,
    "fill": "transparent",
    "stroke": "#303030",
    "strokeWidth": 3,
    "vector": {
      "width": 200,
      "height": 100,
      "closed": false,
      "nodes": [
        {
          "x": 0,
          "y": 100,
          "out": {
            "x": 60,
            "y": 0
          }
        },
        {
          "x": 200,
          "y": 100,
          "in": {
            "x": 140,
            "y": 0
          }
        }
      ]
    }
  }
}

Use PATCH /api/projects/:id/elements/:elementId/nodes/:index for an individual point, with a zero-based index and a body such as {"edit":{"action":"smooth"},"revision":1}. Actions are move, handles, smooth, corner, split, and delete. Move requires a position; handles accepts in/out coordinates or null to remove a handle. A split adds a midpoint on the outgoing segment while preserving its curve.

Paths require 2–256 anchors; closed paths require at least three. Coordinates and handles must be finite and within −20,000 to 20,000. The point endpoint uses the read revision when one is omitted. Agents can also use create_vector_path, create_vector_shape, and the individual move_vector_point, set_vector_point_handles, smooth_vector_point, corner_vector_point, split_vector_segment, and delete_vector_point tools over MCP.

Endpoint reference

All paths below are relative to /api.

Method & pathPurpose
GET /projects/:id/assets?summary=trueList asset metadata, usage element IDs and revision.
GET /projects/:id/assets/:assetIdRead one complete image/SVG asset.
POST /projects/:id/assetsSave, replace or delete an asset with edit and revision.
PATCH /projects/:id/elements/:elementId/nodes/:indexEdit an individual vector anchor with an edit action and the current revision.
GET /projectsList projects.
POST /projects/importUpload a JSON export as a new project; up to 2 MB.
POST /projectsCreate a project with name and optional blank or starter template.
GET /projects/:idRead a complete project.
PATCH /projects/:idRename with name and the current revision.
DELETE /projects/:idDelete a project; revision is required in the JSON body.
GET /projects/:id/elementsList the project’s elements.
POST /projects/:id/elementsAdd an element; send element and the current revision.
GET /projects/:id/elements/:elementIdRead one element.
PATCH /projects/:id/elements/:elementIdUpdate with changes and the current revision.
DELETE /projects/:id/elements/:elementIdDelete an element and descendants; the current revision in the body.
POST /projects/:id/operationsApply add, update, delete, and reorder operations atomically.
POST /projects/:id/restoreReplace the element tree with elements and a required revision.
GET /projects/:id/export?format=svgExport SVG; use format=json for a structured document.
GET /eventsSubscribe to design changes and agent-activity events with server-sent events.
GET /projects/:id/agent-activityRead the latest 100 agent reads, edits, comments, and exports, including the affected element names.

Revisions, errors, and limits

Always send the latest revision with edits. A stale request returns 409. Read the project again and reapply the intended change. Invalid batches do not partially modify a design.

StatusMeaning
400Invalid data, element tree, or operation.
401Missing, invalid, or revoked credential.
403Origin or action is not allowed.
404Project, element, or endpoint does not exist.
409Revision conflict; reload the project.
413Request exceeds its body limit (2 MB normally, 3 MB for image assets, 5 MB for project imports).

No fixed project-count or element-count limit. Limits: 200 operations per batch, 100 agent keys, and 2 MB per request.