Skip to content

Advertising ​

The campaign tree and its performance. Reading requires campaigns:read; creating, editing and archiving campaigns, ad groups, targets and product ads require campaigns:write.

Each level pairs a structure resource with a metrics one: /v1/campaigns lists what exists, /v1/campaign-metrics lists what it did over a date range.

/v1/portfolios groups campaigns under a shared budget cap. A campaign's portfolioId says which portfolio it belongs to, and setting it on a campaign (Sponsored Products, Brands or Display) moves the campaign in or out.

/v1/advertising-changes is the log of everything Epinium has changed on Amazon, whoever asked for it, including what Amazon rejected.

Servers​

https://api.epinium.com

List the authenticated account's advertising campaigns​

GET
/v1/campaigns

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

limit

Page size. The default is enough to explore; raise it only when you need to walk a whole collection.

Type
integer
Example20
Default
20
Minimum
1
Maximum
100
starting_after

Cursor for the next page: the id of the last record you received. Returns the records after it.

Type
string
ending_before

Cursor for the previous page: the id of the first record you received. Returns the records before it.

Type
string
expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object
search

Case-insensitive substring match over the campaign name. Use it to find a record by name when you do not have its id, instead of paging through the whole list. Regex metacharacters are matched literally.

Type
string
Min Length
1
Max Length
200
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
state
Type
string
Valid values
"ENABLED""PAUSED""ARCHIVED""OTHER"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"adProduct": "string",
  
  
  
"campaignId": "string",
  
  
  
"name": "string",
  
  
  
"state": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"startDate": "string",
  
  
  
"endDate": "string",
  
  
  
"deliveryStatus": "string",
  
  
  
"deliveryReasons": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"budget": {
  
  
  
  
"amount": 0,
  
  
  
  
"currency": "string",
  
  
  
  
"period": "string"
  
  
  
},
  
  
  
"bidStrategy": "string",
  
  
  
"portfolioId": "string",
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string",
  
  
  
"optimizationConfig": {
  
  
  
  
"aiEnabled": true,
  
  
  
  
"objective": {
  
  
  
  
  
"type": "string",
  
  
  
  
  
"value": 0,
  
  
  
  
  
"maxAcosPct": 0
  
  
  
  
},
  
  
  
  
"limits": {
  
  
  
  
  
"minBid": 0,
  
  
  
  
  
"maxBid": 0,
  
  
  
  
  
"placementCapPercent": 0,
  
  
  
  
  
"minSpendBeforeNegative": 0
  
  
  
  
},
  
  
  
  
"budget": {
  
  
  
  
  
"dailyBudget": 0,
  
  
  
  
  
"monthlyBudget": 0
  
  
  
  
},
  
  
  
  
"harvesting": {
  
  
  
  
  
"discoveryLevel": "string",
  
  
  
  
  
"competitorAsinTargeting": true,
  
  
  
  
  
"crossCampaign": {
  
  
  
  
  
  
"enabled": true,
  
  
  
  
  
  
"harvestGroupKey": "string",
  
  
  
  
  
  
"role": "string"
  
  
  
  
  
}
  
  
  
  
},
  
  
  
  
"linkedWorkflowDefinitionIds": [
  
  
  
  
  
"string"
  
  
  
  
],
  
  
  
  
"excludedWorkflowDefinitionIds": [
  
  
  
  
  
"string"
  
  
  
  
],
  
  
  
  
"workflowsOptOut": true,
  
  
  
  
"warmingModeUntil": "string",
  
  
  
  
"optimizeDate": "string",
  
  
  
  
"optimizingSince": "string"
  
  
  
}
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


Create a Sponsored Products campaign, paused by default​

POST
/v1/campaigns

Created PAUSED unless you pass state: "ENABLED" explicitly: an enabled campaign starts spending as soon as Amazon accepts it. dailyBudget is checked against the marketplace minimum for the connection country and rejected with 400 below it. Requires the campaigns:write scope and an Idempotency-Key header. Sponsored Brands and Sponsored Display campaigns cannot be created here yet; they can be changed and archived like any other.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"connection": "string",
  
"name": "string",
  
"dailyBudget": 0,
  
"targetingType": "string",
  
"state": "PAUSED",
  
"startDate": "string",
  
"endDate": "string"
}

Responses​

201

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Body

Samples​


GET /v1/campaigns/{id}​

GET
/v1/campaigns/{id}

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Query Parameters

expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"adProduct": "string",
  
"campaignId": "string",
  
"name": "string",
  
"state": "string",
  
"connection": "string",
  
"country": "string",
  
"startDate": "string",
  
"endDate": "string",
  
"deliveryStatus": "string",
  
"deliveryReasons": [
  
  
"string"
  
],
  
"budget": {
  
  
"amount": 0,
  
  
"currency": "string",
  
  
"period": "string"
  
},
  
"bidStrategy": "string",
  
"portfolioId": "string",
  
"createdAt": "string",
  
"updatedAt": "string",
  
"optimizationConfig": {
  
  
"aiEnabled": true,
  
  
"objective": {
  
  
  
"type": "string",
  
  
  
"value": 0,
  
  
  
"maxAcosPct": 0
  
  
},
  
  
"limits": {
  
  
  
"minBid": 0,
  
  
  
"maxBid": 0,
  
  
  
"placementCapPercent": 0,
  
  
  
"minSpendBeforeNegative": 0
  
  
},
  
  
"budget": {
  
  
  
"dailyBudget": 0,
  
  
  
"monthlyBudget": 0
  
  
},
  
  
"harvesting": {
  
  
  
"discoveryLevel": "string",
  
  
  
"competitorAsinTargeting": true,
  
  
  
"crossCampaign": {
  
  
  
  
"enabled": true,
  
  
  
  
"harvestGroupKey": "string",
  
  
  
  
"role": "string"
  
  
  
}
  
  
},
  
  
"linkedWorkflowDefinitionIds": [
  
  
  
"string"
  
  
],
  
  
"excludedWorkflowDefinitionIds": [
  
  
  
"string"
  
  
],
  
  
"workflowsOptOut": true,
  
  
"warmingModeUntil": "string",
  
  
"optimizeDate": "string",
  
  
"optimizingSince": "string"
  
}
}

Playground​

Authorization
Variables
Key
Value

Samples​


Archive a campaign​

DELETE
/v1/campaigns/{id}

Archiving is how Amazon removes an entity, and it CANNOT BE UNDONE: an archived campaign does not come back, and this is the only irreversible operation in this API. That is why it is its own verb instead of a state you could set by accident while changing a bid. Use state: "PAUSED" if you only want to stop it - that one is reversible. A campaign that does not exist, or belongs to another account, is a 404. One managed by the optimizer is refused. Requires the campaigns:write scope and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Variables
Key
Value

Samples​


Change the state, budget, name or portfolio of a campaign​

PATCH
/v1/campaigns/{id}

Send only the fields you want to change; anything you omit is left as it is. At least one field is required. A campaign that does not exist, or belongs to another account, is a 404 - never a 403, which would confirm it exists. A campaign managed by the optimizer is refused, because its next run would overwrite you. If Amazon rejects the change the response is still 200 with result: "failed" and the reason, so you can tell "Amazon said no" from "the call never happened". Requires the campaigns:write scope and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Request Body​

application/json
JSON
{
  
"state": "string",
  
"dailyBudget": 0,
  
"name": "string",
  
"portfolioId": "string"
}

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Variables
Key
Value
Body

Samples​


Changes the workflow actually applied to this campaign​

