Skip to main content
This page is for a backend job or service that calls the v2 buyer REST API, such as a nightly reporting pull, and is moving to the V3 HTTP API. Your API key works for both. What changes is the shape of each call: V3 has one fixed route per operation, takes a JSON body, and returns typed results. The V3 HTTP API page is the reference for requests, responses and errors; this page covers what is different from v2.

The calls, side by side

Every V3 call is a POST to https://api.apostra.com/api/v3/tools/<operation> with your key as a bearer token. A key that belongs to one account needs no other header. See Make a request.

Read advertisers

The advertisers are in data.objects.results, one object per advertiser with advertiserId, name, primaryCurrency and status. To read one advertiser, call get with kind: "advertiser" and its id; the advertiser is in data.object.

Read an advertiser’s campaigns

Each result nests the campaign and its advertiser: data.objects.results[].campaign.campaignId and data.objects.results[].advertiser.advertiserId. Filters always go inside filter; V3 HTTP does not read a filter from the top level of the body.

Page through results

v2 paged with numbers (limit and offset for advertisers, take and skip for campaigns). V3 pages with a cursor:
  1. Send limit (up to 200 for search, up to 100 rows for get_delivery).
  2. If the response has a nextCursor (data.objects.nextCursor for search, data.page.nextCursor for get_delivery), send the same request again with cursor set to it.
  3. Stop when the response has no nextCursor.
A cursor belongs to the request that produced it. Send it back with the same operation, filters and limit.

Read delivery

v2 GET /api/v2/buyer/reporting/metrics becomes get_delivery with report: "campaign_delivery". For one advertiser and one day:
  • Dates. Send range.startDate and range.endDate (up to 90 days), or range.lifetime: true. There is no days parameter.
  • Grouping. dimensions chooses the grouping, from date, advertiser, campaign, media_buy, package and others. Each row carries its dimension values in rows[].dimensions, for example rows[].dimensions.campaign.id.
  • Metric values. Each metric is an object, not a bare number: {"value": 1250, "status": "available"}. When status is unavailable, value is null and reason says why. A missing value is never reported as zero.
  • Totals. data.totals.metrics holds the total for each metric. When the matched delivery mixes provisional (Snapshot) and final (Official) figures, totals gives no number and totalsByFinality gives one total per class. See Reporting for what each label means.
  • Paging. Rows come in pages of up to 100 (limit); follow data.page.nextCursor as above.

Metric names

V3 uses AdCP’s delivery metric names.

The v2 summary view

v2 reporting returns a tree by default (view=summary): advertiser, then campaign, media buy and package, with totals at each level. get_delivery returns flat rows instead. To build the same tree, request dimensions: ["campaign", "media_buy", "package"] and group the rows in your client. For daily rows, add date. These v2 reporting features have no V3 equivalent today: delivery pace and goal progress in the summary view, the converted cross-advertiser total (displayCurrency), outcome counts from your measurement uploads (outcomeType), and CSV download (download=true). If you depend on one of them, tell us before you move.

Errors

V3 returns a non-2xx status with an AdCP error in error; data is null.
  • A request body that does not match the operation’s schema returns 422 with code INVALID_REQUEST, and error.details.validation names the field. v2 returned 400 for invalid query parameters.
  • A key cannot reach another account. Sending an X-SCOPE3-CUSTOMER-ID header that does not match the key’s account returns 403.
See Errors for every code and what to do about it.

Generate a client

The V3 OpenAPI document lists every operation, its body and its result. You can generate a typed client from it rather than writing requests by hand. See Generate a client, or use an official SDK.