Static Ads Lab
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) — analyzes reference_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 via PATCH and re-render. See Editable image ads.

ID prefix: ia_.

Fields

FieldTypeDescription
idstringia_…
reference_ad_url / brand_id / product_id / audience_idstringInputs
design_template_idstring | nullHistorical template source for legacy rows. New rows return null
product_variant_idstring | nullOptional variant override
promptstring | nullFree-form creative direction
optionsobject | nullReserved for legacy/internal rows. New public requests omit it
editablebooleanIf true, ran the editable pipeline
sku_codeenumflat_image_ad or editable_image_ad
statusenumprocessing | completed | failed
progressobject | null{ step, message, percentage } while processing
image_urlstring | nullMeta-ready PNG (when complete)
width / heightnumber | nullPixel dimensions
current_json_treeobject | nullEditable JSON tree (only for editable ads)
figma_render_url / initial_figma_render_urlstring | nullFigma sync renders
errorobject | null{ code, message } when failed
duration_msnumber | nullWorker wall-clock time
batch_idstring | nullSet when generated as part of a batch
created_at / completed_atstringISO 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

MethodPathPurpose
POST/v1/image-adsGenerate an image ad
GET/v1/image-adsList image ads (supports ids=, status=, batch_id=)
GET/v1/image-ads/:idGet an image ad
PATCH/v1/image-ads/:idUpdate the JSON tree (editable only)
DELETE/v1/image-ads/:idDelete an image ad
POST/v1/image-ads/syncSync from Figma
GET/v1/image-ads/:id/versionsList versions (editable only)
GET/v1/image-ads/:id/versions/:versionIdGet 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_id and brand_id must be linked. Using a product that doesn't belong to the brand returns 422.
  • reference_ad_url must 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_tree is null until generation completes — wait for status: "completed" before reading it.

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.