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 design template. 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[Pick a design template in the dashboard]
  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[POST /v1/design-templates from a reference image]
  A3 --> Generate[POST /v1/image-ads]
  B5 --> Generate
  Generate --> Wait[Poll or SSE 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. Pick a public design template from the library. Then use the API to read the resulting IDs.

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, templates] = 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()),
  fetch("https://api.staticadslab.com/v1/design-templates?status=completed", { 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 template = templates.data[0];

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

If you're going API-first (Path B), see the Concepts section for POST recipes, and chain them: brand → product → variants/images → audience → design template (this last one is async; see Design templates).

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({
    design_template_id: template.id,
    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, or stream via SSE. See Async jobs for both 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