ChatGPT Ads Cards
Individual ChatGPT ad cards (creatives) seen for a tracked domain's prompts, paginated newest-first.
curl --request GET \
--url 'https://api.aiclicks.io/api/v1/ads/cards?domain_id=8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3&days=30&page=1&per_page=50' \
--header 'Authorization: Bearer ak_live_xxx'
import httpx, os
resp = httpx.get(
"https://api.aiclicks.io/api/v1/ads/cards",
params={
"domain_id": "8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3",
"days": 30,
"page": 1,
"per_page": 50,
},
headers={"Authorization": f"Bearer {os.environ['AICLICKS_API_KEY']}"},
)
resp.raise_for_status()
body = resp.json()["data"]
print(f"{body['totalCount']} cards total")
for card in body["cards"]:
you = " (you)" if card["isYou"] else ""
print(f"{card['brand']}{you}: {card['title']} -> {card['url']}")
const url = new URL("https://api.aiclicks.io/api/v1/ads/cards");
url.searchParams.set("domain_id", "8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3");
url.searchParams.set("days", "30");
url.searchParams.set("page", "1");
url.searchParams.set("per_page", "50");
const resp = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.AICLICKS_API_KEY}` },
});
const { data } = await resp.json();
for (const card of data.cards) {
console.log(`${card.brand}: ${card.title} (${card.queryShown})`);
}
{
"data": {
"cards": [
{
"id": "resp_a1b2:0:0",
"brandId": "globex",
"brand": "Globex",
"domain": "globex.io",
"color": "#DB2777",
"favicon": "https://globex.io/favicon.ico",
"isYou": false,
"title": "Analytics that scales with you",
"body": "Start free. No credit card. Ship dashboards in minutes.",
"queryShown": "best analytics tool for startups",
"url": "https://globex.io/startups?utm_source=chatgpt",
"image": "https://globex.io/ads/hero.png",
"topic": "Analytics"
},
{
"id": "resp_a1b2:1:0",
"brandId": "acme",
"brand": "Acme",
"domain": "acme.com",
"color": "#2563EB",
"favicon": "https://acme.com/favicon.ico",
"isYou": true,
"title": "Acme Analytics — built for founders",
"body": "The metrics that matter, from day one.",
"queryShown": "best analytics tool for startups",
"url": "https://acme.com/?ref=chatgpt",
"image": null,
"topic": "Analytics"
}
],
"totalCount": 311,
"pagination": {
"current_page": 1,
"per_page": 50,
"total_count": 311,
"total_pages": 7,
"has_next": true,
"has_prev": false,
"last_page": false
}
},
"domain_id": "8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3",
"days": 30,
"generated_at": "2026-06-17T10:00:11.218Z"
}
{
"detail": "domain_id query parameter is required. List the domains this key can access with GET /api/v1/domains, then pass ?domain_id=<uuid>."
}
{
"detail": "Invalid or revoked API key"
}
{
"detail": "API access is not enabled for this team. Contact support@aiclicks.io."
}
{
"detail": "Domain not found"
}
{
"detail": "Too many requests. Please try again later."
}
Returns the individual ad cards — the creatives ChatGPT rendered — seen for your domain's tracked prompts during the lookback window, one row per card, paginated newest-first. Each card carries its advertiser, the copy (title / body), the destination URL, the prompt it was shown on, and its topic. Use it to answer "show me the actual ads running against my prompts on ChatGPT" in one call.
Cards are sorted by their response time, most recent first. This is the raw creative feed; for the per-advertiser roll-up use ``.
domain_id is a required query parameter. Use `` to discover which domains the calling key can access.
Authorizations
Your API key formatted as Bearer ak_live_<your-key>. Create one in the dashboard under Settings → Developers.
Optional UUID for log correlation. If omitted, we generate one and echo it back in the response.
Query parameters
UUID of the domain. Find domains via ``. Omitting this returns 400.
Look-back window, 1–365. Defaults to 30.
1-based page number. Defaults to 1. Must be ≥ 1.
Cards per page, 1–500. Defaults to 50.
Response
The cards payload plus a total count and pagination metadata.
One row per ad card, sorted by response time descending (newest first). This is the current page slice, not the full set.
Total cards matching the window across all pages. Equal to pagination.total_count.
Pagination metadata for the cards slice.
Echo of the requested domain.
Echo of the requested window.
ISO-8601 timestamp of when the server produced (or cached) this response.
Response headers
| Header | Description |
|---|---|
X-Cache | HIT or MISS. Indicates whether the response came from cache. |
X-Request-Id | Unique request id. Echoes incoming if you set one. |
X-RateLimit-Limit | Max requests per minute for this key. |
X-RateLimit-Remaining | Requests remaining in current minute. |
X-RateLimit-Reset | Unix epoch seconds when the window resets. |
Caching
Cached for 30 minutes server-side per (domain_id, days, page, per_page). Newly completed analyses appear after the TTL expires.
Errors
domain_id query parameter missing. Body points you at /api/v1/domains.
Missing, malformed, or revoked API key.
Team's developer_access flag is off, the domain belongs to a team your API key is not scoped to, or your allowed_domains allowlist excludes it.
domain_id is malformed, does not exist, or your user is not a member of its team.
Rate limit exceeded. Inspect the Retry-After header for how long to wait.
Empty result
If no ad cards ran in the window, the response is a successful 200 with an empty list, totalCount of 0, and zeroed pagination:
{
"data": {
"cards": [],
"totalCount": 0,
"pagination": {
"current_page": 1,
"per_page": 50,
"total_count": 0,
"total_pages": 0,
"has_next": false,
"has_prev": false,
"last_page": true
}
},
"domain_id": "8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3",
"days": 30,
"generated_at": "2026-06-17T10:00:11.218Z"
}