GET
/v1/campaigns/{id}/optimization-history

Only changes that were APPLIED, and only for real: a dry-run simulation never appears here, under any parameter. Aggregated to a net per entity — data carries one row per target whose bid was moved, with the bid from before the first change against the bid after the last one, so a target raised then capped back down reports direction: unchanged with change_count: 2. That is the reading a flat decision list hides, and it is usually the answer to whether the optimization is doing anything. Proposals are excluded: the optimizer computes a bid the economic ceiling can then cut, and only what reached Amazon is reported. Non-bid changes (harvested keywords, negatives, placement adjustments, blocked or quarantined targets) do not share the table because they have no previous bid — they are counted in other_changes. Monetary amounts are decimal strings. The window is capped at 90 days, which is the retention of the underlying records.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Query Parameters

start_date
Type
string
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
end_date
Type
string
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
limit

Page size, up to 500. Paginate with offset, not with a cursor: these rows are aggregated changes, not records with an id. Narrow the window with start_date / end_date instead of walking every page.

Type
integer
Default
100
Minimum
1
Maximum
500
offset
Type
integer
Default
0
Minimum
0
Maximum
9007199254740991
order
Type
string
Valid values
"asc""desc"
Default
"desc"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"entity_type": "string",
  
  
  
"adgroup": "string",
  
  
  
"first_bid": "string",
  
  
  
"last_bid": "string",
  
  
  
"net_change": "string",
  
  
  
"direction": "string",
  
  
  
"change_count": 0,
  
  
  
"first_change_at": "string",
  
  
  
"last_change_at": "string",
  
  
  
"last_reason": "string",
  
  
  
"last_scenario": "string"
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0,
  
"other_changes": [
  
  
{
  
  
  
"entity_type": "string",
  
  
  
"entity_id": "string",
  
  
  
"change_type": "string",
  
  
  
"count": 0,
  
  
  
"last_change_at": "string",
  
  
  
"last_reason": "string"
  
  
}
  
],
  
"summary": {
  
  
"targets_touched": 0,
  
  
"bid_changes": 0,
  
  
"raised": 0,
  
  
"lowered": 0,
  
  
"unchanged": 0,
  
  
"other_changes": 0,
  
  
"window": {
  
  
  
"start_date": "string",
  
  
  
"end_date": "string"
  
  
}
  
}
}

Playground​

Authorization
Variables
Key
Value

Samples​


Create a campaign with its ad group, targets and product ads​

POST
/v1/campaigns/full

One call for the whole structure, in order: campaign, ad group, targets, product ads. There is NO rollback on Amazon — if a later step fails the earlier entities stay created, and the response tells you how far it got in stopped_at plus what went wrong in partial_errors. Read that instead of retrying: a retry would create a second campaign. Everything is created paused unless you ask otherwise. Requires campaigns:write and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"campaign": {
  
  
"connection": "string",
  
  
"name": "string",
  
  
"dailyBudget": 0,
  
  
"targetingType": "string",
  
  
"state": "PAUSED",
  
  
"startDate": "string",
  
  
"endDate": "string"
  
},
  
"adGroup": {
  
  
"name": "string",
  
  
"defaultBid": 0,
  
  
"state": "PAUSED"
  
},
  
"targets": [
  
  
{
  
  
  
"targetType": "string",
  
  
  
"negative": false,
  
  
  
"keywordText": "string",
  
  
  
"matchType": "string",
  
  
  
"asin": "string",
  
  
  
"sku": "string",
  
  
  
"productMatchType": "string",
  
  
  
"category": "string",
  
  
  
"productBrand": "string",
  
  
  
"productPriceGreaterThan": 0,
  
  
  
"productPriceLessThan": 0,
  
  
  
"productRatingGreaterThan": 0,
  
  
  
"productRatingLessThan": 0,
  
  
  
"productAgeRange": "string",
  
  
  
"productPrimeShippingEligible": true,
  
  
  
"themeMatchType": "string",
  
  
  
"event": "string",
  
  
  
"lookback": 0,
  
  
  
"audienceId": "string",
  
  
  
"contentCategoryId": "string",
  
  
  
"locationId": "string",
  
  
  
"bid": 0
  
  
}
  
],
  
"productAds": [
  
  
{
  
  
  
"product": "string",
  
  
  
"state": "PAUSED"
  
  
}
  
]
}

Responses​

201

application/json
JSON
{
  
"success": true,
  
"campaign": "string",
  
"adgroup": "string",
  
"targets_created": 0,
  
"product_ads_created": 0,
  
"stopped_at": "string",
  
"partial_errors": [
  
  
"string"
  
]
}

Playground​

Authorization
Headers
Body

Samples​


Update Epinium's own optimization settings for a campaign​

PATCH
/v1/campaigns/{id}/optimization-config

Sets what the optimizer chases for this campaign: target ACOS or ROAS, bid floor and ceiling, monthly budget, harvesting overrides, and which workflows may touch it. None of this reaches Amazon - it is the configuration Epinium optimizes against, so no Idempotency-Key is required. Read the current values with GET /v1/campaigns/:id?expand[]=optimizationConfig. What puts a campaign under the optimizer is linkedWorkflowDefinitionIds: a workflow listed there processes it every night and moves real bids on Amazon - confirm it with the person first, exactly as you would turning a workflow on. A workflow that selects campaigns on its own can also pick it up, and workflowsOptOut: true is what declines that; the only setting that always keeps a workflow away is excludedWorkflowDefinitionIds, which wins over the other two. aiEnabled is NOT that switch: it records the account holder consent, travels to Amazon as the epinium:ai_enabled tag and makes the campaign eligible as a cross-harvest peer, so aiEnabled: false does NOT take a campaign out of the optimizer - remove it from linkedWorkflowDefinitionIds (plus workflowsOptOut: true if the workflow selects campaigns on its own) or add the workflow to excludedWorkflowDefinitionIds instead. optimizeDate and optimizingSince are read-only, stamped by the optimizer itself, and sending either is a 400. Requires campaigns:write.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Request Body​

application/json
JSON
{
  
"aiEnabled": true,
  
"objective": {
  
  
"type": "string",
  
  
"value": 0,
  
  
"maxAcosPct": 0
  
},
  
"limits": {
  
  
"minBid": 0,
  
  
"maxBid": 0,
  
  
"placementCapPercent": 0,
  
  
"minSpendBeforeNegative": 0
  
},
  
"budget": {
  
  
"dailyBudget": 0,
  
  
"monthlyBudget": 0
  
},
  
"harvesting": {
  
  
"crossCampaign": {
  
  
  
"enabled": true,
  
  
  
"harvestGroupKey": "string",
  
  
  
"role": "string"
  
  
},
  
  
"discoveryLevel": "string",
  
  
"competitorAsinTargeting": true
  
},
  
"warmingModeUntil": "string",
  
"linkedWorkflowDefinitionIds": [
  
  
"string"
  
],
  
"excludedWorkflowDefinitionIds": [
  
  
"string"
  
],
  
"workflowsOptOut": true
}

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"paths": [
  
  
"string"
  
],
  
"reason": "string",
  
"error": "string"
}

Playground​

Authorization
Variables
Key
Value
Body

Samples​


Same update for up to 1000 campaigns, one patch per row​

POST
/v1/campaigns/optimization-config/batch

