Static Ads Lab

Build your first Meta image ad

Zero to a Meta-ready PNG in under five minutes — covering both the UI-first and API-first setup paths.

By the end of this page you will have generated a Meta image ad through the Static Ads Lab API and downloaded a Meta-ready PNG.

Prerequisites

Two things need to be set up in the dashboard — they're the only steps the API can't do for you. Everything else is API-driven.

  1. A Static Ads Lab account. Sign up — onboarding takes a couple of minutes.
  2. Wallet balance. Top up at Settings → Billing. A flat image ad costs $1.00; an editable image ad costs $4.00.
  3. An API key. Create one at Settings → API Keys. It starts with sal_live_ and is shown only once — store it somewhere safe.

Pick a setup path

Once you have an account, an API key, and wallet balance, you need a brand, a product, an audience, and a public reference ad URL. There are two ways:

flowchart TD
  Start[Have account, API key, and wallet]
  Start --> Path[Pick a setup path]
  Path --> A[Path A — UI-first]
  Path --> B[Path B — API-first]
  A --> A1[Onboarding flow auto-creates brand, product, audience]
  A1 --> A2[Choose a reference ad URL]
  A2 --> A3[Use the API to GET those resource IDs]
  B --> B1[POST /v1/brands]
  B1 --> B2[POST /v1/products]
  B2 --> B3[POST /v1/product-variants and /v1/images]
  B3 --> B4[POST /v1/audiences]
  B4 --> B5[Choose a public reference ad URL]
  A3 --> Generate[POST /v1/image-ads]
  B5 --> Generate
  Generate --> Wait[Poll until completed]
  Wait --> PNG[Meta-ready PNG]

Path A — UI-first (recommended, fastest). Run the onboarding flow — paste your Shopify URL and the dashboard auto-extracts your brand, products, and a recommended audience. Then use the API to read the resulting IDs and supply a public reference_ad_url when generating ads.

Path B — API-first. Build everything from scratch via the API. More work, but the right path if you're integrating Static Ads Lab as a backend for a multi-tenant product where each tenant brings their own brand data.

The rest of this tutorial works for both paths — once you have IDs, the generation flow is identical.

With an AI coding agent

If you'd rather have Claude Code, Cursor, or Codex drive this for you, paste the prompt at the top of this page and answer the questions it asks.

With code

1. Verify your API key

const response = await fetch("https://api.staticadslab.com/v1/account", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const { data } = await response.json();
console.log(data.organization.name);
console.log(data.api_key.scopes);

If the call fails with 401, re-check that the key is sal_live_… and the header is X-API-Key (not Authorization: Bearer).

2. Get your resource IDs

If you ran onboarding (Path A), list the resources to grab the IDs:

const headers = { "X-API-Key": "YOUR_API_KEY" };

const [brands, products, audiences] = await Promise.all([
  fetch("https://api.staticadslab.com/v1/brands", { headers }).then((r) => r.json()),
  fetch("https://api.staticadslab.com/v1/products", { headers }).then((r) => r.json()),
  fetch("https://api.staticadslab.com/v1/audiences", { headers }).then((r) => r.json()),
]);

const brand = brands.data[0];
const product = products.data.find((p) => p.brand_id === brand.id);
const audience = audiences.data.find((a) => a.product_id === product.id);
const referenceAdUrl = "https://cdn.example.com/reference-ad.png";

console.log({ brand: brand.id, product: product.id, audience: audience.id, referenceAdUrl });

If you're going API-first (Path B), see the Concepts section for POST recipes, and chain them: brand → product → variants/images → audience. Then provide a public reference_ad_url when creating the image ad.

3. Create an image 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: referenceAdUrl,
    brand_id: brand.id,
    product_id: product.id,
    audience_id: audience.id,
  }),
});

const { data } = await response.json();
console.log(data.id);     // ia_...
console.log(data.status); // "processing"

The API returns 202 Accepted with the ad in processing status.

4. Wait for completion

Image ads take 30–60 seconds. Poll every 4 seconds until status is completed or failed. See Async jobs for polling and batch polling patterns.

async function waitForCompletion(adId) {
  const headers = { "X-API-Key": "YOUR_API_KEY" };
  while (true) {
    const r = await fetch(`https://api.staticadslab.com/v1/image-ads/${adId}`, { headers });
    const { data } = await r.json();
    if (data.status === "completed") return data;
    if (data.status === "failed") throw new Error(data.error?.message ?? "failed");
    await new Promise((res) => setTimeout(res, 4000));
  }
}

const completed = await waitForCompletion(data.id);
console.log(completed.image_url);

The image_url is your Meta-ready PNG. Download it, upload it to Meta Ads Manager, or pass it to your own pipeline.

What's next