API reference
Every endpoint, field and response of the export API. Generated from openapi.yaml (OpenAPI 3.1, also as JSON).
- Base URL:
https://global-api.attentionpanel.com - Auth:
Authorization: <api key>on every request, no scheme prefix. - Body: JSON in and out. Unknown request fields are rejected.
- Errors:
{ "statusCode": 400, "message": "FROM_DATE_NOT_ALLOWED" }. Themessageis the code to branch on. - Two ways to export: the change feed for mobile
v2(feed: truefor the first pull, thensincewith the lastnext_cursor), which keeps a copy of the export current; and the day export (from_date,to_date) for one-off pulls and desktop. Integration → - Cursors: treat
next_cursoras an opaque string and pass it back unchanged. It does not expire.
Versions
The mobile export has two versions. Desktop has none: leave version out.
| Version | Days | Status |
|---|---|---|
v2 |
From 13 March 2026 in Sweden and Denmark, 26 March in Norway and 19 May in Finland | The current export, and the only one with the change feed. |
v1 |
Up to 11 November 2026 | The legacy export, no longer updated. Moving from the legacy mobile export → |
- Send
versionon every mobile request. A version in the request always applies. - Without it, a request gets the version set for your key:
v2, unless your key was set up on the legacy export. A change-feed pull is alwaysv2. - Outside a version's days: a
from_datebefore 13 March 2026 withv2is a 400V2_FROM_DATE_NOT_AVAILABLE, with the first day inavailable_from. Ato_dateafter 11 November 2026 withv1is a 400V1_NOT_AVAILABLE_AFTER, with the last day inavailable_to. - Every job states its version:
versionin Get an export.
Create an export
POST /impressions/export
Starts an export job for one platform and market: a day export over an inclusive range of UTC dates (from_date, to_date), or, for mobile v2, the change feed. A feed starts with a first pull (feed: true), which returns every current impression and a cursor; each later pull passes the last cursor (since) and returns every impression added, changed or removed since. Upsert the rows on impression_id and treat removed: true as retired.
Request body
| Field | Type | Description |
|---|---|---|
| device | string · required | The platform. One of mobile, desktop. |
| market | string · required | The market. One of semarket, nomarket, dkmarket, fimarket. |
| from_date | date | Day export: YYYY-MM-DD, inclusive. Not before the key's earliest allowed date. |
| to_date | date | Day export: YYYY-MM-DD, inclusive. Not before from_date. |
| include_html_metadata | boolean | Desktop only. Adds html_metadata when the key is entitled to it. |
| version | string | Mobile only. The mobile data version. When omitted: the version set for the key, else v2; a feed pull is always v2. v2 data starts on a date set per deployment: an earlier from_date returns 400 V2_FROM_DATE_NOT_AVAILABLE with that date in available_from. Mobile v1 data ends on 2026-11-11: a later to_date returns 400 V1_NOT_AVAILABLE_AFTER with that date in available_to. One of v1, v2. |
| feed | boolean | Change feed, mobile v2: the first pull. Returns every current impression from the key's earliest allowed date, and a cursor. Always true. |
| since | string | Change feed, mobile v2: the next_cursor of the last pull. Returns every impression added, changed or removed since. A cursor does not expire. |
Response 200
| Field | Type | Description |
|---|---|---|
| export_id | string · required | Use in the other endpoints. URL-encode it in paths. |
| status | string · required | Always RUNNING. |
| version | string | The data version the job exports. One of v1, v2. |
Errors
| Status · message | Cause |
|---|---|
| 400 (validation message) | Missing or unknown field, bad date, from_date after to_date, or neither dates nor feed or since. |
| 400 FROM_DATE_NOT_ALLOWED | from_date is before the key's earliest allowed date. |
| 400 MAX_PARALLEL_RUNS_LIMIT_REACHED | The key already has its maximum number of running jobs for this platform, market and version. |
| 400 V2_FROM_DATE_NOT_AVAILABLE | version v2 with from_date before the first day of v2 data, which available_from gives (YYYY-MM-DD). |
| 400 V1_NOT_AVAILABLE_AFTER | Mobile version v1 with to_date after the last day of v1 data, which available_to gives (YYYY-MM-DD); v1 is no longer built. Request v2 for later days. action says the same. |
| 400 V2_ONLY_AVAILABLE_FOR_MOBILE | version v2 with a device other than mobile. |
| 400 FEED_TAKES_NO_DATES | feed or since together with from_date or to_date. |
| 400 FEED_OR_SINCE | Both feed and since: a pull is either the first one or one since a cursor. |
| 400 FEED_MUST_BE_TRUE | feed other than true. |
| 400 FEED_ONLY_AVAILABLE_FOR_MOBILE | feed or since with a device other than mobile. |
| 400 FEED_ONLY_AVAILABLE_FOR_V2 | feed or since with a version other than v2. |
| 400 CURSOR_INVALID | since is not a cursor this API returned. |
| 400 CURSOR_GAP | Changes after since were lost on our side. Start a new feed with feed: true; impressions you hold that are not in it are retired. action says the same. |
| 401 | No Authorization header. |
| 403 | Invalid key, or platform or market outside its entitlements. |
| 500 EXPORT_VERSION_MISCONFIGURED | The default export version set for the key is not valid, and we have been alerted. A request that names its version is not affected. |
Get an export
GET /exports/{export_id}
Returns the job's state, and the files once it has succeeded.
Response 200
| Field | Type | Description |
|---|---|---|
| status | string · required | Only RUNNING changes. One of RUNNING, SUCCEEDED, FAILED, CANCELLED. |
| version | string | The data version the job exports. One of v1, v2. |
| download_urls | string[] | On SUCCEEDED. Presigned, one archive per calendar month in the range (for a feed pull, per month of the impressions it returns; none when nothing changed), named <export_id>_<year>_<month>.tar.gz and holding a day=DD/ folder of gzipped JSON Lines per day. Valid 24 hours after completion. Send no Authorization header to them. |
| failure_reason | string | On FAILED: NO_DATA (no rows for the request), CURSOR_INVALID or CURSOR_GAP (as the 400 codes of a feed request, found while the job ran), or INTERNAL_ERROR. One of NO_DATA, INTERNAL_ERROR, CURSOR_INVALID, CURSOR_GAP. |
| next_cursor | string | On SUCCEEDED, for a change-feed pull: pass it as since in the next pull. |
Errors
| Status · message | Cause |
|---|---|
| 400 EXPORT_EXPIRED | The download URLs are older than 24 hours. Create a new export. |
| 404 | Unknown export_id, or one created with another key. |
Cancel an export
POST /exports/{export_id}/cancel
Stops a running job.
Response 200
| Field | Type | Description |
|---|---|---|
| export_id | string · required | The cancelled job. |
| status | string · required | Always CANCELLED. |
Errors
| Status · message | Cause |
|---|---|
| 400 EXPORT_NOT_IN_CANCELABLE_STATE | The job is no longer running. |
| 404 | Unknown export_id, or one created with another key. |