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.
- A Static Ads Lab account. Sign up — onboarding takes a couple of minutes.
- Wallet balance. Top up at Settings → Billing. A flat image ad costs $1.00; an editable image ad costs $4.00.
- 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.