Embed

Embed

These routes back the embeddable studio. The first two are reachable anonymously with just an embed id; the rest require the short-lived embed session bearer token minted by the second one.

Embed

GET /v1/embed/:embedId

GET/v1/embed/:embedId

Public embed info — branding and enabled toggles. No authentication required; safe to call from an anonymous browser.

Response
{
  "enabled": true,
  "brandTitle": "Acme Studio",
  "brandIconUrl": "https://.../icon.png",
  "brandAccentColor": "#FB923C",
  "downloadsEnabled": true,
  "assetPickerEnabled": false,
  "smartResizeEnabled": true,
  "allowedDomains": ["app.example.com"]
}

allowedDomains is intentionally public — it is what drives the embedding page's own frame-ancestors CSP, so a browser can enforce it before the page even loads.

Embed

POST /v1/embed/:embedId/session

POST/v1/embed/:embedId/session

Mint a short-lived embed session bearer token. The embed page calls this itself when it loads; every visitor gets the same access to the workspace's templates.

Response
{
  "token": "femb_...",
  "expiresIn": 3600,
  "config": {
    "enabled": true,
    "brandTitle": "Acme Studio",
    "brandIconUrl": "https://.../icon.png",
    "brandAccentColor": "#FB923C",
    "downloadsEnabled": true,
    "assetPickerEnabled": false,
    "smartResizeEnabled": true,
    "allowedDomains": ["app.example.com"]
  }
}

The body takes no fields. A userId sent by older embed snippets is accepted and ignored — embed sessions identify no end user.

Embed

GET /v1/embed/:embedId/templates

GET/v1/embed/:embedId/templatesscope: template:read

List the workspace's templates. Every visitor of the embed sees the same list.

Authenticated with the embed session token from Authorization: Bearer femb_…, not an API key.

Embed

POST /v1/embed/:embedId/templates

POST/v1/embed/:embedId/templatesscope: template:write

Create a template in the workspace, shared with every visitor. Sends the template.created webhook.

Embed

GET /v1/embed/:embedId/templates/:templateId

GET/v1/embed/:embedId/templates/:templateIdscope: template:read

The editable design document, for the embedded studio to open.

Embed

PUT /v1/embed/:embedId/templates/:templateId

PUT/v1/embed/:embedId/templates/:templateIdscope: template:write

Save the design document (embedded editor autosave). One template.updated webhook follows once the editing goes quiet.

Embed

POST /v1/embed/:embedId/templates/:templateId/editing-done

POST/v1/embed/:embedId/templates/:templateId/editing-donescope: template:write

Tell BuildOnce the embedded studio was closed. A template.updated webhook normally waits until autosaving goes quiet for 2 minutes — this sends it at once instead, so the host doesn't have to wait on a user who just left.

No body. Responds 204 with no content.

Embed

POST /v1/embed/:embedId/templates/:templateId/render

POST/v1/embed/:embedId/templates/:templateId/renderscope: render:write

Rasterize the current draft. Gated by the embed's Downloads toggle — a session without downloadsEnabled won't hold the render:write scope needed here. A video (mp4, webm, gif) answers 202 { renderId, status } while it draws; an image answers in full.

ParamTypeNotes
video.fpsnumberFrames per second. Default 30 (gif: 15, its maximum).
video.scale0.5 | 1 | 2A multiple of the design's size. Double (2) stops at 2160px on the longest side; a GIF is never scaled up. Same price at every size.
video.qualitysmall | standard | highMP4/WebM encoder quality. Ignored for GIF.
Embed

GET /v1/embed/:embedId/renders/:renderId

GET/v1/embed/:embedId/renders/:renderIdscope: render:write

A render's status after a 202: queued, processing, succeeded (with its files) or failed. Gated by the Downloads toggle.

Was this page helpful?