# One ad: GET /v1/ads/{id}

> The `Ad` record plus `detail`: every version of the ad, each country it ran in, targeting, the EU's reach figures (Meta) and who paid. Pass an `id` from any platform's search.

Base URL: `https://api.publicadsapi.com` · Auth: `authorization: Bearer <key>` · Web version: https://publicadsapi.com/docs/api/ads

## Request

cURL:

```bash
curl "https://api.publicadsapi.com/v1/ads/meta_900000000000001" \
  -H "authorization: Bearer $PADS_API_KEY"
```

Node.js:

```js
const res = await fetch('https://api.publicadsapi.com/v1/ads/meta_900000000000001', {
  headers: { authorization: `Bearer ${process.env.PADS_API_KEY}` },
});

const result = await res.json();
if (!res.ok) throw new Error(`${result.error.code}: ${result.error.message}`);
console.log(result.ads.length, 'ads; next page:', result.next_cursor);
```

Python:

```python
import os
import requests

res = requests.get(
    "https://api.publicadsapi.com/v1/ads/meta_900000000000001",
    headers={"authorization": f"Bearer {os.environ['PADS_API_KEY']}"},
    timeout=60,
)
result = res.json()
if not res.ok:
    raise RuntimeError(f"{result['error']['code']}: {result['error']['message']}")
print(len(result["ads"]), "ads; next page:", result["next_cursor"])
```

- `Authorization` (header, string, required): `Bearer <key>`. Keys starting `pads_test_` get the sandbox (sample ads, never charged); keys starting `pads_live_` read the platform and use credits.
- `id` (path, string, required): Our id from a search: `<platform>_<the platform's id>`, and for Google `google_<AR id>_<CR id>`. Example: `meta_900000000000001`
- `include` (query, comma-separated): `raw` adds the platform's own record as `raw`. The only parameter this endpoint takes.

Uses the platform's credits when the ad is found: Meta 1, Google 1, TikTok 1, LinkedIn 2. An id we can't find is `404 AD_NOT_FOUND` and uses none.

## Response

200 OK (a Meta ad delivered in the EU):

```json
{
  "id": "meta_900000000000001",
  "platform": "meta",
  "platform_ad_id": "900000000000001",
  "library_url": "https://www.facebook.com/ads/library/?id=900000000000001",
  "advertiser": {
    "id": "100000000000001",
    "name": "Northwind Running Co",
    "domain": null,
    "library_url": "https://www.facebook.com/ads/library/?view_all_page_id=100000000000001"
  },
  "status": "active",
  "first_shown": "2026-08-04T07:00:00Z",
  "last_shown": "2026-10-18T07:00:00Z",
  "format": "image",
  "text": {
    "headline": "Trail shoes, half price this week",
    "body": "Grip that holds on wet rock. Free returns for 60 days.",
    "description": null,
    "cta": "Shop now"
  },
  "text_source": "platform",
  "link_url": "https://northwind-running.example/trail",
  "media": [
    {
      "type": "image",
      "url": "https://example.com/sandbox-media/meta-trail.jpg",
      "preview_url": null,
      "width": 1080,
      "height": 1080
    }
  ],
  "placements": [
    "facebook",
    "instagram",
    "audience_network",
    "messenger"
  ],
  "regions": null,
  "metrics": {
    "impressions": null,
    "reach": null,
    "spend": null
  },
  "variants": 1,
  "detail": {
    "variants": [
      {
        "text": {
          "headline": "Trail shoes, half price this week",
          "body": "Grip that holds on wet rock. Free returns for 60 days.",
          "description": null,
          "cta": "Shop now"
        },
        "media": [
          {
            "type": "image",
            "url": "https://example.com/sandbox-media/meta-trail.jpg",
            "preview_url": null,
            "width": 1080,
            "height": 1080
          }
        ]
      }
    ],
    "regions": [],
    "targeting": {
      "age_min": 18,
      "age_max": 54,
      "genders": [
        "female",
        "male"
      ],
      "locations": [
        "DE",
        "FR",
        "NL"
      ],
      "used": null
    },
    "eu_reach": {
      "total": 46876,
      "by_country": [
        {
          "country": "DE",
          "reach": 24310
        },
        {
          "country": "FR",
          "reach": 14002
        },
        {
          "country": "NL",
          "reach": 8564
        }
      ],
      "by_age_gender": [
        {
          "country": "DE",
          "age_range": "18-24",
          "male": 3120,
          "female": 2904,
          "unknown": 41
        },
        {
          "country": "DE",
          "age_range": "25-34",
          "male": 6870,
          "female": 7215,
          "unknown": 88
        },
        {
          "country": "FR",
          "age_range": "25-34",
          "male": 4011,
          "female": 4390,
          "unknown": 22
        }
      ]
    },
    "payer": {
      "payer": "Northwind Running Co",
      "beneficiary": "Northwind Running Co"
    }
  },
  "credits_used": 1,
  "credits_remaining": 99
}
```

## What detail holds

