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.
GET /v1/embed/:embedId
/v1/embed/:embedIdPublic embed info — branding and enabled toggles. No authentication required; safe to call from an anonymous browser.
{
"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.
POST /v1/embed/:embedId/session
/v1/embed/:embedId/sessionMint 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.
{
"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.
GET /v1/embed/:embedId/templates
/v1/embed/:embedId/templatesscope: template:readList 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.
POST /v1/embed/:embedId/templates
/v1/embed/:embedId/templatesscope: template:writeCreate a template in the workspace, shared with every visitor. Sends the template.created webhook.
GET /v1/embed/:embedId/templates/:templateId
/v1/embed/:embedId/templates/:templateIdscope: template:readThe editable design document, for the embedded studio to open.
PUT /v1/embed/:embedId/templates/:templateId
/v1/embed/:embedId/templates/:templateIdscope: template:writeSave the design document (embedded editor autosave). One template.updated webhook follows once the editing goes quiet.
POST /v1/embed/:embedId/templates/:templateId/editing-done
/v1/embed/:embedId/templates/:templateId/editing-donescope: template:writeTell 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.
POST /v1/embed/:embedId/templates/:templateId/render
/v1/embed/:embedId/templates/:templateId/renderscope: render:writeRasterize 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.
| Param | Type | Notes |
|---|---|---|
| video.fps | number | Frames per second. Default 30 (gif: 15, its maximum). |
| video.scale | 0.5 | 1 | 2 | A 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.quality | small | standard | high | MP4/WebM encoder quality. Ignored for GIF. |
GET /v1/embed/:embedId/renders/:renderId
/v1/embed/:embedId/renders/:renderIdscope: render:writeA render's status after a 202: queued, processing, succeeded (with its files) or failed. Gated by the Downloads toggle.
Was this page helpful?