Figma sync
Round-trip an image ad through Figma using the Static Ads Lab plugin.
Static Ads Lab ships with a Figma plugin that lets you pull an image ad's JSON tree into Figma, edit it visually, and sync the result back to the API.
Prerequisites
- A completed image ad (
editor_supported: true). - The Static Ads Lab Figma plugin installed.
- Your API key in the plugin's settings.
Round-trip flow
sequenceDiagram
participant App as Your app
participant API as Static Ads Lab API
participant Figma as Figma + plugin
App->>API: POST /v1/image-ads
API-->>App: completed { current_json_tree }
Figma->>API: Plugin loads ad by ID
API-->>Figma: current_json_tree + figma_render_url
Note over Figma: User edits in Figma
Figma->>API: POST /v1/image-ads/sync (items)
API-->>Figma: 200 { results }
Note right of API: render in the background
App->>API: GET /v1/image-ads/:id/render-status
API-->>App: rendered_tree_revision == tree_revisionSync endpoint
The Figma plugin uses POST /v1/image-ads/sync to push edits back. Up to 10 ads per request:
await fetch("https://api.staticadslab.com/v1/image-ads/sync", {
method: "POST",
headers: {
"X-API-Key": process.env.SAL_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
items: [
{
id: "ia_...",
current_json_tree: updatedTree, // { schemaVersion: 2, colorProfile: "SRGB", root }
base_revision: 7, // optional: the tree_revision you loaded into Figma
figma_render_base64: "iVBORw0KGgo...", // raw base64, no data: prefix
},
],
}),
});Each item is handled on its own. An item with a current_json_tree is validated and saved as a new revision (tree_revision increments, and the previous state is kept as a version, iav_…), then the image renders in the background at 2×, the same way it does after a PATCH. Poll GET /v1/image-ads/:id/render-status until rendered_tree_revision equals tree_revision; a failed render shows in render_error and keeps the saved tree and the previous image. Send the optional per-item base_revision to get REVISION_CONFLICT for that item instead of overwriting a newer save. An item that fails gets status: "error" with VALIDATION_ERROR, INVALID_IMAGE_URL or REVISION_CONFLICT and details naming each path. It is left untouched, and the other items still sync. An editor still holding the previous revision gets 409 REVISION_CONFLICT on its next PATCH with base_revision.
You usually don't call this endpoint yourself — the plugin does it. But it's documented in case you're integrating Figma another way (e.g., a custom Figma extension).
When this is useful
- A designer needs to make pixel-perfect tweaks beyond what the JSON tree exposes.
- You want a human-in-the-loop step before publishing an ad.
- You're A/B-testing manual Figma variants against the AI baseline.
Pitfalls
- Sync only accepts ads the editor supports (
editor_supported: true). figma_render_base64is the raw PNG bytes, base64-encoded, without thedata:image/png;base64,prefix.- The full tree is required when you change it, as a schema-v2 document. If you only want to update the rendered PNG without overwriting the tree, omit
current_json_tree. - Use fonts we ship (Supported fonts) for the render to match Figma. A Figma-only font such as a local or paid font still syncs: our render draws it in Inter at the closest style, and the tree keeps the original font for Figma.
- Ads created before schema v2 are returned in the retired tree format, which sync does not accept. Generate them again to edit them.
- Up to 10 ads per call. Larger batches must be split.