Overview
Overview
The Advertiser API manages one advertiser organization: the organization that owns the API key. It lists and updates campaigns, ads, stats, and the wallet. Server-side conversions use a separate endpoint. An MCP server calls this same API.
There is no staff path and no cross-organization path. A resource that belongs to another organization is not found.
Base URL
https://tyfrhxfejrawgdlhryfu.supabase.co/functions/v1/advertiser-api
Paths are appended directly. There is no /v1 prefix.
curl 'https://tyfrhxfejrawgdlhryfu.supabase.co/functions/v1/advertiser-api/campaigns' \
-H 'Authorization: Bearer idl_adv_xxx'
| Function | URL |
|---|---|
| Advertiser API | https://tyfrhxfejrawgdlhryfu.supabase.co/functions/v1/advertiser-api |
| Conversions API | https://tyfrhxfejrawgdlhryfu.supabase.co/functions/v1/conversions-api |
| MCP server | https://tyfrhxfejrawgdlhryfu.supabase.co/functions/v1/advertiser-mcp |
The OpenAPI document lists every field and status code: advertiser-api.yaml.
API keys
Create a key in Ads Manager, under Settings → API keys. Only an organization owner or admin can create or revoke keys. An organization can have 25 active keys.
The key is shown in full once, at creation. It starts with idl_adv_. Later, the dashboard shows the prefix only.
Send it on every request, either way:
-H 'Authorization: Bearer idl_adv_xxx'
-H 'x-api-key: idl_adv_xxx'
A missing, malformed, or revoked key returns 401.
{
"error": {
"code": "unauthorized",
"message": "Invalid API key"
}
}
Scopes
A key has one or more of conversions, read, and write. write does not include read. A key created without an explicit scope list is conversions only.
| Scope | Allows |
|---|---|
read | GET campaigns, ads, stats, wallet, transactions |
write | POST and PATCH campaigns, ads, pause, resume, deposit Checkout |
conversions | POST on the separate conversions endpoint only |
The wrong scope returns 403 with insufficient_scope.
Rate limit
advertiser-api allows 120 requests per key per 60 seconds. The window is fixed. A 429 includes Retry-After (seconds) and:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current window (120) |
X-RateLimit-Remaining | Requests left after this one |
X-RateLimit-Reset | Unix time when the window ends |
The conversions endpoint does not use this budget. POST /ads/from-url also shares the landing-page extractor limit of 10 requests per organization per hour.
The MCP server uses the same 120 requests per minute. It authenticates once per HTTP call and does not count that call twice.
Idempotency-Key
POST requests accept Idempotency-Key (1–255 printable ASCII characters). The same key and the same body replay the first response for 24 hours. The key is scoped to the API key.
| Situation | Status | error.code |
|---|---|---|
| Same key, different body | 409 | idempotency_key_reused |
| Same key, first request still running | 409 | idempotency_in_progress |
| Key is not 1–255 printable ASCII | 400 | invalid_request |
PATCH does not use this header.
Errors
Advertiser API errors use this shape:
{
"error": {
"code": "not_found",
"message": "Campaign not found"
}
}
Activation errors can also include campaign_id and dashboard_url.
| Status | code | When |
|---|---|---|
400 | invalid_request | Bad query, body, or id |
401 | unauthorized | Missing or unknown key |
403 | insufficient_scope | Key lacks read or write |
404 | not_found | Unknown path, or the resource is not in this organization |
405 | method_not_allowed | Verb not allowed. The Allow header lists the verbs. |
409 | first_campaign_requires_dashboard_validation | The organization's first API campaign cannot be turned on here |
409 | insufficient_balance | Wallet balance is zero |
409 | ads_pending_moderation | No ad is approved yet |
409 | ad_required | The campaign has no ad that can deliver |
409 | no_active_ad_set | The campaign has no ad set that can go active |
429 | rate_limited | Over 120 requests in the current window, or the landing-page limit |
500 | internal_error | Server error |
503 | not_ready | The API, Checkout, or creative extraction is not configured |
Days and date filters are UTC. Amounts on the wallet, transactions, stats, budgets, and bids are cents of the wallet currency. That currency is EUR unless the wallet row stores another three-letter code. Transaction rows and stat days do not include a currency field.