Concepts
Image ads
The core API output — Meta-ready PNGs generated from a reference ad, brand, product, and audience.
An image ad is the API output. You combine a reference ad image 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) — analyzesreference_ad_url, creates a new Perfect Ad, and returns a single 4K PNG. Use for high-volume, "generate-and-launch" workflows. - Editable image ad (
editable_image_ad, $4.00) — creates a Perfect Ad, fresh-reverse-engineers it into an editable JSON tree, and renders the final ad. 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_… |
reference_ad_url / brand_id / product_id / audience_id | string | Inputs |
design_template_id | string | null | Historical template source for legacy rows. New rows return null |
product_variant_id | string | null | Optional variant override |
prompt | string | null | Free-form creative direction |
options | object | null | Reserved for legacy/internal rows. New public requests omit it |
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 |
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({
reference_ad_url: "https://cdn.example.com/reference-ad.png",
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({
reference_ad_url: "https://cdn.example.com/reference-ad.png",
brand_id: "brand_...",
product_id: "prod_...",
audience_id: "aud_...",
editable: true,
}),
});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.reference_ad_urlmust be a publicly accessible image URL.- 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({ referenceAdUrl, brandId, productId, audienceId, editable }) that creates an ad, polls every 4 seconds until completed, and returns the result. Throw on failed.