Static Ads Lab
Concepts

Search

Find products, variants, audiences, design packs, swipe files and image ads in one request. Built for typeaheads, @-mention pickers and agents.

GET /v1/search searches six resource types at once and returns a short, uniform result for each match: a type, an id, a label, and a preview when there is one. Use it for typeaheads, @-mention pickers, command palettes, and agent tools. It's the same endpoint the StaticAds.ai Studio composer uses.

Mental model

  • One request, many types. Each requested type is searched in parallel, so a search costs one request against your rate limit, however many types you ask for.
  • Grouped by type. Results come back in the order of types, up to limit per type. Within a type, names that start with your query come first.
  • Empty query = recent. Leave query empty to get the most recent items of each type, which is handy for showing suggestions the moment a picker opens.
  • Resolve mode. Pass ids instead of query to turn a mixed list of ids (prod_…, sf_…, dp_…) into labels and previews in one call, for example to render chips in a saved prompt.
  • Same visibility as the list endpoints. You see what your organization can see. Archived products, variants, audiences, design packs and swipe files are left out, as are swipe files still processing. Swipe files and StaticAds.ai design packs follow your data source settings.

How each type matches

objectMatches onlabelhintthumbnail_url
productproduct nameproduct namenullnull
product_variantvariant namevariant nameproduct namenull
audienceaudience nameaudience nameproduct namenull
design_packpack titlepack title"StaticAds.ai" for StaticAds.ai packsnull
swipe_filead format or industry (e.g. testimonial, apparel)format and industrynull200px preview
image_adad id (ia_…), or the name of the product it was made forproduct name + "ad"ad idpreview

Parameters

ParameterTypeDescription
querystringText to match, case-insensitive, up to 200 characters. Empty returns recent items.
typesstringComma-separated: product, product_variant, audience, design_pack, swipe_file, image_ad. Defaults to all.
brand_idstringLimit brand-owned types (products, variants, audiences, image ads) to one brand
limitnumberResults per type, 1-25, default 5
idsstringComma-separated ids of any supported type, up to 100. Switches to resolve mode; query and limit are ignored.

Permissions

Each type needs its own read scope (products:read, product_variants:read, audiences:read, design_packs:read, swipe_files:read, image_ads:read). Types your key can't read are skipped, so a key with only products:read gets product results. If your key can't read any of the requested types, the request returns 403 INSUFFICIENT_PERMISSIONS.

Search as the user types

const params = new URLSearchParams({
  query: "legg",
  types: "product,product_variant,audience",
  brand_id: "brand_a1b2c3d4e5f67890",
  limit: "5",
});

const response = await fetch(`https://api.staticadslab.com/v1/search?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const { data } = await response.json();

for (const result of data) {
  console.log(result.object, result.id, result.label, result.hint);
}
// product prod_… Skirted Leggings null
// product_variant pv_… Skirted Leggings - Black / M Skirted Leggings

Debounce keystrokes (100-150ms is a good default) and cache results by query, so a fast typist sends a few requests instead of one per key.

Resolve ids to labels

const ids = ["prod_a1b2c3d4e5f67890", "sf_f9e8d7c6b5a43210", "dp_0123456789abcdef"];

const response = await fetch(
  `https://api.staticadslab.com/v1/search?ids=${ids.join(",")}`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } },
);
const { data } = await response.json();
const byId = new Map(data.map((result) => [result.id, result]));

console.log(byId.get("sf_f9e8d7c6b5a43210")?.label); // "Testimonial · Apparel & Accessories"

Ids that don't exist, or that your organization can't see, are left out of the response rather than returning an error.