NOT all-or-nothing: data carries one row per campaign you sent, in the order you sent them. A row that fails validation comes back failed with the reason and the others still apply, because each campaign is validated against its OWN stored state - a bid ceiling that is mandatory for one objective may be absent in another campaign. The warning about linkedWorkflowDefinitionIds applies to every row: enrolling a batch puts all of those campaigns under a workflow that moves real bids on Amazon every night, so confirm it with the person before doing it wholesale. aiEnabled is consent and an Amazon tag, not the enrolment switch, in the batch exactly as in the single. Requires campaigns:write.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Request Body​

application/json
JSON
{
  
"changes": [
  
  
{
  
  
  
"aiEnabled": true,
  
  
  
"objective": {
  
  
  
  
"type": "string",
  
  
  
  
"value": 0,
  
  
  
  
"maxAcosPct": 0
  
  
  
},
  
  
  
"limits": {
  
  
  
  
"minBid": 0,
  
  
  
  
"maxBid": 0,
  
  
  
  
"placementCapPercent": 0,
  
  
  
  
"minSpendBeforeNegative": 0
  
  
  
},
  
  
  
"budget": {
  
  
  
  
"dailyBudget": 0,
  
  
  
  
"monthlyBudget": 0
  
  
  
},
  
  
  
"harvesting": {
  
  
  
  
"crossCampaign": {
  
  
  
  
  
"enabled": true,
  
  
  
  
  
"harvestGroupKey": "string",
  
  
  
  
  
"role": "string"
  
  
  
  
},
  
  
  
  
"discoveryLevel": "string",
  
  
  
  
"competitorAsinTargeting": true
  
  
  
},
  
  
  
"warmingModeUntil": "string",
  
  
  
"linkedWorkflowDefinitionIds": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"excludedWorkflowDefinitionIds": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"workflowsOptOut": true,
  
  
  
"id": "string"
  
  
}
  
]
}

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"result": "string",
  
  
  
"paths": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"reason": "string",
  
  
  
"error": "string"
  
  
}
  
],
  
"applied": 0,
  
"failed": 0
}

Playground​

Authorization
Body

Samples​


Change state, budget, name or portfolio on up to 1000 campaigns​

POST
/v1/campaigns/batch

Same fields as the single update, up to 1000 campaigns per call - the cap is the per-request limit Amazon itself declares. NOT all-or-nothing: data carries one row per campaign you sent, in the order you sent them, and applied is what actually reached Amazon. Only applied rows are billed. A campaign is applied only when EVERY field you asked for went through: if the state changes and the budget is rejected, that campaign is failed with the reason, because reporting it as applied is how an agent concludes the budget moved when it did not. Requires campaigns:write and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"changes": [
  
  
{
  
  
  
"state": "string",
  
  
  
"dailyBudget": 0,
  
  
  
"name": "string",
  
  
  
"portfolioId": "string",
  
  
  
"id": "string"
  
  
}
  
]
}

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"result": "string",
  
  
  
"error": "string"
  
  
}
  
],
  
"applied": 0,
  
"failed": 0
}

Playground​

Authorization
Headers
Body

Samples​


campaign-metrics​

Advertising performance per campaign, aggregated from the account's report history. Requires campaigns:read.


Advertising performance per campaign, from the account's report history​

GET
/v1/campaign-metrics

Aggregated from the report history over a required start_date/end_date window. Unlike the rest of the API, this resource paginates with limit/offset (an aggregated row has no id to use as a cursor) and has_more tells whether another page follows. Monetary amounts are decimal strings; ratios are fractions (0.1642 = 16.42%) and are null, never 0, when their denominator is zero. With group_by, rows are aggregated across entities (see the parameter) and total_count counts groups, or group-periods when granularity is not total.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

start_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-01"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
end_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-31"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
granularity

total (default) aggregates the whole window into one row per entity or group. Any other value adds a date field with the START of each calendar period: the day, the Monday of the ISO week, or the first day of the month, quarter or year. Periods at the edges of the window are partial: 2026-01-15..2026-03-10 with monthly returns January (15th to 31st), February, and March (1st to 10th). daily has a shorter window cap than the rest.

Type
string
Valid values
"total""daily""weekly""monthly""quarterly""yearly"
Example"total"
Default
"total"
limit

Page size. For a top-N, combine order_by with a small limit instead of raising it: limit/offset bound the response, not what ClickHouse scans.

Type
integer
Example100
Default
100
Minimum
1
Maximum
1000
offset
Type
integer
Example0
Default
0
Minimum
0
Maximum
9007199254740991
order
Type
string
Valid values
"asc""desc"
Example"desc"
Default
"desc"
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
group_by

Aggregate across entities instead of returning one row per entity. To get the account total, or a per-country or per-connection breakdown, use this INSTEAD of paging through the catalog and summing: one row per group (and per period when granularity is not total), and the credits scale with the groups returned, not with the number of products. account collapses everything and cannot be combined with other values; connection and country can be combined by repeating the param (group_by[]=connection&group_by[]=country). Rows are always split by currency (amounts are never converted) and, in advertising, by ad_product. In grouped rows the entity fields (product, asin, sku, campaign, ad_group, target...) are null, and so are the metrics that cannot be aggregated (rank, price, fulfillment_channel, vendor rates and sourcing_lead_time_days). Seller stock and days_of_coverage are null too unless country is one of the dimensions: FBA Pan-European stock is reported in full in every marketplace, so adding it up across countries would count the same units once per country. Combines with every filter.

connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
ad_product
Type
string
Valid values
"SP""SB""SD"
order_by
Type
string
Valid values
"cost""sales""impressions""clicks""orders""units""acos""roas""ctr""cpc""conversion_rate"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"object": "string",
  
  
  
"campaign": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"ad_product": "string",
  
  
  
"currency": "string",
  
  
  
"date": "string",
  
  
  
"impressions": 0,
  
  
  
"clicks": 0,
  
  
  
"cost": "string",
  
  
  
"sales": "string",
  
  
  
"orders": 0,
  
  
  
"units": 0,
  
  
  
"ctr": 0,
  
  
  
"cpc": "string",
  
  
  
"acos": 0,
  
  
  
"roas": 0,
  
  
  
"conversion_rate": 0,
  
  
  
"top_of_search_is": 0,
  
  
  
"new_to_brand_sales": "string",
  
  
  
"new_to_brand_purchases": 0,
  
  
  
"detail_page_views": 0,
  
  
  
"viewable_impressions": 0
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


portfolios​

The authenticated account's portfolios and the budget cap each one puts on its campaigns. Requires campaigns:read; writing requires campaigns:write.


List the authenticated account's portfolios and their budget caps​

GET
/v1/portfolios

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

limit

Page size. The default is enough to explore; raise it only when you need to walk a whole collection.

Type
integer
Example20
Default
20
Minimum
1
Maximum
100
starting_after

Cursor for the next page: the id of the last record you received. Returns the records after it.

Type
string
ending_before

Cursor for the previous page: the id of the first record you received. Returns the records before it.

Type
string
search

Case-insensitive substring match over the portfolio name. Use it to find a record by name when you do not have its id, instead of paging through the whole list. Regex metacharacters are matched literally.

Type
string
Min Length
1
Max Length
200
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
state
Type
string
Valid values
"ENABLED""PAUSED""ARCHIVED""OTHER"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"portfolioId": "string",
  
  
  
"name": "string",
  
  
  
"state": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"budget": {
  
  
  
  
"policy": "string",
  
  
  
  
"amount": 0,
  
  
  
  
"currencyCode": "string",
  
  
  
  
"startDate": "string",
  
  
  
  
"endDate": "string"
  
  
  
},
  
  
  
"inBudget": true,
  
  
  
