# GET /v1/projects/:projectId/ads/campaigns (/docs/api/reference/ads/list-campaigns)



<Endpoint method="GET" path="/v1/projects/{projectId}/ads/campaigns" auth="Bearer" scope="ads:read" phase="1" />

Lists every ad campaign across the project's connected ad accounts, on every supported platform. Result includes the platform-native id, current status, objective, budget, and spend window. The `metricsSnapshot7d` field is reserved (always `{}` in Phase 1) — call [`GET /v1/projects/:projectId/ads-metrics`](/docs/api/reference/ads/ads-metrics) for paid performance.

<Callout type="warn">
  Ads endpoints are currently read-only, plus CAPI config and `ads-content` overrides. Creating, updating, pausing, or deleting campaigns, ad sets, and ads is planned. For now, mutate in the platform's own ad manager — the next call to this endpoint picks up the changes.
</Callout>

<Parameters
  title="Path"
  rows="[
  { name: 'projectId', type: 'string (UUID)', required: true, description: 'Project to list within.' },
]"
/>

<Parameters
  title="Query"
  rows="[
  { name: 'platforms', type: 'string[]', description: 'Restrict to one or more platforms.', enum: ['meta_ads', 'tiktok_ads', 'apple_ads'] },
  { name: 'adAccountId', type: 'string (UUID)', description: 'Restrict to campaigns on one ad account.' },
  { name: 'status', type: 'string[]', description: 'Filter by platform-native status.', enum: ['active', 'paused', 'archived', 'deleted', 'in_review', 'rejected'] },
  { name: 'since', type: 'string (ISO-8601)', description: 'Return campaigns created on or after this time.' },
  { name: 'cursor', type: 'string', description: 'Opaque pagination cursor. Forged or malformed cursors are rejected and treated as no cursor (first page).' },
  { name: 'limit', type: 'number', description: 'Page size, 1–200.', default: '100' },
]"
/>

## Example request [#example-request]

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```bash
    curl "https://api.layers.com/v1/projects/prj_01HX9Y7K8M2P4RSTUV56789AB/ads/campaigns?platforms=meta_ads&status=active&limit=25" \
      -H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..."
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    const res = await fetch(
      `https://api.layers.com/v1/projects/${projectId}/ads/campaigns?platforms=meta_ads&status=active&limit=25`,
      { headers: { Authorization: `Bearer ${apiKey}` } },
    );
    const { items, nextCursor } = await res.json();
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import httpx

    r = httpx.get(
        f"https://api.layers.com/v1/projects/{project_id}/ads/campaigns",
        params={"platforms": "meta_ads", "status": "active", "limit": 25},
        headers={"Authorization": f"Bearer {api_key}"},
    )
    ```
  </Tab>
</Tabs>

## Response [#response]

<Response status="200" description="OK">
  ```json
  {
    "items": [
      {
        "campaignId": "cmp_01HXG9...",
        "adAccountId": "aa_01HXF1...",
        "platform": "meta_ads",
        "externalId": "23852014...",
        "name": "Q2 Mobile Ordering — Prospecting",
        "objective": "conversions",
        "status": "active",
        "dailyBudget": { "amount": 150.00, "currency": "USD" },
        "lifetimeBudget": null,
        "startTime": "2026-04-01T00:00:00Z",
        "endTime": null,
        "createdAt": "2026-03-29T15:04:00Z",
        "metricsSnapshot7d": {}
      },
      {
        "campaignId": "cmp_01HXGB...",
        "adAccountId": "aa_01HXF2...",
        "platform": "tiktok_ads",
        "externalId": "1785502...",
        "name": "Q2 Mobile Ordering — TT Retargeting",
        "objective": "conversions",
        "status": "paused",
        "dailyBudget": null,
        "lifetimeBudget": { "amount": 3000.00, "currency": "USD" },
        "startTime": "2026-04-10T00:00:00Z",
        "endTime": "2026-05-10T00:00:00Z",
        "createdAt": "2026-04-08T21:18:00Z",
        "metricsSnapshot7d": {}
      }
    ],
    "nextCursor": null
  }
  ```
</Response>

## Notes [#notes]

* `status` is the platform-native value. Mapping varies subtly between Meta, TikTok, and Apple — do not assume `active` means the same thing everywhere. When the distinction matters (for instance `in_review` on Meta pre-launch), use the platform's own ad manager as the source of truth.
* `metricsSnapshot7d` is reserved for a future inline rollup. It is always `{}` today; call [`GET /v1/projects/:projectId/ads-metrics`](/docs/api/reference/ads/ads-metrics) with `scope=campaign` and an explicit window for paid performance.
* Soft-deleted campaigns (`status: "deleted"` on Meta, "archived" on TikTok) are included by default. Filter them out with `status` if you only want live work.

## See also [#see-also]

* [`GET /v1/projects/:projectId/ads/adsets`](/docs/api/reference/ads/list-adsets) — one level deeper
* [`GET /v1/projects/:projectId/ads-metrics`](/docs/api/reference/ads/ads-metrics) — paid performance at any scope
* [`GET /v1/projects/:projectId/ads/ad-accounts`](/docs/api/reference/ads/list-ad-accounts) — which accounts are connected
