Skip to content
Developers
Open app

List ad campaigns

GET
/v1/metrics/ad-campaigns
const url = 'https://api.focal.inc/v1/metrics/ad-campaigns?space_id=6916bc3d-e1ab-425b-ac25-eefada01a9a2&ad_account_id=f0958ef1-b662-425b-8794-79ca648489c7&status=not_launched_yet';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}

List the campaigns in the given ad accounts. A campaign’s id is what ad_campaign_id takes on GET /v1/metrics/insights, /v1/metrics/ad-sets, /v1/metrics/ads and /v1/metrics/creatives.

Ordered by last_active_at descending (never-active rows last), then by name. query matches names case-insensitively; status narrows to one delivery status. Every ad_account_id must be visible in space_id — 404 otherwise, as on insights.

Pass fields to trim the response to the properties you actually need — e.g. ?fields=name,status returns just those (plus id, always). Unknown names are rejected rather than ignored.

Required scope: metrics:read — a scope of its own, deliberately not covered by media:read, because ad spend and revenue are a different sensitivity class from asset metadata. (all:read does cover it.)

space_id is required and decides what you can see. The caller must be able to read that space (404 otherwise, so a space you can’t reach is indistinguishable from one that doesn’t exist), and an ad account is returned only when it is shared with that space or with the whole organization — or is private and was connected by the calling user. Rate-limit cost: 5.

space_id
required
string format: uuid

Example

6916bc3d-e1ab-425b-ac25-eefada01a9a2

Required. The single space to query, as a UUID. The API reads one space at a time — comma-separated lists and wildcards are not accepted, and there is no implicit default.

ad_account_id
required
string

Example

f0958ef1-b662-425b-8794-79ca648489c7

Ad accounts to read from, comma-separated — ids from GET /v1/metrics/ad-accounts. Each must be visible in space_id.

query
string

Only return rows whose name contains this (case-insensitive).

status
string
Allowed values: not_launched_yet live paused

Only return rows with this delivery status.

limit
integer
>= 1 <= 100

Max rows per page (1–100). Default 25.

cursor
string

Pagination cursor returned as next_cursor from the previous page.

fields
string

Return only these properties of each ad campaign, instead of the full object. id is always included. Omit for the complete object. Selectable: id, external_id, ad_account_id, name, status, first_active_at, last_active_at, created_at, updated_at.

OK

Media typeapplication/json
object
data
required
Array<object>
object
id
required

Focal’s id for the campaign — pass it as ad_campaign_id to GET /v1/metrics/insights (filters.ad_campaign_ids in query_metrics), /v1/metrics/ad-sets, /v1/metrics/ads and /v1/metrics/creatives.

string format: uuid
external_id
required

The id on the ad platform itself. Use it to correlate with data pulled straight from the platform; use id when calling Focal.

string
ad_account_id
required

The ad account it belongs to — an id from GET /v1/metrics/ad-accounts.

string format: uuid
name
required

The name as it appears on the ad platform.

string
status
required

Delivery status as last synced from the ad platform.

string
Allowed values: not_launched_yet live paused
first_active_at
required

YYYY-MM-DD of the first day the platform reported activity, or null when it never ran.

string format: date
nullable
last_active_at
required

YYYY-MM-DD of the most recent day the platform reported activity, or null when it never ran.

string format: date
nullable
created_at
required

When Focal first synced it.

string format: date-time
updated_at
required
string format: date-time
next_cursor
required

Pass back as cursor to fetch the next page. null on the last page.

string
nullable
has_more
required

true when another page is available. Equivalent to next_cursor !== null.

boolean

Example

{
"data": [
{
"id": "7c3b0b7e-980f-4ac8-8fce-2fe0084d9231",
"external_id": "120210987654321098",
"ad_account_id": "f0958ef1-b662-425b-8794-79ca648489c7",
"name": "Spring 2027 – Prospecting",
"status": "not_launched_yet",
"first_active_at": "2027-03-04",
"last_active_at": "2027-03-28",
"created_at": "2027-03-04T10:15:00Z",
"updated_at": "2027-03-06T14:42:00Z"
}
],
"next_cursor": "eyJ0IjoiMjAyNy0wMy0wNFQxMDoxNTowMC4wMDBaIiwiaSI6Ijc4NmJlZWRhLTU1YWMtNDAyNS1iZjZlLTQzYjI5MThlODRhOSJ9",
"has_more": true
}

The request was malformed (invalid cursor, unknown type, validation failure, etc.). error.code is bad_request.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "bad_request",
"message": "Invalid request body",
"details": [
{
"field": "space_id",
"issue": "Invalid UUID"
}
]
}
}

Missing, invalid, or disabled token. error.code is unauthenticated.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "unauthenticated",
"message": "Bearer token is missing or invalid"
}
}

The token doesn’t have the scope this endpoint requires. error.code is forbidden.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "forbidden",
"message": "Token doesn't have the required scope"
}
}

Resource doesn’t exist or is outside the token’s space allow-list. The two cases share a response shape so a restricted token can’t probe for the existence of out-of-scope spaces. error.code is not_found.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "not_found",
"message": "Not found"
}
}

Rate limit exceeded. error.code is rate_limited. Wait the number of seconds in the Retry-After header before retrying. Quotas are per-token; see the “Rate limiting” section at the top of this document.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "rate_limited",
"message": "Rate limit of 1000 units per 60s exceeded (this request cost 5)"
}
}
Retry-After
integer
Example
12

Seconds to wait before retrying.