"servingStatus": "string",
  
  
  
"statusReasons": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string"
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


Create a portfolio, optionally with a budget cap​

POST
/v1/portfolios

Creates a portfolio in the Amazon Ads account of connection. budget caps what ALL the campaigns in the portfolio can spend together: MONTHLY_RECURRING resets every month, DATE_RANGE applies between startDate and endDate, NO_CAP removes the cap. The currency is the marketplace one; you do not send it. If Amazon rejects the portfolio the response is still 201 with result: "failed", the reason in error and id: null. Requires the campaigns:write scope and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"connection": "string",
  
"name": "string",
  
"state": "ENABLED",
  
"budget": {
  
  
"policy": "string",
  
  
"amount": 0,
  
  
"startDate": "string",
  
  
"endDate": "string"
  
}
}

Responses​

201

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Body

Samples​


GET /v1/portfolios/{id}​

GET
/v1/portfolios/{id}

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"portfolioId": "string",
  
"name": "string",
  
"state": "string",
  
"connection": "string",
  
"country": "string",
  
"budget": {
  
  
"policy": "string",
  
  
"amount": 0,
  
  
"currencyCode": "string",
  
  
"startDate": "string",
  
  
"endDate": "string"
  
},
  
"inBudget": true,
  
"servingStatus": "string",
  
"statusReasons": [
  
  
"string"
  
],
  
"createdAt": "string",
  
"updatedAt": "string"
}

Playground​

Authorization
Variables
Key
Value

Samples​


Change the name, state or budget cap of a portfolio​

PATCH
/v1/portfolios/{id}

Send only what you want to change; at least one field is required. budget is replaced whole: send the full cap you want, not just the amount. A portfolio that does not exist, or belongs to another account, is a 404. If Amazon rejects the change the response is still 200 with result: "failed" and the reason, and nothing is changed on our side. Requires the campaigns:write scope and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Request Body​

application/json
JSON
{
  
"name": "string",
  
"state": "string",
  
"budget": {
  
  
"policy": "string",
  
  
"amount": 0,
  
  
"startDate": "string",
  
  
"endDate": "string"
  
}
}

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Variables
Key
Value
Body

Samples​


adgroups​


List the authenticated account's ad groups​

GET
/v1/adgroups

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

limit

Page size. The default is enough to explore; raise it only when you need to walk a whole collection.

Type
integer
Example20
Default
20
Minimum
1
Maximum
100
starting_after

Cursor for the next page: the id of the last record you received. Returns the records after it.

Type
string
ending_before

Cursor for the previous page: the id of the first record you received. Returns the records before it.

Type
string
expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object
search

Case-insensitive substring match over the ad group name. Use it to find a record by name when you do not have its id, instead of paging through the whole list. Regex metacharacters are matched literally.

Type
string
Min Length
1
Max Length
200
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
state
Type
string
Valid values
"ENABLED""PAUSED""ARCHIVED""OTHER"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"adProduct": "string",
  
  
  
"adGroupId": "string",
  
  
  
"name": "string",
  
  
  
"state": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"campaign": "string",
  
  
  
"defaultBid": 0,
  
  
  
"adGroupTargetType": "string",
  
  
  
"deliveryStatus": "string",
  
  
  
"deliveryReasons": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string"
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


Create an ad group inside a Sponsored Products campaign​

POST
/v1/adgroups

Created PAUSED unless you pass state: "ENABLED". defaultBid is clamped to the marketplace bid limits for the campaign country, so a bid outside them is adjusted rather than rejected. The campaign must already be published on Amazon; one that belongs to another account is a 404, never a 403. Requires the campaigns:write scope and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"campaign": "string",
  
"name": "string",
  
"defaultBid": 0,
  
"state": "PAUSED",
  
"targetType": "string"
}

Responses​

201

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Body

Samples​


GET /v1/adgroups/{id}​

GET
/v1/adgroups/{id}

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Query Parameters

expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"adProduct": "string",
  
"adGroupId": "string",
  
"name": "string",
  
"state": "string",
  
"connection": "string",
  
"country": "string",
  
"campaign": "string",
  
"defaultBid": 0,
  
"adGroupTargetType": "string",
  
"deliveryStatus": "string",
  
"deliveryReasons": [
  
  
"string"
  
],
  
"createdAt": "string",
  
"updatedAt": "string"
}

Playground​

Authorization
Variables
Key
Value

Samples​


Archive a ad group​

DELETE
/v1/adgroups/{id}

Archiving is how Amazon removes an entity, and it CANNOT BE UNDONE: an archived ad group does not come back, and this is the only irreversible operation in this API. That is why it is its own verb instead of a state you could set by accident while changing a bid. Use state: "PAUSED" if you only want to stop it - that one is reversible. An ad group that does not exist, or belongs to another account, is a 404. One managed by the optimizer is refused. Requires the campaigns:write scope and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Variables
Key
Value

Samples​


Change the state, default bid or name of an ad group​

PATCH
/v1/adgroups/{id}

Send only the fields you want to change; anything you omit is left as it is. At least one field is required. defaultBid is checked against the marketplace bid limits before it is sent, so an out-of-range bid comes back with the limits instead of a generic rejection from Amazon. An ad group that does not exist, or belongs to another account, is a 404 - never a 403, which would confirm it exists. One managed by the optimizer is refused, because its next run would overwrite you. If Amazon rejects the change the response is still 200 with result: "failed" and the reason. Requires the campaigns:write scope and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Request Body​

application/json
JSON
{
  
"state": "string",
  
"defaultBid": 0,
  
"name": "string"
}

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Variables
Key
Value
Body

Samples​


Change state, default bid or name on up to 1000 ad groups​

POST
/v1/adgroups/batch

Same fields as the single update, up to 1000 ad groups per call - the cap is the per-request limit Amazon itself declares. NOT all-or-nothing: data carries one row per ad group you sent, in the order you sent them, and applied is what actually reached Amazon. Only applied rows are billed. An ad group is applied only when EVERY field you asked for went through. Requires campaigns:write and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"changes": [
  
  
{
  
  
  
"state": "string",
  
  
  
"defaultBid": 0,
  
  
  
"name": "string",
  
  
  
"id": "string"
  
  
}
  
]
}

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"result": "string",
  
  
  
"error": "string"
  
  
}
  
],
  
"applied": 0,
  
"failed": 0
}

Playground​

Authorization
Headers
Body

Samples​


adgroup-metrics​

Performance per ad group over a date range.


Advertising performance per ad group, from the account's report history​

GET
/v1/adgroup-metrics

Aggregated from the report history over a required start_date/end_date window. Like the rest of the metrics resources it paginates with limit/offset (an aggregated row has no id to use as a cursor) and has_more tells whether another page follows. Monetary amounts are decimal strings; ratios are fractions (0.1642 = 16.42%) and are null, never 0, when their denominator is zero. With group_by, rows are aggregated across entities (see the parameter) and total_count counts groups, or group-periods when granularity is not total.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

start_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-01"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
end_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-31"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
granularity

total (default) aggregates the whole window into one row per entity or group. Any other value adds a date field with the START of each calendar period: the day, the Monday of the ISO week, or the first day of the month, quarter or year. Periods at the edges of the window are partial: 2026-01-15..2026-03-10 with monthly returns January (15th to 31st), February, and March (1st to 10th). daily has a shorter window cap than the rest.

Type
string
Valid values
"total""daily""weekly""monthly""quarterly""yearly"
Example"total"
Default
"total"
limit

