Skip to main content
The embed is the editing surface. Your backend should still use the Moda Public API for account-level and workflow-level operations.

Let users choose a canvas

Use the Public API to list or search canvases, then create an embed session for the selected canvas. A canvas in either response is a CanvasItem. The title field is name (not title), and neither endpoint returns a thumbnail — render the picker from name/category/updated_at, or open the canvas to get a preview.
CanvasItem
The two endpoints use different envelope keys — list is cursor-paginated under data, search is a flat list under canvases:
List canvases — { data, next_cursor }
Search canvases — { canvases }
Page through the full list with next_cursor until it comes back null:

Build a canvas picker

Recommended flow:
  1. User opens your “Choose design” screen.
  2. Your backend calls GET /v1/canvases or GET /v1/canvases/search.
  3. Your frontend shows the result list.
  4. User selects a canvas.
  5. Your backend creates an embed session for that canvas.
  6. Your frontend loads the returned embed_url.
Do not create embed sessions for every canvas in the list. Create one only when the user opens a canvas.

Restrict canvases in an internal tool

Your app should remain the policy decision point. Moda can pin an embed session to one canvas, one mode, and one set of allowed browser origins, but your backend should decide which internal users may see or edit each canvas before creating the session. Recommended pattern:
  1. Store the mapping between your internal users, teams, projects, or roles and the Moda canvas IDs they may access.
  2. When a user opens your picker, call the Moda Public API from your backend and filter the results against that mapping before returning them to the browser.
  3. When the browser asks to open a canvas, do not trust the submitted canvas_id. Re-check the current internal user against your access mapping on the backend.
  4. Create the embed session only after that check passes.
  5. Set mode from your app’s authorization result. For example, reviewers get view-no-export or view; editors get edit.
  6. Set external_user.id to your stable internal user ID for attribution and audit trails.
  7. Revoke active sessions when the user signs out, changes role, or loses access to the underlying project.
Backend authorization sketch
For larger workspaces, avoid relying only on client-side filtering. Keep a server-side allowlist, project membership table, or policy check that runs both when listing canvases and when minting the embed session.

Save and autosave

Edit-mode embeds autosave after user edits. You can still call manual save before an important transition:
Listen for canvas:saved before closing a modal or advancing your workflow:

Use your own chat UI

Create sessions with:
Then send messages from your UI:
Render agent output from events:
Use chat.stop to cancel the active agent turn.

Insert user-uploaded images

If the user picks an image in your app, send the File to the iframe. The iframe uploads it through the embed image endpoint and inserts a real Moda image node. Embed uploads currently accept PNG, JPEG, GIF, and WebP files up to 25 MB. If you need SVG or larger asset handling, upload through your own workflow and pass a browser-renderable HTTPS URL to insertImage.
The user can also paste images directly into the iframe. The embed handles screenshots and image files from the clipboard.

Insert server-generated images

If your backend generates an image, prefer one of these: Example with a URL:

Export from the iframe

Use iframe export when the user needs the file immediately in the browser.
export:completed includes a dataUrl — the whole file inline as base64, with no size cap. This is fine for a single image, but a multi-page PDF/PPTX can be many megabytes in memory and is capped by a ~120s completion timeout. Use Public API export when your backend needs a durable export URL, background polling, caching, a server-side workflow, or whenever the document is large or multi-page:

Refresh long-running sessions

Sessions can last up to 3600 seconds. For long editing sessions:
  1. Track expires_at from session creation.
  2. Set a timer to refresh from your backend before expiry (for example, 60s ahead).
  3. Send the new token to the iframe with session.refresh; the iframe replies session:refreshed { expiresAt }.
Instead of computing your own timer, you can drive the refresh off the iframe’s proactive session:refresh_requested event, which fires ahead of expiry (by default 60 seconds before the browser token lapses):

Revoke on logout or close

Call revoke when access should end:
Your backend should call:

Should you build an API wrapper?

Most teams do best with two small clients: Avoid a browser SDK that exposes general Moda API calls. It would either leak your API key or require your backend to proxy every possible operation. A backend wrapper is useful if your app uses several Public API endpoints:
Keep the wrapper thin so you can call new Public API endpoints without waiting for a browser SDK release.