Layers
Partner APIAPI referenceAds

GET /v1/projects/:projectId/ads/ads

List individual ads across Meta, TikTok, and Apple, with creative identifiers for joining back to ads-content.

View as Markdown
GET/v1/projects/{projectId}/ads/ads
Phase 1stable
Auth
Bearer
Scope
ads:read

Lists individual ads under the project, across platforms. Phase 1 ships meta_ads + tiktok_ads only — Apple Search Ads has no equivalent layer junction (ASA bottoms out at the ad-group level), so it is intentionally excluded here. Each ad carries its parent adset and campaign and the adsContentId that lets you join back to ads-content when the ad was promoted from a Layers-scored creative.

Read-only today. Creating, updating, pausing, or deleting ads is planned. Mutate in the platform's ad manager for now.

Path
  • projectId
    string (UUID)required
    Project to list within.
Query
  • adsetId
    string (UUID)optional
    Restrict to ads in one ad set.
  • campaignId
    string (UUID)optional
    Restrict to ads in one campaign.
  • adAccountId
    string (UUID)optional
    Restrict to ads on one ad account.
  • platforms
    string[]optional
    Restrict to one or more platforms.
    One of: meta_ads, tiktok_ads, apple_ads
  • adsContentId
    string (UUID)optional
    Restrict to ads promoting this ads_content row. Useful for "where is this creative running?"
  • status
    string[]optional
    Filter by platform-native status.
    One of: active, paused, archived, deleted, in_review, rejected
  • cursor
    stringoptional
    Opaque pagination cursor. Forged or malformed cursors are rejected and treated as no cursor (first page).
  • limit
    numberoptionaldefault: 100
    Page size, 1–200.

Example request

curl "https://api.layers.com/v1/projects/prj_01HX9Y7K8M2P4RSTUV56789AB/ads/ads?adsetId=adg_01HXG9&status=active" \
  -H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..."
const res = await fetch(
  `https://api.layers.com/v1/projects/${projectId}/ads/ads?adsetId=${adsetId}&status=active`,
  { headers: { Authorization: `Bearer ${apiKey}` } },
);
const { items, nextCursor } = await res.json();

// Find every platform a creative is live on.
const byCreative = new Map<string, string[]>();
for (const ad of items) {
  if (!ad.adsContentId) continue;
  const platforms = byCreative.get(ad.adsContentId) ?? [];
  platforms.push(ad.platform);
  byCreative.set(ad.adsContentId, platforms);
}
import httpx

r = httpx.get(
    f"https://api.layers.com/v1/projects/{project_id}/ads/ads",
    params={"adsetId": adset_id, "status": "active"},
    headers={"Authorization": f"Bearer {api_key}"},
)
items = r.json()["items"]

Response

200OK
{
  "items": [
    {
      "adId": "01HXGCA2B3C4D5E6F7G8H9J0K1",
      "adsetId": "01HXG9A2B3C4D5E6F7G8H9J0K1",
      "campaignId": "01HXG9B2B3C4D5E6F7G8H9J0K1",
      "adAccountId": "01HXF1A2B3C4D5E6F7G8H9J0K1",
      "platform": "meta_ads",
      "externalId": "23852014...",
      "name": "23852014...",
      "status": "active",
      "effectiveStatus": null,
      "adsContentId": null,
      "sourceType": null,
      "creative": null,
      "createdAt": "2026-03-29T15:04:00Z",
      "launchedAt": null,
      "metricsSnapshot7d": {}
    },
    {
      "adId": "01HXGDA2B3C4D5E6F7G8H9J0K1",
      "adsetId": "01HXGBA2B3C4D5E6F7G8H9J0K1",
      "campaignId": "01HXGBB2B3C4D5E6F7G8H9J0K1",
      "adAccountId": "01HXF2A2B3C4D5E6F7G8H9J0K1",
      "platform": "tiktok_ads",
      "externalId": "1785502...",
      "name": "1785502...",
      "status": "paused",
      "effectiveStatus": null,
      "adsContentId": "01HXD2A2B3C4D5E6F7G8H9J0K1",
      "sourceType": null,
      "creative": null,
      "createdAt": "2026-04-08T21:18:00Z",
      "launchedAt": null,
      "metricsSnapshot7d": {}
    }
  ],
  "nextCursor": null
}

Joining ads to creatives

Every ad in this response has at most one adsContentId. That field is the bridge to ads-content (the scored creative), top-performers (cross-source ranking), and — for generated content — the source content_container. Use it to answer:

  • "Where is this creative running?" Query /ads?adsContentId=adc_01HXC9...
  • "What score does this ad's creative have?" Follow adsContentId to /ads-content?adsContentId=... or the item directly at the row level.
  • "Is this ad's creative manually overridden?" Same path — the override lives on the ads-content row.

adsContentId is null only for ads that existed on the platform before Layers tracked them or for creatives outside the scoring pool (rare; mostly legacy imports). Do not rely on null being stable.

Notes

  • status is the partner-normalized status mapped from the layer junction's record (one of active, paused, archived, deleted, in_review, rejected).
  • effectiveStatus, creative, sourceType, launchedAt: reserved for future enrichment from platform-native ad rows. They are always null in Phase 1; partners that need creative metadata or the platform-derived effective status must call the platform's own ad manager.
  • metricsSnapshot7d is reserved (always {} today). For paid performance, call GET /v1/projects/:projectId/ads-metrics with scope=ad and an explicit window.
  • name defaults to the platform-native ad id (externalId) when Layers doesn't have a friendlier label cached.
  • adsContentId is the bridge to ads-content. When non-null, the ad was promoted from a Layers-scored creative; when null, the ad was created outside the Layers refresh loop.

See also

On this page