Page size. For a top-N, combine order_by with a small limit instead of raising it: limit/offset bound the response, not what ClickHouse scans.

Type
integer
Example100
Default
100
Minimum
1
Maximum
1000
offset
Type
integer
Example0
Default
0
Minimum
0
Maximum
9007199254740991
order
Type
string
Valid values
"asc""desc"
Example"desc"
Default
"desc"
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
group_by

Aggregate across entities instead of returning one row per entity. To get the account total, or a per-country or per-connection breakdown, use this INSTEAD of paging through the catalog and summing: one row per group (and per period when granularity is not total), and the credits scale with the groups returned, not with the number of products. account collapses everything and cannot be combined with other values; connection and country can be combined by repeating the param (group_by[]=connection&group_by[]=country). Rows are always split by currency (amounts are never converted) and, in advertising, by ad_product. In grouped rows the entity fields (product, asin, sku, campaign, ad_group, target...) are null, and so are the metrics that cannot be aggregated (rank, price, fulfillment_channel, vendor rates and sourcing_lead_time_days). Seller stock and days_of_coverage are null too unless country is one of the dimensions: FBA Pan-European stock is reported in full in every marketplace, so adding it up across countries would count the same units once per country. Combines with every filter.

connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
ad_group

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
ad_product
Type
string
Valid values
"SP""SB""SD"
order_by
Type
string
Valid values
"cost""sales""impressions""clicks""orders""units""acos""roas""ctr""cpc""conversion_rate"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"object": "string",
  
  
  
"ad_group": "string",
  
  
  
"campaign": "string",
  
  
  
"ad_product": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"currency": "string",
  
  
  
"date": "string",
  
  
  
"impressions": 0,
  
  
  
"clicks": 0,
  
  
  
"cost": "string",
  
  
  
"sales": "string",
  
  
  
"orders": 0,
  
  
  
"units": 0,
  
  
  
"ctr": 0,
  
  
  
"cpc": "string",
  
  
  
"acos": 0,
  
  
  
"roas": 0,
  
  
  
"conversion_rate": 0,
  
  
  
"new_to_brand_sales": "string",
  
  
  
"new_to_brand_purchases": 0,
  
  
  
"detail_page_views": 0,
  
  
  
"viewable_impressions": 0
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


targets​

The authenticated account's advertising targets. Requires campaigns:read.


List the authenticated account's advertising targets​

GET
/v1/targets

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

limit

Page size. The default is enough to explore; raise it only when you need to walk a whole collection.

Type
integer
Example20
Default
20
Minimum
1
Maximum
100
starting_after

Cursor for the next page: the id of the last record you received. Returns the records after it.

Type
string
ending_before

Cursor for the previous page: the id of the first record you received. Returns the records before it.

Type
string
expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object
search

Case-insensitive substring match over the target's expression (keyword, ASIN or category, chosen by targetType) and its matchType; with targetType set, only that type's field is searched. Use it to find a record by name when you do not have its id, instead of paging through the whole list. Regex metacharacters are matched literally.

Type
string
Min Length
1
Max Length
200
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
adGroup

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
state
Type
string
Valid values
"ENABLED""PAUSED""ARCHIVED""OTHER"
targetType
Type
string
Valid values
"AUTO""KEYWORD""PRODUCT_CATEGORY""PRODUCT""PRODUCT_CATEGORY_AUDIENCE""PRODUCT_AUDIENCE""AUDIENCE""THEME""CONTENT_CATEGORY""LOCATION"
negative
Type
string
Valid values
"true""false"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"adProduct": "string",
  
  
  
"targetId": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"campaign": "string",
  
  
  
"adGroup": "string",
  
  
  
"state": "string",
  
  
  
"negative": true,
  
  
  
"bid": 0,
  
  
  
"targetType": "string",
  
  
  
"targetLevel": "string",
  
  
  
"deliveryStatus": "string",
  
  
  
"deliveryReasons": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string"
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


Create keyword, product or category targets in an ad group​

POST
/v1/targets

Creates up to 1000 targets in one call — the cap is Amazon's own per-request limit. NOT all-or-nothing: the response counts what went in and lists every rejection in failure_details with its reason, so a partial result is actionable instead of a retry that duplicates what already worked. Amazon rules are enforced before sending (negative keyword length and word count, category id coercion) and the ad group capacity is checked against the Amazon limits. The response returns COUNTS, not ids: list the ad group targets to get them. Requires campaigns:write and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"adgroup": "string",
  
"targets": [
  
  
{
  
  
  
"targetType": "string",
  
  
  
"negative": false,
  
  
  
"keywordText": "string",
  
  
  
"matchType": "string",
  
  
  
"asin": "string",
  
  
  
"sku": "string",
  
  
  
"productMatchType": "string",
  
  
  
"category": "string",
  
  
  
"productBrand": "string",
  
  
  
"productPriceGreaterThan": 0,
  
  
  
"productPriceLessThan": 0,
  
  
  
"productRatingGreaterThan": 0,
  
  
  
"productRatingLessThan": 0,
  
  
  
"productAgeRange": "string",
  
  
  
"productPrimeShippingEligible": true,
  
  
  
"themeMatchType": "string",
  
  
  
"event": "string",
  
  
  
"lookback": 0,
  
  
  
"audienceId": "string",
  
  
  
"contentCategoryId": "string",
  
  
  
"locationId": "string",
  
  
  
"bid": 0
  
  
}
  
]
}

Responses​

201

application/json
JSON
{
  
"created": 0,
  
"failed": 0,
  
"failure_details": [
  
  
{
  
  
  
"reference": "string",
  
  
  
"error": "string"
  
  
}
  
]
}

Playground​

Authorization
Headers
Body

Samples​


GET /v1/targets/{id}​

GET
/v1/targets/{id}

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Query Parameters

expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"adProduct": "string",
  
"targetId": "string",
  
"connection": "string",
  
"country": "string",
  
"campaign": "string",
  
"adGroup": "string",
  
"state": "string",
  
"negative": true,
  
"bid": 0,
  
"targetType": "string",
  
"targetLevel": "string",
  
"deliveryStatus": "string",
  
"deliveryReasons": [
  
  
"string"
  
],
  
"createdAt": "string",
  
"updatedAt": "string"
}

Playground​

Authorization
Variables
Key
Value

Samples​


Archive a target​

DELETE
/v1/targets/{id}

Archiving is how Amazon removes an entity, and it CANNOT BE UNDONE: an archived target does not come back, and this is the only irreversible operation in this API. That is why it is its own verb instead of a state you could set by accident while changing a bid. Use state: "PAUSED" if you only want to stop it - that one is reversible. A target that does not exist, or belongs to another account, is a 404. Requires the campaigns:write scope and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Variables
Key
Value

Samples​


Change the state or bid of a target​

PATCH
/v1/targets/{id}

Send only the fields you want to change; anything you omit is left as it is. At least one field is required. Only state and bid: what defines a target - its keyword, its ASIN, its match type - is not editable on Amazon, so to change that you create another and archive this one. A negative target has no bid and asking for one is refused. bid is checked against the marketplace limits before it is sent. A target that does not exist, or belongs to another account, is a 404 - never a 403. If Amazon rejects the change the response is still 200 with result: "failed". Requires campaigns:write and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Request Body​

application/json
JSON
{
  
"state": "string",
  
"bid": 0
}

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Variables
Key
Value
Body

Samples​


Change state or bid on up to 1000 targets​

POST
/v1/targets/batch

