Concepts
Image ads
The core API output — Meta-ready PNGs generated from a brand, product, audience, and design template.
An image ad is the API output. You combine a design template with a brand, product, and audience, and the API generates a Meta-ready PNG asynchronously.
Mental model
Two SKUs:
- Flat image ad (
flat_image_ad, $1.00) — runs the Perfect Ad pipeline only. Output: a single 4K PNG. Use for high-volume, "generate-and-launch" workflows. - Editable image ad (
editable_image_ad, $4.00) — runs the full pipeline (concept → Perfect Ad → image generation → template population → polish → final render). Output: a PNG plus a JSON tree you can mutate viaPATCHand re-render. See Editable image ads.
ID prefix: ia_.
Fields
| Field | Type | Description |
|---|---|---|
id | string | ia_… |
design_template_id / brand_id / product_id / audience_id | string | Inputs |
product_variant_id | string | null | Optional variant override |
prompt | string | null | Free-form creative direction |
options | object | null | generate_ai_images, generate_copy toggles |
editable | boolean | If true, ran the editable pipeline |
sku_code | enum | flat_image_ad or editable_image_ad |
status | enum | processing | completed | failed |
progress | object | null | { step, message, percentage } while processing |
image_url | string | null | Meta-ready PNG (when complete) |
width / height | number | null | Pixel dimensions |
current_json_tree | object | null | Editable JSON tree (only for editable ads) |
figma_render_url / initial_figma_render_url | string | null | Figma sync renders |
error | object | null | { code, message } when failed |
duration_ms | number | null | Worker wall-clock time |
batch_id | string | null | Set when generated as part of a batch |
created_at / completed_at | string | ISO timestamps |
Lifecycle
stateDiagram-v2
[*] --> processing: POST /v1/image-ads (202)
processing --> completed: image_url ready
processing --> failed: error populated
completed --> [*]
failed --> [*]You're billed only on completed. failed jobs do not deduct from your wallet.
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /v1/image-ads | Generate an image ad |
GET | /v1/image-ads | List image ads (supports ids=, status=, batch_id=) |
GET | /v1/image-ads/:id | Get an image ad (supports Accept: text/event-stream for SSE) |
PATCH | /v1/image-ads/:id | Update the JSON tree (editable only) |
DELETE | /v1/image-ads/:id | Delete an image ad |
POST | /v1/image-ads/sync | Sync from Figma |
GET | /v1/image-ads/:id/versions | List versions (editable only) |
GET | /v1/image-ads/:id/versions/:versionId | Get a version |
Common patterns
Generate a flat ad
const response = 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_...",
}),
});
const { data } = await response.json();
// data.id, data.status === "processing"Generate an editable ad
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,
}),
});Override specific text or images before generation
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_...",
node_overrides: {
"node-id-headline": { characters: "Limited time: 25% off" },
"node-id-hero": { imageFillUrl: "https://cdn.example.com/hero.jpg" },
},
}),
});Batch poll
When generating many ads, poll them in one request rather than N:
const ids = ["ia_a", "ia_b", "ia_c"].join(",");
const response = await fetch(
`https://api.staticadslab.com/v1/image-ads?ids=${ids}`,
{ headers: { "X-API-Key": "YOUR_API_KEY" } },
);
const { data } = await response.json();
const stillProcessing = data.filter((d) => d.status === "processing");See Batch generation and Async jobs.
Pitfalls
product_idandbrand_idmust be linked. Using a product that doesn't belong to the brand returns422.- The design template must be in
status: "completed"before you can use it. - Don't poll faster than every 2 seconds. 4 seconds is the recommended interval for image ads.
- For editable ads, the
current_json_treeisnulluntil generation completes — wait forstatus: "completed"before reading it.
Related
Prompt for your agent
Read https://www.staticadslab.com/docs/resources/image-ads.mdx and write generateAd({ designTemplateId, brandId, productId, audienceId, editable }) that creates an ad, polls every 4 seconds until completed, and returns the result. Throw on failed.