| Field | Type | What it is |
| --- | --- | --- |
| detail.variants | array | Every version of the ad: `text` and `media` each. One entry when the platform has one version. |
| detail.regions | array | Each country it ran in: `country`, `first_shown`, `last_shown`, and `impressions` and `reach` ranges where the platform gives them. |
| detail.targeting | object | `age_min`, `age_max`, `genders`, `locations` and `used` (the kinds of targeting used, such as `demographics`). Each `null` where the platform does not say. |
| detail.eu_reach | object or null | Meta, ads delivered in the EU: `total`, `by_country` and `by_age_gender` (counts of people reached). |
| detail.payer | object or null | `payer` and `beneficiary`: who paid and who the ad was for, where the platform shows it. |

## What each platform gives

The rich detail is the EU's: the Digital Services Act makes the platforms publish reach and targeting for ads shown there. Ads shown only in the US carry their dates and the ad itself on every platform. Fields a platform leaves out are `null` or empty, never guessed.

| Platform | Ads shown in the EU | Ads shown elsewhere (the US, for example) |
| --- | --- | --- |
| Meta | Total EU reach; reach by country, age and gender; ages, genders and places targeted; payer and beneficiary. | The ad itself. Political and issue ads add spend and impressions ranges. |
| Google | Every version; each country with first and last shown; impressions per country; the kinds of targeting used; who paid. | Every version and each country with its dates. No impressions or targeting, political ads aside. |
| TikTok | Reach per country, targeting, who paid. | The UK and Switzerland the same as the EU. No other countries are in the library. |
| LinkedIn | Impressions range and impressions by country, top targeting, who paid. | Advertiser and payer only. |

200 OK (a Google ad shown in Germany and Ireland):

```json
{
  "id": "google_AR10000000000000000001_CR20000000000000000001",
  "platform": "google",
  "platform_ad_id": "CR20000000000000000001",
  "library_url": "https://adstransparency.google.com/advertiser/AR10000000000000000001/creative/CR20000000000000000001",
  "advertiser": {
    "id": "AR10000000000000000001",
    "name": "Tailspin Travel Ltd",
    "domain": "tailspin-travel.example",
    "library_url": "https://adstransparency.google.com/advertiser/AR10000000000000000001"
  },
  "status": "unknown",
  "first_shown": "2025-10-13T00:00:00Z",
  "last_shown": "2026-10-18T00:00:00Z",
  "format": "text",
  "text": {
    "headline": "Tailspin Travel | City breaks from £99",
    "body": "Flights and hotel together. ATOL protected. Book by Sunday.",
    "description": null,
    "cta": null
  },
  "text_source": "ocr",
  "link_url": "https://tailspin-travel.example/city-breaks",
  "media": [
    {
      "type": "image",
      "url": "https://example.com/sandbox-media/google-text.png",
      "preview_url": null,
      "width": 380,
      "height": 120
    }
  ],
  "placements": [
    "search"
  ],
  "regions": [
    "GB",
    "DE",
    "IE"
  ],
  "metrics": {
    "impressions": null,
    "reach": null,
    "spend": null
  },
  "variants": 4,
  "detail": {
    "variants": [
      {
        "text": {
          "headline": "Tailspin Travel | City breaks from £99",
          "body": "Flights and hotel together. ATOL protected. Book by Sunday.",
          "description": null,
          "cta": null
        },
        "media": []
      },
      {
        "text": {
          "headline": "Tailspin Travel | City breaks from £109",
          "body": "Flights and hotel together. ATOL protected. Book by Sunday.",
          "description": null,
          "cta": null
        },
        "media": []
      },
      {
        "text": {
          "headline": "Tailspin Travel | City breaks from £119",
          "body": "Flights and hotel together. ATOL protected. Book by Sunday.",
          "description": null,
          "cta": null
        },
        "media": []
      },
      {
        "text": {
          "headline": "Tailspin Travel | City breaks from £129",
          "body": "Flights and hotel together. ATOL protected. Book by Sunday.",
          "description": null,
          "cta": null
        },
        "media": []
      }
    ],
    "regions": [
      {
        "country": "DE",
        "first_shown": "2025-10-13T00:00:00Z",
        "last_shown": "2026-10-18T00:00:00Z",
        "impressions": {
          "min": 10000,
          "max": 50000
        },
        "reach": null
      },
      {
        "country": "IE",
        "first_shown": "2026-01-05T00:00:00Z",
        "last_shown": "2026-10-18T00:00:00Z",
        "impressions": {
          "min": 1000,
          "max": 5000
        },
        "reach": null
      },
      {
        "country": "GB",
        "first_shown": null,
        "last_shown": "2026-10-18T00:00:00Z",
        "impressions": null,
        "reach": null
      }
    ],
    "targeting": {
      "age_min": null,
      "age_max": null,
      "genders": null,
      "locations": [
        "DE",
        "IE"
      ],
      "used": [
        "demographics",
        "location",
        "contextual"
      ]
    },
    "eu_reach": null,
    "payer": {
      "payer": "Tailspin Travel Ltd",
      "beneficiary": null
    }
  },
  "credits_used": 1,
  "credits_remaining": 99
}
```

## Errors

`404 AD_NOT_FOUND` when the platform has no ad with that id (it may have been taken down) or the id is not one of ours. A Google id needs both its parts. Every other error is as for search: see [Errors](https://publicadsapi.com/docs/errors.md).

See also: [LinkedIn](https://publicadsapi.com/docs/api/linkedin.md) · [The Ad record](https://publicadsapi.com/docs/api/ad-record.md)
