Static Ads Lab
Concepts

Audiences

Target personas tied to a product. Audiences shape the ad copy and creative direction.

An audience is a target persona attached to a product — like "budget-conscious parents" or "millennial outdoor enthusiasts". When you generate an image ad, the audience steers the copy, tone, and creative direction.

Mental model

The same product, generated for two different audiences, produces two different ads. The audience's name and description are inputs to the AI copy and creative pipeline. Audiences are scoped to a product, not the brand — so a brand with three products has three independent audience pools.

ID prefix: aud_.

Fields

FieldTypeDescription
idstringaud_…
product_idstringOwning product (prod_…)
namestringShort persona name
descriptionstring | nullLong-form persona description; the more concrete, the better the output
detailsobject | nullFree-form audience metadata (interests, pain points, jobs-to-be-done)
duplicated_from_idstring | nullThe audience this one was duplicated from, if any
created_at / updated_atstringISO timestamps

Endpoints

MethodPathPurpose
POST/v1/audiencesCreate an audience
GET/v1/audiencesList audiences
GET/v1/audiences/:idGet an audience
PATCH/v1/audiences/:idUpdate an audience
DELETE/v1/audiences/:idDelete an audience
POST/v1/audiences/:id/duplicateDuplicate an audience

Duplicating

POST /v1/audiences/:id/duplicate creates an independent copy named "<name> - copy" on the same product. An archived audience still yields an active copy.

To copy an audience onto a different product, create it directly and set duplicated_from_id yourself — that records the same lineage while choosing the destination:

await fetch("https://api.staticadslab.com/v1/audiences", {
  method: "POST",
  headers: { "X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    product_id: "prod_other_product",
    name: "Technical Grapplers (18-40)",
    description: "…",
    duplicated_from_id: "aud_source",
  }),
});

Copies never sync. Editing either audience leaves the other unchanged, and duplicated_from_id keeps pointing at the source even after the source is deleted.

Common patterns

Create an audience

const response = await fetch("https://api.staticadslab.com/v1/audiences", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    product_id: "prod_YOUR_PRODUCT_ID",
    name: "Millennial Outdoor Enthusiasts",
    description:
      "25–40 year olds who hike weekends, follow outdoor influencers on Instagram, and care about sustainable materials.",
  }),
});
const { data } = await response.json();
console.log(data.id); // aud_...

Generate ads for multiple audiences

The classic batch pattern: one product, many audiences, one ad per (product, audience) pair.

const audienceIds = ["aud_a", "aud_b", "aud_c"];
const ads = await Promise.all(
  audienceIds.map((aud) =>
    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_YOUR_PRODUCT_ID",
        audience_id: aud,
      }),
    }).then((r) => r.json()),
  ),
);

Then batch-poll the resulting IDs.

Pitfalls

  • Vague descriptions produce generic ads. "People who like nature" is bad. "Weekend hikers in the Pacific Northwest who own at least one pair of trail shoes" is good.
  • A product can have many audiences. There's no public quota, but each audience burns wallet on every generation — be deliberate.

Prompt for your agent

Read https://www.staticadslab.com/docs/resources/audiences.mdx and create three distinct audiences for product prod_YOUR_PRODUCT_ID. Each should have a specific demographic, psychographic, and a clear pain point.