This is the bid sweep: up to 1000 targets in ONE call, each with its own bid - the cap is the per-request limit Amazon itself declares. Prefer it over calling the single update in a loop. NOT all-or-nothing: data carries one row per target you sent, in the order you sent them, and applied is what actually reached Amazon. Only applied rows are billed, so a partial result costs you only what worked. A target is applied only when EVERY field you asked for went through. Requires campaigns:write and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"changes": [
  
  
{
  
  
  
"state": "string",
  
  
  
"bid": 0,
  
  
  
"id": "string"
  
  
}
  
]
}

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"result": "string",
  
  
  
"error": "string"
  
  
}
  
],
  
"applied": 0,
  
"failed": 0
}

Playground​

Authorization
Headers
Body

Samples​


target-metrics​

Performance per target, with its keyword and match type.


Advertising performance per target, from the account's report history​

GET
/v1/target-metrics

Aggregated from the report history over a required start_date/end_date window, with the target type and keyword resolved from the catalog. This is one of the two heaviest resources, so its window is capped shorter: 93 days for granularity=total and 31 for daily. Paginates with limit/offset and has_more tells whether another page follows. Monetary amounts are decimal strings; ratios are fractions (0.1642 = 16.42%) and are null, never 0, when their denominator is zero. With group_by, rows are aggregated across entities (see the parameter) and total_count counts groups, or group-periods when granularity is not total.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

start_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-01"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
end_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-31"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
granularity

total (default) aggregates the whole window into one row per entity or group. Any other value adds a date field with the START of each calendar period: the day, the Monday of the ISO week, or the first day of the month, quarter or year. Periods at the edges of the window are partial: 2026-01-15..2026-03-10 with monthly returns January (15th to 31st), February, and March (1st to 10th). daily has a shorter window cap than the rest.

Type
string
Valid values
"total""daily""weekly""monthly""quarterly""yearly"
Example"total"
Default
"total"
limit

Page size. For a top-N, combine order_by with a small limit instead of raising it: limit/offset bound the response, not what ClickHouse scans.

Type
integer
Example100
Default
100
Minimum
1
Maximum
1000
offset
Type
integer
Example0
Default
0
Minimum
0
Maximum
9007199254740991
order
Type
string
Valid values
"asc""desc"
Example"desc"
Default
"desc"
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
group_by

Aggregate across entities instead of returning one row per entity. To get the account total, or a per-country or per-connection breakdown, use this INSTEAD of paging through the catalog and summing: one row per group (and per period when granularity is not total), and the credits scale with the groups returned, not with the number of products. account collapses everything and cannot be combined with other values; connection and country can be combined by repeating the param (group_by[]=connection&group_by[]=country). Rows are always split by currency (amounts are never converted) and, in advertising, by ad_product. In grouped rows the entity fields (product, asin, sku, campaign, ad_group, target...) are null, and so are the metrics that cannot be aggregated (rank, price, fulfillment_channel, vendor rates and sourcing_lead_time_days). Seller stock and days_of_coverage are null too unless country is one of the dimensions: FBA Pan-European stock is reported in full in every marketplace, so adding it up across countries would count the same units once per country. Combines with every filter.

connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
ad_group

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
target

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
ad_product
Type
string
Valid values
"SP""SB""SD"
order_by
Type
string
Valid values
"cost""sales""impressions""clicks""orders""units""acos""roas""ctr""cpc""conversion_rate"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"object": "string",
  
  
  
"target": "string",
  
  
  
"target_type": "string",
  
  
  
"match_type": "string",
  
  
  
"target_expression": "string",
  
  
  
"campaign": "string",
  
  
  
"ad_group": "string",
  
  
  
"ad_product": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"currency": "string",
  
  
  
"date": "string",
  
  
  
"impressions": 0,
  
  
  
"clicks": 0,
  
  
  
"cost": "string",
  
  
  
"sales": "string",
  
  
  
"orders": 0,
  
  
  
"units": 0,
  
  
  
"ctr": 0,
  
  
  
"cpc": "string",
  
  
  
"acos": 0,
  
  
  
"roas": 0,
  
  
  
"conversion_rate": 0,
  
  
  
"new_to_brand_sales": "string",
  
  
  
"new_to_brand_purchases": 0,
  
  
  
"detail_page_views": 0,
  
  
  
"viewable_impressions": 0
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


product-ads​


List the authenticated account's advertising product ads​

GET
/v1/product-ads

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

limit

Page size. The default is enough to explore; raise it only when you need to walk a whole collection.

Type
integer
Example20
Default
20
Minimum
1
Maximum
100
starting_after

Cursor for the next page: the id of the last record you received. Returns the records after it.

Type
string
ending_before

Cursor for the previous page: the id of the first record you received. Returns the records before it.

Type
string
expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object
search

Case-insensitive substring match over the advertised ASIN and SKU. Use it to find a record by name when you do not have its id, instead of paging through the whole list. Regex metacharacters are matched literally.

Type
string
Min Length
1
Max Length
200
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
adGroup

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
product

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
asin
Type
string
state
Type
string
Valid values
"ENABLED""PAUSED""ARCHIVED""OTHER"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"adProduct": "string",
  
  
  
"adId": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"campaign": "string",
  
  
  
"adGroup": "string",
  
  
  
"product": "string",
  
  
  
"asin": "string",
  
  
  
"sku": "string",
  
  
  
"state": "string",
  
  
  
"adType": "string",
  
  
  
"deliveryStatus": "string",
  
  
  
"deliveryReasons": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string"
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


Advertise catalog products in an ad group​

POST
/v1/product-ads

Each entry links one catalog product to the ad group. Products are resolved against YOUR catalog: one that is not there, or that lacks the identifier the account needs (ASIN for Vendor, SKU for Seller), is reported in failure_details with that reason instead of failing the whole call. Created PAUSED unless asked otherwise. The response returns COUNTS, not ids: list the ad group product ads to get them. Requires campaigns:write and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"adgroup": "string",
  
"productAds": [
  
  
{
  
  
  
"product": "string",
  
  
  
"state": "PAUSED"
  
  
}
  
]
}

Responses​

201

application/json
JSON
{
  
"created": 0,
  
"failed": 0,
  
"failure_details": [
  
  
{
  
  
  
"reference": "string",
  
  
  
"error": "string"
  
  
}
  
]
}

Playground​

Authorization
Headers
Body

Samples​


GET /v1/product-ads/{id}​

GET
/v1/product-ads/{id}

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Query Parameters

expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"adProduct": "string",
  
"adId": "string",
  
"connection": "string",
  
"country": "string",
  
"campaign": "string",
  
"adGroup": "string",
  
"product": "string",
  
"asin": "string",
  
"sku": "string",
  
"state": "string",
  
"adType": "string",
  
"deliveryStatus": "string",
  
"deliveryReasons": [
  
  
"string"
  
],
  
"createdAt": "string",
  
"updatedAt": "string"
}

Playground​

Authorization
Variables
Key
Value

Samples​


Archive a product ad​

DELETE
/v1/product-ads/{id}

Archiving is how Amazon removes an entity, and it CANNOT BE UNDONE: an archived product ad does not come back, and this is the only irreversible operation in this API. That is why it is its own verb instead of a state you could set by accident while changing a bid. Use state: "PAUSED" if you only want to stop it - that one is reversible. A product ad that does not exist, or belongs to another account, is a 404. Requires the campaigns:write scope and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Variables
Key
Value

Samples​


Enable or pause a product ad​

PATCH
/v1/product-ads/{id}

