Editable image ads
PNG plus a structured JSON tree you can mutate via PATCH and re-render. Versioned and Figma-syncable.
An editable image ad is an image ad generated with
"editable": true. In addition to the Meta-ready PNG, you get a JSON tree — a structured document representing every visual element. You canPATCHthe tree to change text, images, colors, or layout, and the API re-renders the PNG.
When to use editable ads
- You're building a custom ad editor on top of the API.
- You want programmatic ad variants (e.g., 50 ads with the same layout but different headlines).
- You want to round-trip an ad through Figma — see Figma sync.
If you just need one Meta-ready PNG and don't intend to modify it, use a flat image ad — it's $1.00 vs $4.00.
Lifecycle
stateDiagram-v2
[*] --> processing: POST editable=true (202)
processing --> completed: image_url + current_json_tree ready
processing --> failed
completed --> patched: PATCH /v1/image-ads/:id
patched --> completed: re-render done
completed --> [*]Every successful PATCH creates a new version (iav_…) you can list and replay.
Endpoints
All editable ads share the Image ads endpoints. The editable-only endpoints are:
| Method | Path | Purpose |
|---|---|---|
PATCH | /v1/image-ads/:id | Update the JSON tree |
GET | /v1/image-ads/:id/versions | List versions |
GET | /v1/image-ads/:id/versions/:versionId | Get a specific version |
POST | /v1/image-ads/sync | Sync from Figma |
Common patterns
Generate, then change a headline
const create = await fetch("https://api.staticadslab.com/v1/image-ads", {
method: "POST",
headers: { "X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
design_template_id: "dt_...",
brand_id: "brand_...",
product_id: "prod_...",
audience_id: "aud_...",
editable: true,
}),
});
const { data: created } = await create.json();
const ad = await waitForCompletion(created.id);
const headlineNodeId = findNodeIdByRole(ad.current_json_tree, "headline");
ad.current_json_tree.nodes[headlineNodeId].characters = "Black Friday: 40% off";
await fetch(`https://api.staticadslab.com/v1/image-ads/${ad.id}`, {
method: "PATCH",
headers: { "X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({ current_json_tree: ad.current_json_tree }),
});A PATCH re-renders the PNG asynchronously; the resource returns to status: "processing" and back to completed when the new render is ready. Poll GET /v1/image-ads/:id until the new image_url is available.
Use node_overrides instead of PATCH
If you know upfront which nodes you want to override, use node_overrides at creation time. It's simpler and skips the patch round-trip:
await fetch("https://api.staticadslab.com/v1/image-ads", {
method: "POST",
headers: { "X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
design_template_id: "dt_...",
brand_id: "brand_...",
product_id: "prod_...",
audience_id: "aud_...",
editable: true,
node_overrides: {
"node-id-headline": { characters: "Black Friday: 40% off" },
"node-id-hero": {
imageFillUrl: "https://cdn.example.com/black-friday-hero.jpg",
},
},
}),
});Override values are applied verbatim and never modified by the AI pipeline.
List versions
const response = await fetch(
`https://api.staticadslab.com/v1/image-ads/${adId}/versions`,
{ headers: { "X-API-Key": "YOUR_API_KEY" } },
);
const { data } = await response.json();
data.forEach((v) => console.log(v.version_number, v.image_url));Pitfalls
current_json_treeis alwaysnullfor flat ads. If you need to modify, you must request"editable": trueat creation time. There is no path to convert a flat ad into an editable one.- A
PATCHreturns the resource asprocessingwhile the new render runs. Don't readimage_urluntil you seecompletedagain. - Image fills must be public URLs in
imageFillUrl. The API does not accept base64 image data in JSON. - Versions are immutable. Once written, a version's
json_treeandimage_urlcannot be changed.
Related
Prompt for your agent
Read https://www.staticadslab.com/docs/resources/editable-image-ads.mdx and write a function patchHeadline(adId, newHeadline) that updates an editable ad's headline node and waits for the re-render to complete.