Static Ads Lab
Concepts

Product variants

SKUs of a product (sizes, colors, bundles) that carry their own images for ad generation.

A product variant is a specific SKU of a product — a size, color, bundle, or other variation. Each variant has its own ordered list of images that the API uses during image ad generation.

Mental model

If your product is "Trail Runner Pro", variants are "Red / 10", "Black / 11", "Limited Edition Blue". When you generate an image ad and pass product_variant_id, the API uses that variant's images instead of the default product images. Useful when different SKUs need different hero shots.

ID prefix: pv_.

Fields

FieldTypeDescription
idstringpv_…
product_idstringOwning product (prod_…)
namestringVariant name (e.g., "Red / Large")
sort_ordernumberDisplay sort order
image_idsstring[]Ordered list of image IDs (img_…) for this variant
duplicated_from_idstring | nullThe variant this one was duplicated from, if any
created_at / updated_atstringISO timestamps

Endpoints

MethodPathPurpose
POST/v1/product-variantsCreate a variant
GET/v1/product-variantsList variants
GET/v1/product-variants/:idGet a variant
PATCH/v1/product-variants/:idUpdate a variant
DELETE/v1/product-variants/:idDelete a variant
POST/v1/product-variants/:id/duplicateDuplicate a variant

Common patterns

Create a variant with images

const response = await fetch("https://api.staticadslab.com/v1/product-variants", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    product_id: "prod_YOUR_PRODUCT_ID",
    name: "Red / Large",
    image_ids: ["img_red_lg_hero", "img_red_lg_lifestyle"],
  }),
});

Use a variant when generating an image 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_...",
    product_variant_id: "pv_red_lg",
  }),
});

Duplicate a variant to reshoot it

The most common reason to duplicate: you want the same SKU shot with a different model or in a different setting. The copy arrives attached to the same images, so you swap them out rather than starting from an empty variant.

const response = await fetch(
  "https://api.staticadslab.com/v1/product-variants/pv_red_lg/duplicate",
  {
    method: "POST",
    headers: { "X-API-Key": "YOUR_API_KEY" },
  },
);

const { data } = await response.json();
// data.name                → "Red / Large - copy"
// data.duplicated_from_id  → "pv_red_lg"
// data.image_ids           → same image IDs as the source

// Replace the photos on the copy. The source variant is untouched: attaching
// and detaching edits this variant's list, not the image records themselves.
await fetch(`https://api.staticadslab.com/v1/product-variants/${data.id}`, {
  method: "PATCH",
  headers: { "X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({ image_ids: ["img_new_model_01", "img_new_model_02"] }),
});

Pitfalls

  • Duplicating shares image records rather than copying files. Detaching an image from the copy leaves the original variant's images intact, but deleting an image through /v1/images/:id removes it everywhere it is attached.
  • Variants have no description field. Variant-specific copy comes from the product description and the audience.
  • image_ids order matters — the API treats earlier IDs as primary candidates for hero shots.
  • A variant must belong to a product in the same brand as the image ad request.

Prompt for your agent

Read https://www.staticadslab.com/docs/resources/product-variants.mdx and create variants for product prod_YOUR_PRODUCT_ID. I have a CSV with columns name, image_urls — for each row, upload the images, then create the variant with those image IDs.