State is the only writable field: a product ad links one catalog product to an ad group and has no bid or name of its own. A product ad that does not exist, or belongs to another account, is a 404 - never a 403. If Amazon rejects the change the response is still 200 with result: "failed" and the reason. Requires campaigns:write and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Request Body​

application/json
JSON
{
  
"state": "string"
}

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"result": "string",
  
"error": "string"
}

Playground​

Authorization
Headers
Variables
Key
Value
Body

Samples​


Enable or pause up to 1000 product ads​

POST
/v1/product-ads/batch

Up to 1000 product ads per call - the cap is the per-request limit Amazon itself declares. NOT all-or-nothing: data carries one row per product ad you sent, in the order you sent them, and applied is what actually reached Amazon. Only applied rows are billed. Requires campaigns:write and an Idempotency-Key header.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Header Parameters

idempotency-key*

Any string identifying this intent, up to 255 characters. Reuse the same value when retrying the same change: without it a network timeout turns one write into two.

Type
string
Required
Min Length
1
Max Length
255

Request Body​

application/json
JSON
{
  
"changes": [
  
  
{
  
  
  
"state": "string",
  
  
  
"id": "string"
  
  
}
  
]
}

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"result": "string",
  
  
  
"error": "string"
  
  
}
  
],
  
"applied": 0,
  
"failed": 0
}

Playground​

Authorization
Headers
Body

Samples​


product-ad-metrics​

Performance per advertised product, with its ASIN.


Advertising performance per product ad, from the account's report history​

GET
/v1/product-ad-metrics

Aggregated from the report history over a required start_date/end_date window. Only Sponsored Products and Sponsored Display have product ads; Sponsored Brands does not, so ad_product accepts SP and SD only. Paginates with limit/offset and has_more tells whether another page follows. Monetary amounts are decimal strings; ratios are fractions (0.1642 = 16.42%) and are null, never 0, when their denominator is zero. With group_by, rows are aggregated across entities (see the parameter) and total_count counts groups, or group-periods when granularity is not total.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

start_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-01"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
end_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-31"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
granularity

total (default) aggregates the whole window into one row per entity or group. Any other value adds a date field with the START of each calendar period: the day, the Monday of the ISO week, or the first day of the month, quarter or year. Periods at the edges of the window are partial: 2026-01-15..2026-03-10 with monthly returns January (15th to 31st), February, and March (1st to 10th). daily has a shorter window cap than the rest.

Type
string
Valid values
"total""daily""weekly""monthly""quarterly""yearly"
Example"total"
Default
"total"
limit

Page size. For a top-N, combine order_by with a small limit instead of raising it: limit/offset bound the response, not what ClickHouse scans.

Type
integer
Example100
Default
100
Minimum
1
Maximum
1000
offset
Type
integer
Example0
Default
0
Minimum
0
Maximum
9007199254740991
order
Type
string
Valid values
"asc""desc"
Example"desc"
Default
"desc"
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
group_by

Aggregate across entities instead of returning one row per entity. To get the account total, or a per-country or per-connection breakdown, use this INSTEAD of paging through the catalog and summing: one row per group (and per period when granularity is not total), and the credits scale with the groups returned, not with the number of products. account collapses everything and cannot be combined with other values; connection and country can be combined by repeating the param (group_by[]=connection&group_by[]=country). Rows are always split by currency (amounts are never converted) and, in advertising, by ad_product. In grouped rows the entity fields (product, asin, sku, campaign, ad_group, target...) are null, and so are the metrics that cannot be aggregated (rank, price, fulfillment_channel, vendor rates and sourcing_lead_time_days). Seller stock and days_of_coverage are null too unless country is one of the dimensions: FBA Pan-European stock is reported in full in every marketplace, so adding it up across countries would count the same units once per country. Combines with every filter. cluster gives one row per product cluster (the clusters resource), with its id in cluster and its name in cluster_name. A product in several clusters counts in full in each of them, so the cluster rows do NOT add up to the account total, and products in no cluster are left out. It combines with connection and country, and with the cluster filter to choose which clusters come back.

cluster

Restrict the rows to the products of one or more product clusters (the clusters resource), by cluster id; repeat the param for several (cluster[]=a&cluster[]=b) and the result is their union, a product in two of them counting once. A cluster holds catalog products (one per connection and country), not ASINs: seller and vendor metrics keep exactly those products, so the same ASIN on another connection is left out unless its product is in the cluster too; product-ad metrics keep each product's ASIN in its country, across every advertising profile in scope. Combines with group_by (e.g. the monthly total of a product family) and with every other filter. An id that does not exist or belongs to another account contributes nothing, so the list comes back empty rather than failing. Rows that Amazon could not match to a catalog product are excluded by this filter: about 0.01% of seller sales, about 5% of vendor sales, and about 3% of product-ad spend (those rows carry no ASIN either).

connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
ad_group

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
product_ad

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
asin

Amazon ASIN: 10 uppercase letters or digits, e.g. B08GPHNSCW.

Type
string
Pattern
"^[A-Z0-9]{10}$"
ad_product
Type
string
Valid values
"SP""SD"
order_by
Type
string
Valid values
"cost""sales""impressions""clicks""orders""units""acos""roas""ctr""cpc""conversion_rate"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"object": "string",
  
  
  
"product_ad": "string",
  
  
  
"product": "string",
  
  
  
"asin": "string",
  
  
  
"campaign": "string",
  
  
  
"ad_group": "string",
  
  
  
"cluster": "string",
  
  
  
"cluster_name": "string",
  
  
  
"ad_product": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"currency": "string",
  
  
  
"date": "string",
  
  
  
"impressions": 0,
  
  
  
"clicks": 0,
  
  
  
"cost": "string",
  
  
  
"sales": "string",
  
  
  
"orders": 0,
  
  
  
"units": 0,
  
  
  
"ctr": 0,
  
  
  
"cpc": "string",
  
  
  
"acos": 0,
  
  
  
"roas": 0,
  
  
  
"conversion_rate": 0,
  
  
  
"new_to_brand_sales": "string",
  
  
  
"new_to_brand_purchases": 0,
  
  
  
"detail_page_views": 0,
  
  
  
"viewable_impressions": 0
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


search-terms​

The authenticated account's advertising search terms. Requires campaigns:read.


List the authenticated account's advertising search terms​

GET
/v1/search-terms

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

limit

Page size. The default is enough to explore; raise it only when you need to walk a whole collection.

Type
integer
Example20
Default
20
Minimum
1
Maximum
100
starting_after

Cursor for the next page: the id of the last record you received. Returns the records after it.

Type
string
ending_before

Cursor for the previous page: the id of the first record you received. Returns the records before it.

Type
string
expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object
search

Case-insensitive substring match over the shopper search term text. Use it to find a record by name when you do not have its id, instead of paging through the whole list. Regex metacharacters are matched literally.

Type
string
Min Length
1
Max Length
200
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
adGroup

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
searchTerm
Type
string

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"adProduct": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"campaign": "string",
  
  
  
"adGroup": "string",
  
  
  
"searchTerm": "string",
  
  
  
"searchTermTargetType": "string",
  
  
  
"targetSourceMatchType": "string",
  
  
  
"lastReportDate": "string",
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string"
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


GET /v1/search-terms/{id}​

GET
/v1/search-terms/{id}

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Path Parameters

id*

24-character hexadecimal Mongo ObjectId.

Type
string
Required
Pattern
"^[a-f0-9]{24}$"

Query Parameters

expand

Inline related records instead of returning just their ids. Repeat the param for several (expand[]=connection&expand[]=country) and nest with dot notation (connection.country), up to 4 levels.

fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object

Responses​

200

application/json
JSON
{
  
"id": "string",
  
"adProduct": "string",
  
"connection": "string",
  
"country": "string",
  
"campaign": "string",
  
"adGroup": "string",
  
"searchTerm": "string",
  
"searchTermTargetType": "string",
  
"targetSourceMatchType": "string",
  
"lastReportDate": "string",
  
"createdAt": "string",
  
"updatedAt": "string"
}

Playground​

Authorization
Variables
Key
Value

Samples​


search-term-metrics​

Performance per shopper query, with its text and matching target.


Advertising performance per shopper search term, from the account's report history​

GET
/v1/search-term-metrics

Aggregated from the report history over a required start_date/end_date window, with the shopper query resolved from the catalog into query. Answers "which searches do I spend most on?": use order_by=cost with limit instead of paging. This is the heaviest resource in the API, so its window is capped shorter: 93 days for granularity=total and 31 for daily. Rows are grouped per search term AND target, because the same text can be matched by different targets. Only Sponsored Products and Sponsored Brands produce search terms, so ad_product accepts SP and SB only. Monetary amounts are decimal strings; ratios are fractions (0.1642 = 16.42%) and are null, never 0, when their denominator is zero. With group_by, rows are aggregated across entities (see the parameter) and total_count counts groups, or group-periods when granularity is not total.

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

start_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-01"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
end_date*

Both ends are included in the range. The window is capped, and the cap depends on the resource AND on granularity — daily allows a much shorter span than total, and target-metrics and search-term-metrics are stricter than the rest because limit/offset bound the response but not what ClickHouse scans. Going over returns a 400 naming the exact limit for your request.

Type
string
Required
Example"2026-07-31"
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
granularity

total (default) aggregates the whole window into one row per entity or group. Any other value adds a date field with the START of each calendar period: the day, the Monday of the ISO week, or the first day of the month, quarter or year. Periods at the edges of the window are partial: 2026-01-15..2026-03-10 with monthly returns January (15th to 31st), February, and March (1st to 10th). daily has a shorter window cap than the rest.

Type
string
Valid values
"total""daily""weekly""monthly""quarterly""yearly"
Example"total"
Default
"total"
limit

Page size. For a top-N, combine order_by with a small limit instead of raising it: limit/offset bound the response, not what ClickHouse scans.

Type
integer
Example100
Default
100
Minimum
1
Maximum
1000
offset
Type
integer
Example0
Default
0
Minimum
0
Maximum
9007199254740991
order
Type
string
Valid values
"asc""desc"
Example"desc"
Default
"desc"
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
group_by

Aggregate across entities instead of returning one row per entity. To get the account total, or a per-country or per-connection breakdown, use this INSTEAD of paging through the catalog and summing: one row per group (and per period when granularity is not total), and the credits scale with the groups returned, not with the number of products. account collapses everything and cannot be combined with other values; connection and country can be combined by repeating the param (group_by[]=connection&group_by[]=country). Rows are always split by currency (amounts are never converted) and, in advertising, by ad_product. In grouped rows the entity fields (product, asin, sku, campaign, ad_group, target...) are null, and so are the metrics that cannot be aggregated (rank, price, fulfillment_channel, vendor rates and sourcing_lead_time_days). Seller stock and days_of_coverage are null too unless country is one of the dimensions: FBA Pan-European stock is reported in full in every marketplace, so adding it up across countries would count the same units once per country. Combines with every filter.

connection

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
country

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
ad_group

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
target

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
search_term

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
ad_product
Type
string
Valid values
"SP""SB"
order_by
Type
string
Valid values
"cost""sales""impressions""clicks""orders""units""acos""roas""ctr""cpc""conversion_rate"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"object": "string",
  
  
  
"search_term": "string",
  
  
  
"query": "string",
  
  
  
"target": "string",
  
  
  
"campaign": "string",
  
  
  
"ad_group": "string",
  
  
  
"ad_product": "string",
  
  
  
"connection": "string",
  
  
  
"country": "string",
  
  
  
"currency": "string",
  
  
  
"date": "string",
  
  
  
"impressions": 0,
  
  
  
"clicks": 0,
  
  
  
"cost": "string",
  
  
  
"sales": "string",
  
  
  
"orders": 0,
  
  
  
"units": 0,
  
  
  
"ctr": 0,
  
  
  
"cpc": "string",
  
  
  
"acos": 0,
  
  
  
"roas": 0,
  
  
  
"conversion_rate": 0
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


advertising-changes​

Every change Epinium pushed to Amazon for the authenticated account - from the app, a workflow, an internal job or this API - including the ones Amazon rejected. Requires campaigns:read.


List the changes Epinium pushed to Amazon for the authenticated account​

GET
/v1/advertising-changes

Authorizations​

bearer

Client API key (POST /api-keys). Send as Authorization: Bearer epk_live_....

Type
HTTP (bearer)

Parameters​

Query Parameters

limit

Page size. The default is enough to explore; raise it only when you need to walk a whole collection.

Type
integer
Example20
Default
20
Minimum
1
Maximum
100
starting_after

Cursor for the next page: the id of the last record you received. Returns the records after it.

Type
string
ending_before

Cursor for the previous page: the id of the first record you received. Returns the records before it.

Type
string
fields

Trim the response to the fields you need, comma-separated and keyed by ENTITY TYPE rather than by resource name: fields[campaign]=id,name. A key that matches no entity is ignored silently and the full object comes back.

Type
object
include_total

Set to true to also receive total_count: how many records match every filter of this request, ignoring starting_after/ending_before/offset - the size of the whole result set, not of what is left. has_more is always returned regardless. It costs an extra count query, so ask for it once, on the first page, to decide whether the set is worth walking. On metrics resources it counts entities (or groups with group_by), and, with any granularity other than total, each of their periods that has data, not entities times periods: entity-days with granularity=daily. total_count comes back null when the count could not finish in time; the list is still returned, so treat it as unknown, never as zero.

Type
string
Valid values
"true""false"
campaign

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
adgroup

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
entity

24-character hexadecimal Mongo ObjectId.

Type
string
Pattern
"^[a-f0-9]{24}$"
entity_type
Type
string
Valid values
"campaign""adgroup""target""productAd""portfolio"
source
Type
string
Valid values
"front""workflow""public-api""mcp""system"
result
Type
string
Valid values
"applied""failed"
field
Type
string
correlation_id
Type
string
start_date
Type
string
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"
end_date
Type
string
Pattern
"^\\d{4}-\\d{2}-\\d{2}$"

Responses​

200

application/json
JSON
{
  
"object": "string",
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"at": "string",
  
  
  
"entity_type": "string",
  
  
  
"entity_id": "string",
  
  
  
"campaign": "string",
  
  
  
"adgroup": "string",
  
  
  
"field": "string",
  
  
  
"old_value": null,
  
  
  
"new_value": null,
  
  
  
"source": "string",
  
  
  
"actor": {
  
  
  
  
"type": "string",
  
  
  
  
"id": "string",
  
  
  
  
"label": "string"
  
  
  
},
  
  
  
"result": "string",
  
  
  
"error": "string",
  
  
  
"profile_id": "string",
  
  
  
"ad_product": "string",
  
  
  
"correlation_id": "string"
  
  
}
  
],
  
"has_more": true,
  
"total_count": 0
}

Playground​

Authorization
Variables
Key
Value

Samples​


Powered by VitePress OpenAPI

Epinium Documentation