Developers

API endpoint reference

Generated from the API contract itself: every endpoint, every field, every code.

Every endpoint MerchDash’s public API answers, with its parameters, its response fields, and what it refuses. This page is generated from the API’s own contract, so it cannot drift from what the server actually does. For how to get a key and how the review model works, start at Public API.

All endpoints sit under https://app.merchdash.net/api/v1/ and take Authorization: Bearer md_live_…. Collections answer { data, nextCursor }; single resources answer { data }. Reads are served from MerchDash’s synced archive rather than live from Amazon.

Limits

LimitValue
Rows per page, default / maximum100 / 500
Metric window, default / maximum30 days ending 2 days ago / 365 days
Changes in one POST /api/v1/changes500
Campaigns + ad groups in one POST /api/v1/structures2000
ASINs + keywords + targets in one POST /api/v1/structures20000
Request body, POST /api/v1/changes and /structures24 MB, every other endpoint accepts 1 MB
Un-answered proposals held per marketplace75

Rate limits are per key and per account, and are described on the Public API page.

Every endpoint

EndpointScopeWhat it answers
GET /api/v1/profilesreadEvery marketplace this account owns and has synced.
GET /api/v1/campaignsreadCampaigns with their metrics for a window.
GET /api/v1/portfoliosreadPortfolios with their budget caps.
GET /api/v1/videosreadThe Sponsored Brands videos in the account's Creative Asset Library, with their names.
POST /api/v1/videos/uploadswriteStart uploading a Sponsored Brands video into the account's Creative Asset Library: returns the URL to PUT the file to.
POST /api/v1/videos/uploads/:uploadId/completewriteRegister an uploaded video in the Creative Asset Library, step 3 after PUTting the file.
GET /api/v1/imagesreadThe logos and custom images in an account's Creative Asset Library, by name.
POST /api/v1/images/uploadswriteStart uploading a Sponsored Brands logo or custom image: returns the URL to PUT the file to.
POST /api/v1/images/uploads/:uploadId/completewriteRegister an uploaded logo or image in the Creative Asset Library, step 3 after PUTting the file.
GET /api/v1/storesreadThe account's Amazon Stores and their pages, the landing pages a Sponsored Brands ad may point to.
GET /api/v1/ad-groupsreadAd groups with their metrics for a window.
GET /api/v1/keywordsreadKeywords with their metrics for a window.
GET /api/v1/targetsreadTargeting clauses with their metrics for a window.
GET /api/v1/asinsreadAdvertising performance aggregated per ASIN.
GET /api/v1/product-adsreadProduct ads (an ASIN/SKU in one ad group) with their metrics for a window.
GET /api/v1/sb-adsreadSponsored Brands ads (creatives) with their metrics for a window.
GET /api/v1/sb-purchased-productsreadWhat shoppers bought after Sponsored Brands ads, per purchased ASIN, for a window.
GET /api/v1/negative-keywordsreadNegative keywords at campaign and ad-group scope.
GET /api/v1/negative-targetsreadNegative product targets (excluded ASINs and brands) at campaign and ad-group scope.
GET /api/v1/audiencesreadThe audiences a marketplace's Sponsored Products campaigns can carry a bid adjustment for.
GET /api/v1/placementsreadMetrics per campaign and placement for a window, Sponsored Products and Sponsored Brands.
POST /api/v1/recommendations/bidsreadAmazon's suggested bids for keywords and auto-targeting clauses in an existing Sponsored Products ad group.
POST /api/v1/recommendations/sb-bidsreadAmazon's suggested bids for keywords and product targets in a Sponsored Brands campaign.
POST /api/v1/recommendations/keywordsreadAmazon's ranked keyword suggestions, with suggested bids, for an ad group or a set of ASINs.
POST /api/v1/recommendations/categoriesreadThe product categories Amazon recommends targeting for a set of ASINs.
POST /api/v1/recommendations/productsreadThe products Amazon suggests targeting for a set of your advertised ASINs (Sponsored Products product targeting).
POST /api/v1/recommendations/budgetsreadAmazon's suggested daily budget for campaigns, with what running out of budget cost them (Sponsored Products and Sponsored Brands).
POST /api/v1/negative-brands/searchreadFind brands by keyword, Amazon's ids for the brands a Sponsored Products negative can exclude.
POST /api/v1/eligibilityreadWhether ASINs can be advertised, and Amazon's reasons when they cannot.
GET /api/v1/search-termsreadShopper search terms with their metrics for a window.
GET /api/v1/metrics/dailyreadAccount totals for each day in a window.
GET /api/v1/sync/statusreadHow current the synced archive is for a marketplace.
POST /api/v1/sync/startreadSync a marketplace now, the dashboard's Sync button.
GET /api/v1/runsreadAutomation runs for a marketplace, newest activity first.
GET /api/v1/runs/:runIdreadOne run, the polling target for the runId a proposal returned.
GET /api/v1/runs/:runId/changesreadThe individual changes a run proposed, and what became of each.
GET /api/v1/changesreadChange history: what MerchDash wrote to Amazon, for one entity or the whole marketplace.
POST /api/v1/changeswritePropose a batch of bid, state, negative, campaign-setting and portfolio changes, for a human to approve, or to apply at once.
POST /api/v1/structureswritePropose new campaigns, ad groups, product ads, keywords and targeting clauses for a human to approve.
GET /api/v1/rulesreadThe marketplace's automation rules.
GET /api/v1/rules/:ruleIdreadOne automation rule.
POST /api/v1/rulesautomationCreate an automation rule.
POST /api/v1/rules/copyautomationCopy saved rules into other marketplaces of the same account.
PATCH /api/v1/rules/:ruleIdautomationEdit an automation rule: its script, name, schedule, mode, category, season, or whether it is on.
DELETE /api/v1/rules/:ruleIdautomationDelete an automation rule.
POST /api/v1/rules/:ruleId/runautomationRun an automation rule now, the same as pressing Run on the Automation page.
POST /api/v1/rules/:ruleId/run/cancelautomationTake a rule's run out of the queue before it starts.
GET /api/v1/rules/:ruleId/runreadThe progress and outcome of the rule's latest manual run.
POST /api/v1/rules/validateautomationCheck a rule script without saving or running it.
POST /api/v1/rules/previewautomationDry-run a script: what it would change right now, without saving it and without writing anything.
GET /api/v1/rules/preview/:jobIdreadThe progress and result of a dry run.
POST /api/v1/rules/preview/:jobId/cancelautomationStop a dry run that is still running.
GET /api/v1/categoriesreadThe marketplace's rule categories.
POST /api/v1/categoriesautomationCreate a rule category.
PATCH /api/v1/categories/:categoryIdautomationRename a rule category, move it into another one, or switch it on or off.
DELETE /api/v1/categories/:categoryIdautomationDelete a rule category.
GET /api/v1/runs/:runId/logreadA run's log: what its rule wrote with log(), and MerchDash's own notes.
POST /api/v1/runs/:runId/applyautomationApprove a pending review and write its changes to Amazon, the same as pressing Apply in the review queue.
POST /api/v1/runs/:runId/retry-failedautomationSend a finished run's failed changes to Amazon again, the Retry button in History.
POST /api/v1/runs/:runId/discardautomationTurn down a pending review, the same as pressing Discard in the review queue. Nothing is written to Amazon.
PATCH /api/v1/runs/:runId/changes/:changeIdautomationChange the bid or budget a pending change proposes, before approving it, the review table's own edit.

GET /api/v1/profiles

Every marketplace this account owns and has synced.

Scope: read

Not "the marketplaces currently ticked in the switcher", the switcher is a UI preference. This is every advertising profile the account owns and has synced at least once, which is exactly the set of profileIds the other endpoints accept.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending

FieldTypeMeaning
profileIdstringThe Amazon advertising profile id.
accountNamestring
nullable
Advertiser account name from the last Amazon discovery. Null if MerchDash has not discovered it.
countryCodestring
nullable
ISO country of the marketplace, when known.
marketplaceIdstring
nullable
Amazon marketplace id, when known.
regionstring
nullable
Amazon Ads API region (NA / EU / FE) this profile is read through.
lastSyncAttimestamp
nullable
When a sync last completed for this marketplace. Null until the first one finishes.

GET /api/v1/campaigns

Campaigns with their metrics for a window.

Scope: read

One row per campaign in the marketplace's snapshot, including campaigns that delivered nothing in the window, their metrics are zero rather than absent. Archived campaigns are included; every row carries state, so filter on it after reading.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only this campaign.
portfolioIdstring
optional
Only the campaigns in this portfolio (ids from GET /api/v1/portfolios).
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then campaignId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
Amazon ad product. Open enum: Amazon may add products.
statestring
nullable
ENABLED / PAUSED / ARCHIVED as of the last sync. Null if never observed.
adFormatstring
nullable
Sponsored Brands ad format of the row's ads: PRODUCT_COLLECTION, STORE_SPOTLIGHT, VIDEO or BRAND_VIDEO as Amazon names it, or MIXED when they differ (a campaign answers for all of its ads, a keyword or target for its ad group's). Null for Sponsored Products and Sponsored Display, and for a Sponsored Brands row whose ads have not been synced. Open set: Amazon may add formats.
campaignIdstringAmazon campaign id. Always a string, never a number, ids exceed the safe integer range.
namestring
nullable
targetingTypestring
nullable
MANUAL or AUTO for Sponsored Products.
budgetnumber
nullable
Daily budget in the marketplace currency.
budgetTypestring
nullable
suggestedBudgetnumber
nullable
Amazon's suggested daily budget as of the last sync, for an enabled Sponsored Products or Sponsored Brands campaign. Null when Amazon gave none, and for a campaign that is not enabled (the sync does not refresh it). POST /api/v1/recommendations/budgets asks Amazon now, with the missed-sales estimate.
percentTimeInBudgetnumber
nullable
Amazon's "Avg Time In Budget" over the campaign's last 7 delivery days, 0–1, as of the last sync. Null when Amazon's window is older than 14 days or it has no data, and for a campaign that is not enabled.
biddingStrategystring
nullable
placementTopPctnumber
nullable
Sponsored Products placement bid adjustment for top of search, in percent. Null means none (0%), and always null for SB/SD. Set with the set_placement_bid operation of POST /api/v1/changes.
placementProductPagePctnumber
nullable
The same for product pages.
placementRestOfSearchPctnumber
nullable
The same for the rest of search.
audienceBidsarray
nullable
Sponsored Products audience bid adjustments, as last synced: [{ audienceId, name, percent }] (name is null until the audience's name has been read). [] means none; null means not known, and is always null for SB/SD. Set with the set_audience_bid operation of POST /api/v1/changes; list the audiences a marketplace offers with GET /api/v1/audiences.
portfolioIdstring
nullable
portfolioNamestring
nullable
startDatestring
nullable
endDatestring
nullable
metricsobjectThe six report metrics summed over the window.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

GET /api/v1/portfolios

Portfolios with their budget caps.

Scope: read

One row per portfolio Amazon lists for the marketplace, including portfolios that hold no campaigns. No metric window: a portfolio has no report of its own, sum its campaigns from GET /api/v1/campaigns, which carry portfolioId. The budget cap is read as of the last sync; change it with the set_portfolio_budget operation of POST /api/v1/changes.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then portfolioId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
portfolioIdstringAmazon portfolio id, as a string.
namestring
nullable
statestring
nullable
ENABLED / PAUSED / ARCHIVED as of the last sync.
budgetPolicystring
nullable
NO_CAP, MONTHLY_RECURRING (the cap resets every calendar month) or DATE_RANGE (one total between the start and end date). Null when the portfolio has not been synced yet.
budgetAmountnumber
nullable
The cap, in budgetCurrency. Null with NO_CAP.
budgetCurrencystring
nullable
budgetStartDatestring
nullable
YYYY-MM-DD. The day the cap starts to apply.
budgetEndDatestring
nullable
YYYY-MM-DD. After it, a DATE_RANGE cap stops the portfolio's campaigns. Null means no end date.
inBudgetboolean
nullable
Amazon's own flag: false once the portfolio has spent its cap. Null when Amazon did not say.
campaignCountintegerCampaigns in this portfolio in MerchDash's snapshot, archived ones included.

GET /api/v1/videos

The Sponsored Brands videos in the account's Creative Asset Library, with their names.

Scope: read

One row per video in Amazon's Creative Asset Library for the marketplace. Archived and deleted videos are left out. The library is copied during a sync, at most once a day, and only for a marketplace that runs Sponsored Brands ads; a video uploaded through MerchDash is listed straight away. name is what a rule's addVideoAd(video: "…") looks a video up by. A freshly uploaded video reads PROCESSING until refresh=true asks Amazon again (a rule run checks for itself).

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
refreshenum
true · false
optional
Ask Amazon for the current status of up to 5 videos still processing, per Amazon account, before answering; spends one request of the key's write budget, like a live read. Defaults to false. Use it to wait for ready after an upload.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then assetId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
assetIdstringAmazon's asset id, without the :version_… suffix. Every version of one video is one row.
versionstring
nullable
The newest version MerchDash has seen, e.g. version_v1.
namestring
nullable
The video's name in the asset library.
statusstring
nullable
Amazon's status for the video, upper-cased, e.g. ACTIVE or PROCESSING.
readybooleanTrue when status is ACTIVE: Amazon has finished processing the video and an ad can use it.
durationSecondsnumber
nullable
Length of the video in seconds, when Amazon reported it.

POST /api/v1/videos/uploads

Start uploading a Sponsored Brands video into the account's Creative Asset Library: returns the URL to PUT the file to.

Scope: write

Step 1 of 3. MerchDash asks Amazon for a pre-signed upload URL; step 2 is yours: PUT the file's bytes to uploadUrl (with the contentType given, no Authorization header, the URL carries its own signature) before expiresAt; step 3 is POST /api/v1/videos/uploads/:uploadId/complete. The file goes straight to Amazon's storage and never through MerchDash. Nothing is in the library until step 3. Once registered, a rule finds the video by name: ad_group.addVideoAd(video: "<name>", asin: "B0…") builds a Sponsored Brands video ad from it. An assistant without a way to send a file (no shell) cannot do step 2; the owner can upload in Amazon Ads instead, which MerchDash copies with its daily sync.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
The Amazon account whose library gets the video, as returned by GET /api/v1/profiles. Not merged with a linked partner: a video belongs to one account, the one whose ad groups will use it.
filenamestring
required
The file's name, ending in .mp4 or .mov.
sizeinteger
required
The file's length in bytes. At most 500 MB, Amazon's limit for Sponsored Brands videos.
namestring
required
Up to 255 characters. The name rules look the video up by; one the library already has is refused, so two videos are never ambiguous.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
uploadIdstringPass it to the complete call. Valid for 55 minutes, on this server only: after a MerchDash restart, start again.
uploadUrlstringAmazon's pre-signed URL. PUT the file's bytes to it, nothing else.
methodstringAlways PUT.
contentTypestringThe Content-Type to send with the PUT, from the file's extension.
expiresAttimestampWhen the upload session ends.
namestringThe name the video will be registered under.

POST /api/v1/videos/uploads/:uploadId/complete

Register an uploaded video in the Creative Asset Library, step 3 after PUTting the file.

Scope: write

Amazon processes the video for about a minute: ready turns true (status ACTIVE) in GET /api/v1/videos?refresh=true, and only then can an ad use it. specFailures lists what Amazon's Sponsored Brands video checks flagged (aspect ratio, length, resolution); a video with any is unlikely to pass Amazon's ad review. Repeating the call for the same uploadId answers the first result again rather than registering twice. Amazon has no way to delete a library video. An unknown or expired uploadId (55 minutes, or a MerchDash restart) is 404: start again.

Headers

HeaderRequiredMeaning
Content-TypeoptionalThe body is optional. A body that is just {} is accepted whatever its Content-Type; any other: Must be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Parameters

ParameterTypeMeaning
uploadId (path)string
required
From POST /api/v1/videos/uploads.

Request body

FieldTypeMeaning
namestring
optional
Overrides the name given at the start. Defaults to it.
asinstring
optional
The product the video shows, an ASIN starting B0. Optional; addVideoAd(asin:) can name it instead.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
assetIdstring
versionstring
nullable
namestring
statusstring
nullable
Usually PROCESSING at first.
readybooleanTrue once Amazon has finished processing it.
specFailuresarrayAmazon's words for each Sponsored Brands video check the file failed. Empty when it passed.

GET /api/v1/images

The logos and custom images in an account's Creative Asset Library, by name.

Scope: read

What MerchDash holds of the image library. It is copied only when something asks for it, a rule's addSbAd(logo: "…"), the app, or refresh=true here, so it can be empty for an account that has images. refresh=true walks the library at Amazon first (spending one request of the key's write budget, like a live read). name is what addSbAd(logo: "<name>") looks a logo up by. Most Merch accounts have no logo: they have no Brand Registry.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon account, as returned by GET /api/v1/profiles. Not merged with a linked partner.
refreshenum
true · false
optional
Read the library from Amazon first. Defaults to false.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: name ascending, ignoring case, then assetId

FieldTypeMeaning
profileIdstring
assetIdstring
versionstring
nullable
namestring
nullable
kindenum
logo · image
logo for a brand logo, image for a custom image.
statusstring
nullable
Amazon's status, upper-cased, e.g. ACTIVE or PROCESSING.
readybooleanTrue when status is ACTIVE.
widthinteger
nullable
heightinteger
nullable

POST /api/v1/images/uploads

Start uploading a Sponsored Brands logo or custom image: returns the URL to PUT the file to.

Scope: write

The image twin of POST /api/v1/videos/uploads, the same three steps: start here, PUT the bytes to uploadUrl, then POST /api/v1/images/uploads/:uploadId/complete. A rule then uses a logo by name: ad_group.addSbAd(from: FIND_SB_AD("…"), logo: "<name>"). Amazon wants a logo of at least 400×400 pixels and a custom image of at least 1200×628; MerchDash cannot see the pixels here, so a smaller file is refused by Amazon later.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
The Amazon account whose library gets the image. Not merged with a linked partner.
filenamestring
required
The file's name, ending in .png, .jpg or .jpeg.
sizeinteger
required
The file's length in bytes. At most 5 MB.
namestring
required
Up to 255 characters. The name rules look the image up by; one the library already has is refused.
kindenum
logo · image
optional
logo (default) or image, a custom image for a product collection ad.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
uploadIdstringPass it to the complete call. Valid for 55 minutes, on this server only.
uploadUrlstringAmazon's pre-signed URL. PUT the file's bytes to it.
methodstringAlways PUT.
contentTypestringThe Content-Type to send with the PUT.
expiresAttimestamp
namestring
kindenum
logo · image

POST /api/v1/images/uploads/:uploadId/complete

Register an uploaded logo or image in the Creative Asset Library, step 3 after PUTting the file.

Scope: write

Listed in GET /api/v1/images at once; ready turns true when Amazon has processed it. Repeating the call for the same uploadId answers the first result again. An unknown or expired uploadId is 404: start again.

Headers

HeaderRequiredMeaning
Content-TypeoptionalThe body is optional. A body that is just {} is accepted whatever its Content-Type; any other: Must be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Parameters

ParameterTypeMeaning
uploadId (path)string
required
From POST /api/v1/images/uploads.

Request body

FieldTypeMeaning
namestring
optional
Overrides the name given at the start. Defaults to it.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
assetIdstring
versionstring
nullable
namestring
kindenum
logo · image
statusstring
nullable
readyboolean
widthinteger
nullable
heightinteger
nullable

GET /api/v1/stores

The account's Amazon Stores and their pages, the landing pages a Sponsored Brands ad may point to.

Scope: read

Asked of Amazon at request time (remembered for 30 minutes), so it spends one request of the key's write budget, like a live read. A page's name or url is what addSbAd(landingPage: "…") takes. Empty for an account without a store, which is most Merch accounts.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon account, as returned by GET /api/v1/profiles. Not merged with a linked partner.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: as Amazon lists them

FieldTypeMeaning
profileIdstring
storeNamestring
nullable
pagesarrayThe store's pages: { id, name, url }.

GET /api/v1/ad-groups

Ad groups with their metrics for a window.

Scope: read

One row per ad group in the snapshot. campaignId narrows the read to one campaign.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only ad groups in this campaign.
portfolioIdstring
optional
Only ad groups in the campaigns of this portfolio (ids from GET /api/v1/portfolios).
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then adGroupId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
Amazon ad product. Open enum: Amazon may add products.
statestring
nullable
ENABLED / PAUSED / ARCHIVED as of the last sync. Null if never observed.
adFormatstring
nullable
Sponsored Brands ad format of the row's ads: PRODUCT_COLLECTION, STORE_SPOTLIGHT, VIDEO or BRAND_VIDEO as Amazon names it, or MIXED when they differ (a campaign answers for all of its ads, a keyword or target for its ad group's). Null for Sponsored Products and Sponsored Display, and for a Sponsored Brands row whose ads have not been synced. Open set: Amazon may add formats.
adGroupIdstring
campaignIdstring
nullable
namestring
nullable
defaultBidnumber
nullable
The ad group's default bid, what a keyword or target with no bid of its own bids.
metricsobjectThe six report metrics summed over the window.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

GET /api/v1/keywords

Keywords with their metrics for a window.

Scope: read

Positive keywords only. Negative keywords are read from GET /api/v1/negative-keywords. A Sponsored Brands keyword is listed once MerchDash has proven it positive (it delivered, or Amazon confirmed it): Amazon's old SB export mixed unmarked negatives in, and those are left out.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only keywords in this campaign.
portfolioIdstring
optional
Only keywords in the campaigns of this portfolio (ids from GET /api/v1/portfolios).
adGroupIdstring
optional
Only keywords in this ad group.
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then keywordId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
Amazon ad product. Open enum: Amazon may add products.
statestring
nullable
ENABLED / PAUSED / ARCHIVED as of the last sync. Null if never observed.
adFormatstring
nullable
Sponsored Brands ad format of the row's ads: PRODUCT_COLLECTION, STORE_SPOTLIGHT, VIDEO or BRAND_VIDEO as Amazon names it, or MIXED when they differ (a campaign answers for all of its ads, a keyword or target for its ad group's). Null for Sponsored Products and Sponsored Display, and for a Sponsored Brands row whose ads have not been synced. Open set: Amazon may add formats.
keywordIdstring
campaignIdstring
nullable
adGroupIdstring
nullable
keywordTextstring
nullable
matchTypestring
nullable
EXACT / PHRASE / BROAD.
bidnumber
nullable
The keyword's own bid. Null means it has none and bids its ad group's defaultBid. Also null while MerchDash has not read the clause's bid yet (one seen only in reports); set_bid on such a clause is refused until the next sync reads it.
metricsobjectThe six report metrics summed over the window.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

GET /api/v1/targets

Targeting clauses with their metrics for a window.

Scope: read

Positive targeting clauses, product targets, categories, and an auto campaign's close-match / loose-match / substitutes / complements clauses. Negative targets are read from GET /api/v1/negative-targets. A Sponsored Brands clause is listed once MerchDash has proven it positive, as for keywords.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only targets in this campaign.
portfolioIdstring
optional
Only targets in the campaigns of this portfolio (ids from GET /api/v1/portfolios).
adGroupIdstring
optional
Only targets in this ad group.
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then targetId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
Amazon ad product. Open enum: Amazon may add products.
statestring
nullable
ENABLED / PAUSED / ARCHIVED as of the last sync. Null if never observed.
adFormatstring
nullable
Sponsored Brands ad format of the row's ads: PRODUCT_COLLECTION, STORE_SPOTLIGHT, VIDEO or BRAND_VIDEO as Amazon names it, or MIXED when they differ (a campaign answers for all of its ads, a keyword or target for its ad group's). Null for Sponsored Products and Sponsored Display, and for a Sponsored Brands row whose ads have not been synced. Open set: Amazon may add formats.
targetIdstring
campaignIdstring
nullable
adGroupIdstring
nullable
expressionstring
nullable
The targeting clause as Amazon stores it.
expressionTypestring
nullable
bidnumber
nullable
Null means the clause bids its ad group's defaultBid. Also null while MerchDash has not read the clause's bid yet (one seen only in reports); set_bid on such a clause is refused until the next sync reads it.
metricsobjectThe six report metrics summed over the window.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

GET /api/v1/asins

Advertising performance aggregated per ASIN.

Scope: read

An ASIN-LEVEL AGGREGATION, not a list of product ads. One row per advertised ASIN, summing every ad of it across every campaign and ad group in the marketplace. ads is how many distinct product ads contributed. To act on one ad, find its adId with GET /api/v1/product-ads?asin=… (or ?adGroupId=…).

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only the delivery of this campaign: each ASIN's metrics, ads and campaigns then describe that campaign alone.
portfolioIdstring
optional
Only the delivery of the campaigns in this portfolio (ids from GET /api/v1/portfolios), summed the same way.
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: asin ascending

FieldTypeMeaning
profileIdstringThe marketplace you asked for. An ASIN row can span both halves of a linked pair of Amazon accounts, the ASIN is the identity here, not the profile.
asinstring
adsintegerDistinct product ads of this ASIN that delivered in the window.
campaignsintegerDistinct campaigns this ASIN delivered in during the window.
metricsobjectThe six report metrics summed over the window.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

GET /api/v1/product-ads

Product ads (an ASIN/SKU in one ad group) with their metrics for a window.

Scope: read

One row per product ad in the snapshot, the adId that set_state with entityType: "productAd" needs. Sponsored Products and Sponsored Display only: Sponsored Brands ads are a different kind of entity and are not listed here. Archived ads are left out unless includeArchived=true. state is the ad's OWN state; whether it can deliver also depends on its ad group and campaign, which live answers. Amazon's Sponsored Display report does not name the ad, so an SD ad's metrics are its ad group's for its ASIN.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only ads in this campaign.
portfolioIdstring
optional
Only ads in the campaigns of this portfolio (ids from GET /api/v1/portfolios).
adGroupIdstring
optional
Only ads in this ad group.
asinstring
optional
Only ads of this ASIN, every ad group it is advertised in, so "pause this ASIN everywhere" is one read. Several ASINs, comma-separated (up to 50), are one read too: use that instead of one request per ASIN, which spends the read budget (120 a minute per key) fast.
includeArchivedenum
true · false
optional
Also list archived ads. Defaults to false.
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then adId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
Amazon ad product. Open enum: Amazon may add products.
statestring
nullable
ENABLED / PAUSED / ARCHIVED as of the last sync. Null if never observed.
adIdstring
campaignIdstring
nullable
adGroupIdstring
nullable
asinstring
nullable
skustring
nullable
Seller SKU. Null for vendors and when Amazon did not export one.
livebooleanTrue when the ad, its ad group and its campaign are all ENABLED (a level never synced counts as enabled), i.e. the ad can deliver.
metricsobjectThe six report metrics summed over the window.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

GET /api/v1/sb-ads

Sponsored Brands ads (creatives) with their metrics for a window.

Scope: read

One row per Sponsored Brands ad in the snapshot. An SB ad is a creative, a headline, a brand, a landing page and up to five ASINs, or a video, and Amazon reports its traffic per ad, not per ASIN, so metrics belong to the ad as a whole. Metrics come from Amazon's per-ad report, which MerchDash keeps for the last 60 days; an ad that did not deliver in the window has zeros. Archived ads are left out unless includeArchived=true.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only ads in this campaign.
adGroupIdstring
optional
Only ads in this ad group.
adFormatenum
VIDEO · PRODUCT_COLLECTION · BRAND_VIDEO · STORE_SPOTLIGHT
optional
Only ads of this format.
includeArchivedenum
true · false
optional
Also list archived ads. Defaults to false.
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then adId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
adIdstring
campaignIdstring
nullable
adGroupIdstring
nullable
namestring
nullable
statestring
nullable
ENABLED / PAUSED / ARCHIVED as of the last sync.
adFormatstring
nullable
VIDEO, PRODUCT_COLLECTION, BRAND_VIDEO or STORE_SPOTLIGHT. Open: Amazon may add formats.
headlinestring
nullable
brandNamestring
nullable
asinsarrayThe ASINs the creative shows, sorted.
servingStatusstring
nullable
Amazon's serving status, e.g. AD_POLICING_PENDING_REVIEW.
moderationStatusstring
nullable
PENDING, APPROVED or REJECTED, Amazon's ad review. Null when Amazon answered a status MerchDash has not seen.
landingPageTypestring
nullable
e.g. STORE, PRODUCT_LIST, DETAIL_PAGE.
landingPageUrlstring
nullable
metricsobjectThe six report metrics summed over the window.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

GET /api/v1/sb-purchased-products

What shoppers bought after Sponsored Brands ads, per purchased ASIN, for a window.

Scope: read

One row per (campaign, ad group, purchased ASIN, attribution type) with purchases in the window, from Amazon's Sponsored Brands purchased-product report (kept for the last 60 days). The purchased ASIN is not always one the ad showed: attributionType says Promoted for an advertised product and Brand Halo for another product of the same brand. Sales-side only, Amazon reports no impressions, clicks or cost here.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only this campaign.
asinstring
optional
Only purchases of this ASIN.
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then campaignId, adGroupId, purchasedAsin and attributionType ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
campaignIdstring
adGroupIdstring
nullable
Null when Amazon's row named no ad group.
purchasedAsinstring
attributionTypestring
nullable
Amazon's attribution, e.g. Promoted or Brand Halo. Null when Amazon left it out.
ordersintegerOrders within 14 days of an ad click.
unitsinteger
salesnumberIn the marketplace currency.
newToBrandOrdersintegerOf orders, those from shoppers who had not bought from the brand in the last 12 months.
newToBrandUnitsinteger
newToBrandSalesnumber

GET /api/v1/negative-keywords

Negative keywords at campaign and ad-group scope.

Scope: read

One row per negative keyword in the snapshot. Sponsored Products negatives are swept from Amazon at both scopes on every state sweep. Amazon offers no Sponsored Brands list, so SB negatives are read from the SB targets export instead, which only the full sweep (about every ten days) fetches: one added in the Amazon console shows up after the next full sweep, and one removed there is archived by it. Archived negatives are left out unless includeArchived=true. Remove one with the remove_negative_keyword operation of POST /api/v1/changes.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only negatives in this campaign (both scopes).
portfolioIdstring
optional
Only negatives in the campaigns of this portfolio (ids from GET /api/v1/portfolios).
adGroupIdstring
optional
Only negatives in this ad group.
keywordTextstring
optional
Only negatives with exactly this text, compared case-insensitively, check here before adding one, or find the id to remove.
matchTypeenum
NEGATIVE_EXACT · NEGATIVE_PHRASE
optional
Only negatives of this match type.
stateenum
ENABLED · PAUSED · ARCHIVED
optional
Only negatives in this state. When given, includeArchived is ignored.
includeArchivedenum
true · false
optional
Also list archived (removed) negatives. Defaults to false.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then negativeKeywordId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
Amazon ad product. Open enum: Amazon may add products.
statestring
nullable
ENABLED / PAUSED / ARCHIVED as of the last sync. Null if never observed.
negativeKeywordIdstring
campaignIdstring
nullable
adGroupIdstring
nullable
Null means campaign scope.
scopeenum
campaign · adGroup
Campaign scope is a different Amazon entity from an ad-group negative.
keywordTextstring
nullable
matchTypestring
nullable
NEGATIVE_EXACT / NEGATIVE_PHRASE.

GET /api/v1/negative-targets

Negative product targets (excluded ASINs and brands) at campaign and ad-group scope.

Scope: read

One row per negative targeting clause in the snapshot, with the same sweep coverage and Sponsored Brands timing as GET /api/v1/negative-keywords. asin is set for an excluded ASIN, brandId for an excluded brand, and both are null for any other clause. Archived clauses are left out unless includeArchived=true. Remove one with the remove_negative_target operation of POST /api/v1/changes.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only negatives in this campaign (both scopes).
portfolioIdstring
optional
Only negatives in the campaigns of this portfolio (ids from GET /api/v1/portfolios).
adGroupIdstring
optional
Only negatives in this ad group.
asinstring
optional
Only clauses excluding this ASIN (brand clauses never match).
stateenum
ENABLED · PAUSED · ARCHIVED
optional
Only negatives in this state. When given, includeArchived is ignored.
includeArchivedenum
true · false
optional
Also list archived (removed) negatives. Defaults to false.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then negativeTargetId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
Amazon ad product. Open enum: Amazon may add products.
statestring
nullable
ENABLED / PAUSED / ARCHIVED as of the last sync. Null if never observed.
negativeTargetIdstring
campaignIdstring
nullable
adGroupIdstring
nullable
Null means campaign scope (Sponsored Products auto campaigns only).
scopeenum
campaign · adGroup
asinstring
nullable
brandIdstring
nullable
The brand an excluded-brand clause names (as POST /api/v1/negative-brands/search returns it). Null for an ASIN clause.
expressionstring
nullable
The clause as Amazon stores it (JSON).

GET /api/v1/audiences

The audiences a marketplace's Sponsored Products campaigns can carry a bid adjustment for.

Scope: read

One row per audience Amazon offers for bid adjustments (its own, and the advertiser's Amazon Marketing Cloud ones), as last read. Served from MerchDash's stored copy and never calls Amazon, so a marketplace nothing has read audiences for yet lists none: a sync fills it. Use audienceId or name as the audience of the set_audience_bid operation.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then audienceId ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
audienceIdstring
namestring
nullable
Amazon's display name for the audience.
pathstring
nullable
Where Amazon files it, e.g. "Audience Category › Custom-built › Product".

GET /api/v1/placements

Metrics per campaign and placement for a window, Sponsored Products and Sponsored Brands.

Scope: read

One row per (campaign, placement) that delivered in the window. For Sponsored Products, the placements the bid adjustments on GET /api/v1/campaigns act on. Sponsored Brands placements are listed too, with adProduct saying which is which; they have no placementCode, because set_placement_bid changes Sponsored Products campaigns only. A campaign with no placement traffic in the window has no rows.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only this campaign.
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId ascending, then campaignId ascending, then placement ascending

FieldTypeMeaning
profileIdstringThe marketplace this row belongs to.
campaignIdstring
placementstringAmazon's label, e.g. "Top of Search on-Amazon".
adProductstringSPONSORED_PRODUCTS or SPONSORED_BRANDS.
placementCodestring
nullable
TOP / PRODUCT_PAGE / REST_OF_SEARCH, the placement value set_placement_bid takes. Null for a placement that has no adjustment, and for every Sponsored Brands row.
metricsobjectThe six report metrics summed over the window.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

POST /api/v1/recommendations/bids

Amazon's suggested bids for keywords and auto-targeting clauses in an existing Sponsored Products ad group.

Scope: read

A LIVE Amazon read: Amazon is asked at request time, through the marketplace's own connection and its own Amazon rate limit, so it is slower than a snapshot read and Amazon's answer may change from one call to the next. Nothing is written. Besides the read budget, each call spends one request of the key's write budget. Amazon's refusals come back in this API's own codes: a request Amazon rejects is validation, an id Amazon does not know (gone since the last sync) is not_found, Amazon throttling is rate_limited, Amazon being down or not answering within 30 seconds is temporarily_unavailable, and a connection Amazon no longer accepts is conflict (reconnect the account in MerchDash). Amazon answers per theme (CONVERSION_OPPORTUNITIES always, plus an event such as PRIME_DAY around one), each with a low, a medium and a high suggested bid per expression and, when it has them, the weekly clicks and orders similar products got at each of those bids.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
adGroupIdstring
required
A Sponsored Products ad group in the snapshot.
expressionsarray
required
Up to 100 { type, value? }. type is CLOSE_MATCH / LOOSE_MATCH / SUBSTITUTES / COMPLEMENTS (no value) or KEYWORD_EXACT_MATCH / KEYWORD_PHRASE_MATCH / KEYWORD_BROAD_MATCH with the keyword as value.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
campaignIdstring
adGroupIdstring
themesarray[{ theme, expressions: [{ type, value, suggestedBids: [low, medium, high] }], impact: { clicks: [{lower, upper}], orders: [{lower, upper}] } | null }]. Bids are in the marketplace currency.

POST /api/v1/recommendations/sb-bids

Amazon's suggested bids for keywords and product targets in a Sponsored Brands campaign.

Scope: read

A LIVE Amazon read: Amazon is asked at request time, through the marketplace's own connection and its own Amazon rate limit, so it is slower than a snapshot read and Amazon's answer may change from one call to the next. Nothing is written. Besides the read budget, each call spends one request of the key's write budget. Amazon's refusals come back in this API's own codes: a request Amazon rejects is validation, an id Amazon does not know (gone since the last sync) is not_found, Amazon throttling is rate_limited, Amazon being down or not answering within 30 seconds is temporarily_unavailable, and a connection Amazon no longer accepts is conflict (reconnect the account in MerchDash). One answer per keyword and per target sent, in the order sent: Amazon's suggested bid with the low and high end of its range, or error when Amazon had no suggestion for it. Bids depend on the ad format, so say adFormat when the campaign's ads are video.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
campaignIdstring
required
A Sponsored Brands campaign in the snapshot.
adFormatenum
PRODUCT_COLLECTION · VIDEO
optional
The ad format the bids are for. Amazon's default when left out.
keywordsarray
optional
[{ keywordText, matchType }], matchType EXACT / PHRASE / BROAD.
targetsarray
optional
[{ type, value }]: ASIN_SAME_AS with an ASIN, or ASIN_CATEGORY_SAME_AS with a category id. Up to 100 keywords and targets together, at least one.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
campaignIdstring
keywordsarray[{ keywordText, matchType, suggested, low, high, error }]. Bids are in the marketplace currency; error is null when Amazon suggested one.
targetsarray[{ type, value, suggested, low, high, error }].

POST /api/v1/recommendations/keywords

Amazon's ranked keyword suggestions, with suggested bids, for an ad group or a set of ASINs.

Scope: read

A LIVE Amazon read: Amazon is asked at request time, through the marketplace's own connection and its own Amazon rate limit, so it is slower than a snapshot read and Amazon's answer may change from one call to the next. Nothing is written. Besides the read budget, each call spends one request of the key's write budget. Amazon's refusals come back in this API's own codes: a request Amazon rejects is validation, an id Amazon does not know (gone since the last sync) is not_found, Amazon throttling is rate_limited, Amazon being down or not answering within 30 seconds is temporarily_unavailable, and a connection Amazon no longer accepts is conflict (reconnect the account in MerchDash). Send adGroupId for keywords that fit an existing Sponsored Products ad group, or asins for keywords that fit products you have not advertised yet, exactly one of the two.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
adGroupIdstring
optional
An existing Sponsored Products ad group.
asinsarray
optional
Up to 50 ASINs.
maxRecommendationsinteger
optional
1–200. Defaults to 100.
sortByenum
DEFAULT · CLICKS · CONVERSIONS
optional
Amazon's ranking. Defaults to DEFAULT.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
adGroupIdstring
nullable
keywordsarray[{ keyword, recId, searchTermImpressionRank, searchTermImpressionShare, bids: [{ matchType, rank, suggested, low, high }] }] in Amazon's order. The impression rank and share are the account's own over 30 days, null when it has not targeted the term.

POST /api/v1/recommendations/categories

The product categories Amazon recommends targeting for a set of ASINs.

Scope: read

A LIVE Amazon read: Amazon is asked at request time, through the marketplace's own connection and its own Amazon rate limit, so it is slower than a snapshot read and Amazon's answer may change from one call to the next. Nothing is written. Besides the read budget, each call spends one request of the key's write budget. Amazon's refusals come back in this API's own codes: a request Amazon rejects is validation, an id Amazon does not know (gone since the last sync) is not_found, Amazon throttling is rate_limited, Amazon being down or not answering within 30 seconds is temporarily_unavailable, and a connection Amazon no longer accepts is conflict (reconnect the account in MerchDash).

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
asinsarray
required
Up to 1,000 ASINs.
includeAncestorboolean
optional
Also return the parent categories of each recommendation, more categories, less relevant ones. Defaults to false.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
categoriesarray[{ categoryId, name, path, parentId, canBeTargeted }].

POST /api/v1/recommendations/products

The products Amazon suggests targeting for a set of your advertised ASINs (Sponsored Products product targeting).

Scope: read

A LIVE Amazon read: Amazon is asked at request time, through the marketplace's own connection and its own Amazon rate limit, so it is slower than a snapshot read and Amazon's answer may change from one call to the next. Nothing is written. Besides the read budget, each call spends one request of the key's write budget. Amazon's refusals come back in this API's own codes: a request Amazon rejects is validation, an id Amazon does not know (gone since the last sync) is not_found, Amazon throttling is rate_limited, Amazon being down or not answering within 30 seconds is temporarily_unavailable, and a connection Amazon no longer accepts is conflict (reconnect the account in MerchDash). Send the ASINs you advertise; Amazon answers with other products worth targeting with a product (ASIN) target, ranked in its own order, each with the themes that led it there. Only the first page of Amazon's answer is returned unless you page on with cursor. Send adGroupId to have each suggestion say whether that ad group already targets the product (read from MerchDash's snapshot of its targets, as a rule's alreadyTargeted is); without it alreadyTargeted is null. Page on until nextCursor is null; rank restarts at 1 on every page.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
asinsarray
required
Up to 50 ASINs you advertise.
maxRecommendationsinteger
optional
1–100. Defaults to 100.
adGroupIdstring
optional
A Sponsored Products ad group of this marketplace. Fills alreadyTargeted; an unknown one is 404, another ad product 400.
cursorstring
optional
The nextCursor of the previous answer, unchanged, to read the next page. Up to 2000 characters.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
adGroupIdstring
nullable
The ad group alreadyTargeted was read against; null when none was sent.
productsarray[{ asin, rank, themes, alreadyTargeted }] in Amazon's order, one row per suggested ASIN. themes are Amazon's own labels, possibly empty. alreadyTargeted is true or false when adGroupId was sent, otherwise null. rank counts within this page.
nextCursorstring
nullable
Pass as cursor for the next page; null when Amazon has no more.

POST /api/v1/recommendations/budgets

Amazon's suggested daily budget for campaigns, with what running out of budget cost them (Sponsored Products and Sponsored Brands).

Scope: read

A LIVE Amazon read: Amazon is asked at request time, through the marketplace's own connection and its own Amazon rate limit, so it is slower than a snapshot read and Amazon's answer may change from one call to the next. Nothing is written. Besides the read budget, each call spends one request of the key's write budget. Amazon's refusals come back in this API's own codes: a request Amazon rejects is validation, an id Amazon does not know (gone since the last sync) is not_found, Amazon throttling is rate_limited, Amazon being down or not answering within 30 seconds is temporarily_unavailable, and a connection Amazon no longer accepts is conflict (reconnect the account in MerchDash). Pairs with set_campaign_budget. Amazon reads the last 7 days the campaign delivered in, about 3 days behind, a long-dormant campaign answers for an old week, so check windowEnd. GET /api/v1/campaigns has the suggestion as of the last sync.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
campaignIdsarray
required
Up to 100 campaign ids of this marketplace, Sponsored Products or Sponsored Brands, as strings.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
campaignsarrayOne entry per campaign sent, in that order: { campaignId, adProduct, budget, suggestedBudget, percentTimeInBudget, windowStart, windowEnd, missedImpressions, missedClicks, missedSales, error }. budget is the current daily budget from the snapshot; percentTimeInBudget is 0–1 (the console's "Avg Time In Budget"), null when Amazon has no data; each missed* is { lower, upper } or null; error says why Amazon gave nothing for that campaign, else null.

POST /api/v1/negative-brands/search

Find brands by keyword, Amazon's ids for the brands a Sponsored Products negative can exclude.

Scope: read

A LIVE Amazon read: Amazon is asked at request time, through the marketplace's own connection and its own Amazon rate limit, so it is slower than a snapshot read and Amazon's answer may change from one call to the next. Nothing is written. Besides the read budget, each call spends one request of the key's write budget. Amazon's refusals come back in this API's own codes: a request Amazon rejects is validation, an id Amazon does not know (gone since the last sync) is not_found, Amazon throttling is rate_limited, Amazon being down or not answering within 30 seconds is temporarily_unavailable, and a connection Amazon no longer accepts is conflict (reconnect the account in MerchDash). Returns Amazon's brand ids, what an excluded-brand negative targets. Pass one as brandId of the add_negative_target operation of POST /api/v1/changes to exclude the brand, and match it against the brandId of GET /api/v1/negative-targets to see whether it already is.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
keywordstring
required
1–100 characters.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
brandsarray[{ brandId, name }].

POST /api/v1/eligibility

Whether ASINs can be advertised, and Amazon's reasons when they cannot.

Scope: read

A LIVE Amazon read: Amazon is asked at request time, through the marketplace's own connection and its own Amazon rate limit, so it is slower than a snapshot read and Amazon's answer may change from one call to the next. Nothing is written. Besides the read budget, each call spends one request of the key's write budget. Amazon's refusals come back in this API's own codes: a request Amazon rejects is validation, an id Amazon does not know (gone since the last sync) is not_found, Amazon throttling is rate_limited, Amazon being down or not answering within 30 seconds is temporarily_unavailable, and a connection Amazon no longer accepts is conflict (reconnect the account in MerchDash). Ask before creating product ads: an ineligible ASIN is refused by Amazon when the ad is created.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
asinsarray
required
Up to 50 ASINs, Amazon's limit for this check; send more as further requests.
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
optional
Which ad product to check. Defaults to SPONSORED_PRODUCTS.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
productsarray[{ asin, sku, overallStatus, eligible, reasons: [{ name, message, severity, helpUrl }] }]. overallStatus is ELIGIBLE / ELIGIBLE_WITH_WARNING / INELIGIBLE; eligible is true for ELIGIBLE and ELIGIBLE_WITH_WARNING and false otherwise, INELIGIBLE, or a status Amazon did not send or MerchDash does not know. An ASIN Amazon has no record of for this account (not sold by this marketplace's seller, or no longer in the catalog) does not fail the request: it comes back with overallStatus: null, eligible: false and a single reason named NOT_FOUND.

GET /api/v1/search-terms

Shopper search terms with their metrics for a window.

Scope: read

One row per (campaign, ad group, keyword, search term) as Amazon reported it. For a product-targeting campaign the "search term" may be an ASIN rather than a shopper query, that is Amazon's own shape.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Only search terms of this campaign.
portfolioIdstring
optional
Only search terms of the campaigns in this portfolio (ids from GET /api/v1/portfolios). Combined with campaignId, both must hold.
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: profileId, campaignId, adGroupId, keywordId, searchTerm, all ascending

FieldTypeMeaning
profileIdstring
adProductstring
campaignIdstring
adGroupIdstring
keywordIdstringThe keyword or target the term matched through.
searchTermstring
keywordstring
nullable
The keyword text or targeting clause it matched.
matchTypestring
nullable
metricsobjectThe six report metrics summed over the window.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

GET /api/v1/metrics/daily

Account totals for each day in a window.

Scope: read

One row per report day, summing every campaign in the marketplace, the same daily totals the MerchDash dashboard charts. This is the endpoint to ask "what did we spend on this day"; the entity reads above answer "what did this campaign do over this window", and summing a page of them is neither cheaper nor more correct. A day the archive holds nothing for is absent rather than zero, before the first sync covered it, no spend and no data look identical, and only GET /api/v1/sync/status can tell them apart. When the marketplace is one half of a linked pair the row is the sum of both, exactly as the dashboard shows it, so a row carries no profileId of its own. There is no paging: the whole window comes back in one response, which the 365-day window cap bounds at 365 rows.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
campaignIdstring
optional
Sum only this campaign. It narrows what each day totals; it never splits a day into several rows.
adProductenum
SPONSORED_PRODUCTS · SPONSORED_BRANDS · SPONSORED_DISPLAY
optional
Sum only this Amazon ad product.
startdate
optional
First day of the metric window, inclusive, as YYYY-MM-DD (UTC, the marketplace's own report days). Defaults to 29 days before end.
enddate
optional
Last day of the metric window, inclusive, as YYYY-MM-DD. Defaults to 2 days ago, because Amazon is still restating attribution for the days after that.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: date ascending

FieldTypeMeaning
datestringThe report day, YYYY-MM-DD, in the marketplace's own report calendar.
metricsobjectThe six report metrics summed over that one day.
metrics.impressionsintegerImpressions in the window.
metrics.clicksintegerClicks in the window.
metrics.costnumberAd spend in the window, in the marketplace currency.
metrics.ordersintegerAttributed orders (14-day) in the window.
metrics.unitsintegerAttributed units (14-day) in the window.
metrics.salesnumberAttributed sales (14-day) in the window, in the marketplace currency.

GET /api/v1/sync/status

How current the synced archive is for a marketplace.

Scope: read

The freshness of the data every read above answers from, and whether proposals are unlocked, they are refused with sync_incomplete until its first full backfill has completed, and again while any full sync (a full re-sync included) is queued or running.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
lastSyncAttimestamp
nullable
When a sync last completed. For a linked pair, the older of the two marketplaces' times (null while either has never synced), GET /api/v1/profiles gives each one's own.
initialSyncCompletebooleanTrue once the first full (95-day) backfill has completed and no full sync, a first backfill, a resumed one or a full re-sync, is queued or running. A sync that completes without being that backfill does not count, however much data the marketplace holds; after a first backfill that failed or was paused, its next sync runs the backfill instead. Computed over the marketplace and its linked partner. Each request checks its own set instead, a proposal its scope, an apply the run's own marketplace and those its changes touch, and a rule run or dry run the rule's marketplace and its linked partner, both of which it evaluates (a rule run writes to both; a dry run writes nothing), so this can read false once such a request would be accepted.
syncingbooleanTrue while a sync is running or queued right now.
firstSyncedDatestring
nullable
Oldest report day held, YYYY-MM-DD. For a linked pair, the value common to both marketplaces.
lastSyncedDatestring
nullable
Newest report day held, YYYY-MM-DD. For a linked pair, the value common to both marketplaces.
syncedDaysintegerHow many report days are held. For a linked pair, the value common to both marketplaces.
campaignsintegerCampaigns in the snapshot.

POST /api/v1/sync/start

Sync a marketplace now, the dashboard's Sync button.

Scope: read

Refreshes the last 7 days of reports and the current entities (a marketplace whose first backfill never completed runs that instead), on both accounts of a linked pair. Returns at once; poll GET /api/v1/sync/status until syncing is false. An account already syncing, or synced in the last 15 minutes (unless its first backfill is still owed, which has no cooldown), is not started, results says which; 429 rate_limited when all were recent. MerchDash's own writes reach the snapshot at once. Writes nothing to Amazon; starting one spends one request of the key's write budget.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
profileIdstring
required
The marketplace, as returned by GET /api/v1/profiles.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
profileIdstring
startedbooleanTrue when at least one sync was queued by this request.
resultsarrayOne entry per Amazon account of the marketplace: { profileId, result }, result one of started, already_syncing, recently_synced.

GET /api/v1/runs

Automation runs for a marketplace, newest activity first.

Scope: read

Every run MerchDash recorded for the marketplace, proposals made through this API and runs made by the account's own automation rules alike. trigger says which.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
statusenum
preview · running · applied · partial · failed · reverted · discarded
optional
Only runs in this public status. Omit for all. Internal bookkeeping states are never accepted or returned.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: most recent activity first, then runId, a run whose mode is review enters the list when it is approved, not when it was proposed

FieldTypeMeaning
runIdstring
profileIdstring
statusenum
preview · running · applied · partial · failed · reverted · discarded
Closed enum.
triggerstringapi, manual, schedule, …, what started the run.
modestring
nullable
How the rule or proposal that made the run is set up: review sends its changes to the review queue, auto writes them by itself; manual is a bulk edit made in the dashboard. It is that setting, not what this run did, a rule run started with an explicit apply or an auto-apply proposal whose hand-off failed can differ. Read status for what happened.
labelstring
nullable
The batch label for an API proposal, or the rule name for a rule run.
ruleIdstring
nullable
The automation rule that made the run (GET /api/v1/rules/{ruleId}); a deleted rule keeps its id. Null for an API proposal and for a dashboard bulk edit, neither has a rule.
apiKeyIdstring
nullable
Which key proposed it. Survives that key being revoked.
startedAttimestamp
nullable
finishedAttimestamp
nullable
countsobjectHow the run's own changes stand. Revert records are not counted.
counts.proposedintegerNot written yet. While the run is preview or partial they await approval. While it is running some may be being written and others left for approval (an apply of selected changes, or creates kept back for review), read the run again once it settles; an auto-applied run asks nobody.
counts.appliedinteger
counts.failedinteger
counts.revertedinteger
counts.discardedintegerNever written and never going to be: turned down, or left unwritten by a run that was stopped or failed.

GET /api/v1/runs/:runId

One run, the polling target for the runId a proposal returned.

Scope: read

The same object the list returns. An unknown id and a run belonging to another account answer identically with 404 not_found: telling them apart would describe somebody else's account.

Parameters

ParameterTypeMeaning
runId (path)string
required
The run id, as returned by POST /api/v1/changes.

Response

Single resource, { data: { … } }.

Fields: same as runs.list

GET /api/v1/runs/:runId/changes

The individual changes a run proposed, and what became of each.

Scope: read

One row per change the run itself proposed. The revert records a later revert writes are excluded: they belong to the revert, not to this run, and status: reverted on the original already says it happened.

Parameters

ParameterTypeMeaning
runId (path)string
required
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: changeId ascending

FieldTypeMeaning
changeIdstring
runIdstring
statusenum
proposed · applied · failed · reverted · discarded
Closed enum. proposed is not written yet, awaiting approval, or, while the run is running, possibly being written by it (read it again once the run settles); discarded was never written and never will be, turned down, or left unwritten by a run that was stopped or failed.
entityTypestring
nullable
campaign / adGroup / keyword / target / productAd / negativeKeyword / negativeTarget / portfolio.
entityIdstring
nullable
Null for a change that creates something, there is no id until it is applied.
entityNamestring
nullable
campaignIdstring
nullable
adGroupIdstring
nullable
fieldstring
nullable
What the change alters: bid, state, negative, budget, biddingStrategy, placement:<label>, name, portfolio (a campaign's, shown by name), portfolioBudget, …
beforeValstring
nullable
The value MerchDash read before proposing. Null for a create.
afterValstring
nullable
The value the change writes.
reasonstring
nullable
The caller's own note, shown to the human reviewing it.
errorstring
nullable
Why this change failed, when it did.
appliedAttimestamp
nullable
createdAttimestamp
nullable

GET /api/v1/changes

Change history: what MerchDash wrote to Amazon, for one entity or the whole marketplace.

Scope: read

Changes MerchDash wrote to Amazon, by rules, API proposals, bulk edits and reverts, newest first. Read it before changing a bid, so you do not undo a recent change or fight a rule. Pending and failed changes are in their run (GET /api/v1/runs); changes made in the Amazon console are not recorded.

Parameters

ParameterTypeMeaning
profileIdstring
required
The Amazon advertising profile (marketplace) to read, as returned by GET /api/v1/profiles. When this marketplace is one half of a linked pair of Amazon accounts, the read covers both, exactly as the MerchDash dashboard does; every row carries the profileId it actually came from.
entityIdstring
optional
Only changes to this entity (any id). Creates carry no entity id.
entityTypeenum
campaign · adGroup · keyword · target · productAd · negativeKeyword · negativeTarget · portfolio · sbAd · asin
optional
Only changes to this kind of entity.
campaignIdstring
optional
Only changes to this campaign and what is inside it.
fieldstring
optional
Only this field (bid, state, budget, …).
startdate
optional
First day of appliedAt, YYYY-MM-DD (UTC). Defaults to 29 days before end.
enddate
optional
Last day, inclusive. Defaults to today. At most 365 days.
limitinteger
optional
Rows per page, 1–500. Defaults to 100.
cursorstring
optional
An opaque cursor from a previous response's nextCursor. It encodes the endpoint and the filters it was issued for: reusing it with different filters is invalid_cursor rather than a silently wrong page. When start/end were left to their defaults, the cursor keeps the window the first page used, so paging across midnight UTC continues the same window. Paging is not a snapshot, rows synced between two pages may appear.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: appliedAt descending, then changeId descending

FieldTypeMeaning
changeIdstring
runIdstringThe run that wrote it (GET /api/v1/runs/:runId).
profileIdstring
kindenum
change · revert
revert is the write that undid an earlier change, named by revertOf.
statusenum
applied · reverted
reverted: written, then undone by the change revertedBy names.
entityTypestring
nullable
entityIdstring
nullable
entityNamestring
nullable
campaignIdstring
nullable
adGroupIdstring
nullable
fieldstring
nullable
As in GET /api/v1/runs/:runId/changes.
beforeValstring
nullable
afterValstring
nullable
reasonstring
nullable
appliedAttimestampWhen Amazon accepted it.
createdAttimestamp
nullable
When it was proposed.
revertOfstring
nullable
For a revert, the changeId it undid.
revertedBystring
nullable
For a reverted change, the revert's changeId.
triggerstring
nullable
What started the run: api, manual, schedule, …
ruleIdstring
nullable
The rule behind it; null for an API proposal or a bulk edit.
labelstring
nullable
The rule name or the proposal's label.

POST /api/v1/changes

Propose a batch of bid, state, negative, campaign-setting and portfolio changes, for a human to approve, or to apply at once.

Scope: write

Writes a run and returns immediately; the writing to Amazon, when there is any, happens in the background. On a review key, the default, and what every key is until its owner says otherwise, nothing reaches Amazon here at all: the proposal waits in MerchDash's review queue until a human applies or turns it down there, or a key with the automation scope does so through POST /api/v1/runs/:runId/apply or /discard. On an auto-apply key, or with "applyMode": "auto", MerchDash applies the batch itself as soon as it is accepted. Either way GET /api/v1/runs/:runId reports the outcome. No key can revert a run.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.
Idempotency-Keyrequired1–128 visible ASCII characters, unique per logical request. A retry with the same key and the same body returns the first call's response and creates nothing; the same key with a different body is 409 idempotency_conflict. Keys are remembered for 24 hours.

Request body

FieldTypeMeaning
profileIdstring
required
Every change in the batch must belong to this marketplace, counting its linked partner account, whose entities are found and written exactly like its own (each change goes to the account that owns the entity). A batch naming an entity of any other marketplace is refused whole.
labelstring
required
1–80 characters. What the review card is titled, the human deciding sees this and nothing else about who sent it.
changesarray
required
1–500 change objects, discriminated on operation. set_auto_clause_bids expands into several changes each, and a request whose expansion exceeds 500 is refused whole rather than truncated.
applyModeenum
review · auto
optional
What happens to the proposal. review queues it for a human, which is what a key does by default. auto writes it to Amazon as soon as it is accepted, with nobody in the loop, and is only allowed on a key whose owner has turned auto-apply on for it, on any other key it is 403 scope. Omit it to use whatever the key is set to. A key that CAN auto-apply may still send review for a batch that wants a second pair of eyes; the reverse is never possible.

Operation: set_bid

Set a keyword's or target's bid. Refused when the keyword or target, its ad group or its campaign is archived, Amazon takes no changes there.

FieldTypeMeaning
entityTypeenum
keyword · target
required
entityIdstring
required
Must exist in this marketplace's snapshot as a positive keyword or targeting clause. A negative's id is not one: bid and state changes to negatives go through their own operations.
bidnumber
required
In the marketplace currency, within Amazon's range for that marketplace and ad product (US: $0.02–$1,000; Sponsored Brands $0.10–$49, $0.25 minimum for video ads). A bid outside it is written at the limit and flagged as adjusted. A bid above the account's own maximum-bid setting is written at that maximum and flagged as adjusted, exactly as an automation rule's would be, except for a keyword or target that already bids above the maximum: it may keep any bid up to its current one, so it can come down gradually, but not rise.
reasonstring
optional
Up to 200 characters, shown to the reviewer. Display only.

Operation: set_state

Enable or pause an entity, a portfolio included, and a Sponsored Products negative keyword or negative target. Refused when the entity, its ad group or its campaign is archived, Amazon takes no changes there. A portfolio may have one state change waiting for approval at a time, a pending rename or budget change does not block it, and a negative one change (409 conflict).

FieldTypeMeaning
entityTypeenum
campaign · adGroup · keyword · target · productAd · portfolio · negativeKeyword · negativeTarget
required
entityIdstring
required
For a negative, its negativeKeywordId / negativeTargetId from GET /api/v1/negative-keywords or /negative-targets. A paused negative stops excluding its term but is not removed; to remove one use remove_negative_keyword / remove_negative_target.
stateenum
ENABLED · PAUSED
required
ARCHIVED is not offered: archiving is irreversible on Amazon and cannot be undone by a revert.
reasonstring
optional

Operation: set_auto_clause_bids

Set the bids of an auto campaign's four predefined targeting clauses, the same action as Actions → Adjust Auto Targeting Bid in the dashboard. This is the only operation that reads from Amazon while it compiles: an auto campaign's clauses appear in MerchDash's own snapshot only once they have delivered, so the clauses are enumerated live and the request expands into one target-bid change per clause it actually alters. Expect it to be slower than the other operations, and to answer 503 temporarily_unavailable when Amazon cannot be reached, no proposal is created in that case.

FieldTypeMeaning
campaignIdstring
required
An auto-targeting Sponsored Products campaign. Any other campaign is refused: nothing else has these clauses.
bidsobject
required
One bid per clause, keyed close-match, loose-match, substitutes, complements. A clause you omit, or set to null, is left alone. Same range and the same maximum-bid clamp as set_bid.
adGroupIdsarray
optional
Narrows the fill to these ad groups of the campaign, at most 125 of them. Omit it to fill every ad group in the campaign. An empty array is refused rather than read as "all".
emptyOnlyboolean
optional
Default true: only clauses with no bid of their own, the ones inheriting the ad group default, are filled. false overwrites existing clause bids too.
reasonstring
optional
Shown to the reviewer on every change this expands into. Omit it and each change explains itself (what the clause was bidding, or which default it was inheriting).

Operation: set_portfolio_budget

Set a portfolio's budget cap, the most all of its campaigns may spend together, including its type and dates. The cap is one object on Amazon, so it is recorded and reverted whole: History shows the cap before and after, and a revert restores the previous cap exactly. Because the whole cap is written, a portfolio may have one budget change waiting for approval at a time: while one is proposed (or being applied), another, this operation or remove_portfolio_budget_cap, is 409 conflict. If MerchDash has not yet read the portfolio's current cap (a portfolio synced before caps were, or created since the last sync), the change still applies but cannot be reverted, there is no previous cap to put back.

FieldTypeMeaning
portfolioIdstring
required
Must exist in this marketplace's snapshot (GET /api/v1/portfolios). An archived portfolio is refused: Amazon cannot change one.
amountnumber
required
The cap, above zero, in the portfolio's currency. Rounded to cents.
policyenum
MONTHLY_RECURRING · DATE_RANGE
optional
MONTHLY_RECURRING resets every calendar month; DATE_RANGE is one total from startDate to endDate, after which the portfolio's campaigns stop. Omit it to keep the portfolio's current policy, or, for a portfolio with no cap, to get MONTHLY_RECURRING. To remove a cap use remove_portfolio_budget_cap.
startDatedate
optional
YYYY-MM-DD. Required with DATE_RANGE unless the portfolio already has a date-range cap. Omitted, the current start date is kept while the policy stays the same, and dropped when it changes.
endDatedate
optional
YYYY-MM-DD, not before startDate. null removes the end date. Omitted, it is kept on the same terms as startDate.
reasonstring
optional

Operation: remove_portfolio_budget_cap

Take a portfolio's budget cap off, so its campaigns spend against their own daily budgets only. A revert puts the previous cap back. If MerchDash has not yet read the portfolio's current cap (a portfolio synced before caps were, or created since the last sync), the change still applies but cannot be reverted, there is no previous cap to put back.

FieldTypeMeaning
portfolioIdstring
required
reasonstring
optional

Operation: rename_portfolio

Rename a portfolio.

FieldTypeMeaning
portfolioIdstring
required
namestring
required
1–255 characters. Leading and trailing whitespace is trimmed; a line break, tab or other control character inside it is refused. A name another portfolio of the same Amazon account already has, an archived one does not count, (each half of a linked pair is checked on its own, one portfolio in each may carry the same name) (compared trimmed, case-folded and with inner whitespace collapsed, so two spaces between words count as one) is refused: portfolios are found by name, and two with one name are ambiguous to every rule that looks one up. So is a name another portfolio is being renamed to in a proposal still waiting for approval (409 conflict), and a second rename of a portfolio whose first is still waiting.
reasonstring
optional

Operation: add_negative_keyword

Add a negative keyword at campaign or ad-group scope. Sponsored Products and Sponsored Brands campaigns only, a Sponsored Display campaign is refused, as is an archived campaign or ad group.

FieldTypeMeaning
campaignIdstring
required
adGroupIdstring
optional
Omit for a campaign-wide negative. Present means ad-group scope.
keywordTextstring
required
1–80 characters. Leading and trailing whitespace is trimmed; a line break, tab or other control character inside it is refused. An ASIN is refused on a Sponsored Products auto campaign or a Sponsored Brands campaign, where only a negative product target (add_negative_target) can block a product.
matchTypeenum
NEGATIVE_EXACT · NEGATIVE_PHRASE
required
reasonstring
optional

Operation: add_negative_target

Add a negative product target, one ASIN, or a whole brand, at campaign or ad-group scope. Send exactly one of asin and brandId. Sponsored Products and Sponsored Brands campaigns only, a Sponsored Display campaign is refused, as is an archived campaign or ad group. An excluded brand is written as an ASIN_BRAND_SAME_AS clause; that write has not yet run against Amazon, so check the applied change in History the first time you use it.

FieldTypeMeaning
campaignIdstring
required
adGroupIdstring
optional
Omit for a campaign-wide negative, allowed on auto-targeting Sponsored Products campaigns, and on Sponsored Brands campaigns, where it is written into every ad group of the campaign. Present means ad-group scope.
asinstring
optional
A 10-character ASIN. Required unless brandId is sent; the two are exclusive.
brandIdstring
optional
A brand id from POST /api/v1/negative-brands/search, up to 40 characters. Required unless asin is sent.
reasonstring
optional

Operation: remove_negative_keyword

Remove (archive) a negative keyword at either scope. Reverting it from History creates it again with the same text, match type and scope; a negative that was paused when removed is not revertible, since the re-created one would be enabled. Removing a negative and adding the same one back in one batch is refused. A negative may have one change (pause, enable or removal) waiting for approval at a time: while one is pending in another proposal, this is 409 conflict.

FieldTypeMeaning
negativeKeywordIdstring
required
As returned by GET /api/v1/negative-keywords. An already-archived one is refused.
reasonstring
optional

Operation: remove_negative_target

Remove (archive) a negative product target at either scope. Reverting re-creates an excluded ASIN or brand; a negative that was paused when removed can be removed but not reverted. Removing a negative and adding the same one back in one batch is refused. A negative may have one change (pause, enable or removal) waiting for approval at a time: while one is pending in another proposal, this is 409 conflict.

FieldTypeMeaning
negativeTargetIdstring
required
As returned by GET /api/v1/negative-targets. An already-archived one is refused.
reasonstring
optional

Operation: set_placement_bid

Set a Sponsored Products campaign's bid adjustment for one placement (placement + percent) or for several at once (placements), what a rule's setPlacementBid() does. Placements you do not name and the bidding strategy are kept. One such change per campaign per batch: a second set_placement_bid or set_bidding_strategy for the same campaign is refused, so name every placement you want in one change. placements becomes one change per placement in the review, none depending on another (leave one out, or revert one, and the rest stand); a placement already at its value is skipped. And one waiting for approval at a time: while a placement or bidding-strategy change for the campaign (from another batch or a rule run) is still proposed, a new one is 409 conflict naming that run, retry once that run has been applied or turned down (one being applied now only needs to finish).

FieldTypeMeaning
campaignIdstring
required
placementenum
TOP · PRODUCT_PAGE · REST_OF_SEARCH
optional
With percent, for one placement. Send this or placements, one of the two is required.
percentinteger
optional
Whole percent, 0–900. 0 removes the adjustment.
placementsobject
optional
Several placements: {"TOP": 60, "PRODUCT_PAGE": 20, "REST_OF_SEARCH": 20}, any of the three, each a whole percent 0–900.
reasonstring
optional

Operation: set_audience_bid

Set a Sponsored Products campaign's bid adjustment for one audience, what a rule's setAudienceBid() does. Only that audience changes: the campaign's other audiences, placements and bidding strategy are kept as Amazon holds them when the change is written, so several audiences on one campaign can go in one batch (the same audience twice is refused). A percent of 0 removes the adjustment. Refused when the campaign is not Sponsored Products or is archived, when the adjustment already has that value, when the audience matches nothing the marketplace offers (or a name matches several, use the id), and when it would be the campaign's 11th (Amazon allows 10). A campaign may have one change to a given audience waiting for approval at a time: while one is proposed (from another batch or a rule run), a new one for the same audience is 409 conflict naming that run. Reverting puts the previous value back, or removes the adjustment if there was none. The Amazon request shape is taken from its OpenAPI spec and has not yet been confirmed against a live account.

FieldTypeMeaning
campaignIdstring
required
audiencestring
required
An audienceId or (part of) a name from GET /api/v1/audiences, case-insensitive.
percentinteger
required
Whole percent, 0–900. 0 removes the adjustment.
reasonstring
optional

Operation: set_campaign_budget

Set a campaign's daily budget, what a rule's setBudget() does on a campaign. Sponsored Products, Sponsored Brands and Sponsored Display. Refused when the campaign is archived, when its budget is not a daily one (a Sponsored Brands lifetime budget, Amazon cannot change a budget's type), and when the budget is already that amount. A campaign may have one budget change waiting for approval at a time: while one is proposed (from another batch or a rule run), a new one is 409 conflict naming that run, retry once that run has been applied or turned down (one being applied now only needs to finish). The proposed amount can be changed before it is applied with PATCH /api/v1/runs/:runId/changes/:changeId. Reverting puts the previous budget back.

FieldTypeMeaning
campaignIdstring
required
budgetnumber
required
In the marketplace currency, greater than 0 (0 or less is validation), rounded to the cent. Below Amazon's floor of 1 it is written at the floor and flagged as adjusted. Amazon's per-marketplace minimum and maximum apply when the change is written.
reasonstring
optional

Operation: set_bidding_strategy

Set a Sponsored Products campaign's bidding strategy (dynamic bids), what a rule's setBiddingStrategy() does. The placement bid adjustments are kept. A Sponsored Brands or Display campaign is refused (they have no such setting), as is an archived one and a strategy the campaign already has. It shares the campaign's one placement slot with set_placement_bid, because both write the whole placement map: one of the two per campaign per batch, and while either is waiting for approval for the campaign (from another batch or a rule run), a new one is 409 conflict naming that run. Reverting puts the previous strategy back, unless it was one MerchDash cannot set, such as Amazon's rule-based bidding.

FieldTypeMeaning
campaignIdstring
required
strategystring
required
"DYNAMIC BIDS - UP AND DOWN", "DYNAMIC BIDS - DOWN ONLY", "FIXED BIDS", or Amazon's own value (autoForSales, legacyForSales, manual, or AUTO_FOR_SALES, LEGACY_FOR_SALES, MANUAL). Case and spacing do not matter. Amazon's RULE_BASED is not offered: it needs settings this operation does not take.
reasonstring
optional

Operation: rename_campaign

Rename a campaign, what a rule's rename() does on a campaign. Sponsored Products, Sponsored Brands and Sponsored Display. Refused when the campaign is archived or already has that exact name. A campaign may have one rename waiting for approval at a time (409 conflict). Reverting puts the previous name back.

FieldTypeMeaning
campaignIdstring
required
namestring
required
1–128 characters, the limit POST /api/v1/structures applies to a campaign it creates. Leading and trailing whitespace is trimmed; a line break, tab or other control character inside it is refused. A name another campaign of the same Amazon account already has, an archived one does not count; each half of a linked pair is checked on its own, is refused, compared trimmed, case-folded and with inner whitespace collapsed, the way /structures and a rule's FIND_CAMPAIGN find a campaign by name. So are two renames to one name in a batch, and, 409 conflict, a name another campaign is being renamed to in a proposal still waiting for approval, or one a proposal (POST /api/v1/structures, or a rule) has reserved for a campaign it has not created yet.
reasonstring
optional

Operation: set_campaign_portfolio

Move a campaign into a portfolio, or take it out of the one it is in, what a rule's moveToPortfolio() does. Refused when the campaign is archived or already where it is asked to go, and when the portfolio is archived, unknown, or belongs to the other Amazon account of a linked marketplace (a campaign can only be in a portfolio of its own account). A campaign may have one move waiting for approval at a time (409 conflict), and none is accepted into a portfolio that a waiting proposal archives. Reverting moves the campaign back to the portfolio it was in; a campaign that was in none cannot be reverted out again.

FieldTypeMeaning
campaignIdstring
required
portfolioIdstring
required
nullable
From GET /api/v1/portfolios. null takes the campaign out of its portfolio, it must be sent: an absent or blank portfolioId is validation, never read as "out".
reasonstring
optional

Operation: archive_portfolio

Archive a portfolio, what a rule's portfolio.archive() does. PERMANENT on Amazon: an archived portfolio cannot be enabled, renamed, given a cap or have campaigns moved into it, by anyone, ever again, and this change has no revert. It is its own operation, never a set_state value, so it cannot be sent by accident. Refused when the portfolio is already archived; when the same batch also changes it (its state, cap or name) or moves a campaign into it; and, 409 conflict, while another proposal waiting for approval does either. Equally, while an archive waits for approval nothing else for that portfolio is accepted.

FieldTypeMeaning
portfolioIdstring
required
reasonstring
optional
Unknown fields are refused. Any field not named above is refused rather than ignored, including the internal fields of a stored change (apiCall, beforeVal, afterVal, status). The server derives all of those from its own snapshot, so a caller can never dictate what MerchDash will send to Amazon.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
runIdstringPoll GET /api/v1/runs/:runId for what a human decides.
countintegerHow many changes the run holds.
applyModeenum
review · auto
What this run will actually do, what the key allows, narrowed by whatever the request asked for. review means a human decides; auto means MerchDash is already writing it.
statusenum
preview · running · applied · partial · failed · reverted · discarded
The run's status at the instant it was created, which is preview either way, an auto-applied run leaves it within seconds, on its own. Branch on applyMode, not on this: with applyMode: "auto" never tell a user their changes are waiting for approval. Poll GET /api/v1/runs/:runId for what happened.

POST /api/v1/structures

Propose new campaigns, ad groups, product ads, keywords and targeting clauses for a human to approve.

Scope: write

Takes a nested graph and turns it into durable creation intents plus one run. On a review key, the default, nothing reaches Amazon here: the proposal is applied from the review queue (or by a key with the automation scope, through POST /api/v1/runs/:runId/apply), and only then is the structure built, parents before children. On an auto-apply key, or with "applyMode": "auto", MerchDash starts building it immediately, in that same dependency order. Because a create cannot be made idempotent by value, the id does not exist yet, each container is RESERVED under a stable identity at proposal time, so it is never built twice. A retry with the same Idempotency-Key replays the first answer. A second proposal naming a campaign, ad group or new portfolio that another run has already reserved is refused with 409 creation_conflict naming that run: retry once that run has been applied or turned down, or, for one Amazon is still creating, a little later, and an automation rule asking for it skips it as already pending.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.
Idempotency-Keyrequired1–128 visible ASCII characters, unique per logical request. A retry with the same key and the same body returns the first call's response and creates nothing; the same key with a different body is 409 idempotency_conflict. Keys are remembered for 24 hours.

What this endpoint will not do

  • Builds Sponsored Products structures. Sponsored Brands only as far as an ad group that ALREADY EXISTS (by adGroupId, or by name inside an existing SB campaign): keywords or targets, never both in one SB ad group, and not the other kind than it already holds, because Amazon keeps the two apart, and no ASINs (an SB ad advertises through its creative). A new SB ad group needs an ad first, which this API cannot supply, so it is refused, and Amazon refuses a keyword in an existing SB ad group that has no ad yet. Sponsored Display is refused (an SD ad group needs a tactic).
  • Auto-targeting campaigns take no keywords and no positive targeting clauses. Amazon creates their close match, loose match, substitutes and complements clauses with the ad group and lets nothing be added to them; only negatives are accepted there, through POST /api/v1/changes.
  • Created entities start ENABLED unless a node says "state": "PAUSED", and campaigns are created with no start date, so a proposal begins spending when the human applies it.
  • A campaign or ad group that already exists, named by id, or matched by the name you gave, is added to, never modified: its budget, bid, targeting and state are not changed here. alreadyPresent reports a container matched by name, with its id (one you named by id is not echoed back); it does not echo settings that were ignored. A request in which everything already exists proposes nothing and is refused with 400 validation ("Everything in this request already exists"), its bounded details listing the first of the matched entries in the alreadyPresent shape ({ kind, value, …Id }, never a { message, path } problem, which is how a client tells this refusal from any other validation), with no count, so a re-send of a structure that was already built is that refusal, not a second run.
  • At most 2000 campaigns and ad groups, and 20000 ASINs, keywords and targeting clauses, per request.
  • Character limits (label, names, keyword text, reason) count UTF-16 code units, as JavaScript's length does: an emoji or another character outside the Basic Multilingual Plane counts as two.

Request body

FieldTypeMeaning
profileIdstring
required
Every node in the graph belongs to this marketplace, counting its linked partner account: a campaign or ad group named by id, or matched by name, in the partner is added to there, and what is created under it is created in the partner. A new campaign (and a new portfolio) is created in the pair's primary account, whichever half profileId names.
labelstring
required
1–80 characters. What the review card is titled.
campaignsarray
optional
Campaigns to create, or existing campaigns to add ad groups to. Each entry names EITHER name OR campaignId, never both. A name the marketplace already has is ADDED TO, not created again, the same get-or-create an automation rule performs, so sending the same request twice builds one campaign. Shape of a new campaign: { name, budget, targeting: "manual" | "auto", state?, biddingStrategy?, portfolio? (a name) or portfolioId?, adGroups: [{ name, defaultBid?, asins?: ["B0…"], keywords?: [{ text, matchType: "EXACT" | "PHRASE" | "BROAD", bid? }], targets?: [{ asin | category, bid? }] }] }; of an existing one { campaignId, adGroups: [...] }. Any other field is refused by name, so a typo is a 400, never ignored.
adGroupsarray
optional
The single-shot form: ad groups that ALREADY exist, named by adGroupId, to add ASINs, keywords or targeting clauses to. This is how a script adds product ads, there is no stage-then-commit step, unlike the dashboard's paste box, and unlike that path nothing is written until a human approves it.
applyModeenum
review · auto
optional
What happens to the proposal. review queues it for a human, which is what a key does by default. auto builds the structure on Amazon as soon as the request is accepted, and is only allowed on a key whose owner has turned auto-apply on for it, on any other key it is 403 scope. Omit it to use whatever the key is set to. Worth a thought here in particular: a campaign or an ad group Amazon has created cannot be un-created by a revert.

Node: campaign (new)

FieldTypeMeaning
namestring
required
1–128 characters. Leading and trailing whitespace is trimmed; a line break, tab or other control character inside it is refused. Compared case-insensitively and whitespace-collapsed, exactly as Amazon collides names. A campaign of this name that already exists is used as-is; its targeting type must match the one asked for, since Amazon cannot change that after creation. A name an existing campaign is being renamed to (rename_campaign, or a rule) in a proposal still waiting for approval is 409 creation_conflict: retry once that run is decided, and once the rename is applied the request adds to that campaign.
budgetnumber
required
Daily budget in the marketplace currency, above zero (0 or less is validation). Below Amazon's floor of 1 it is raised to it; above the account's creation ceiling it is lowered to that and reported in adjustments.
targetingenum
manual · auto
required
Amazon cannot change a campaign's targeting type after it is created.
stateenum
ENABLED · PAUSED
optional
Defaults to ENABLED.
biddingStrategystring
optional
Amazon's value or the Campaign Manager label, "DYNAMIC BIDS - UP AND DOWN", "DYNAMIC BIDS - DOWN ONLY" (the default), or "FIXED BIDS".
portfoliostring
optional
A portfolio name, 1–255 characters (the limit rename_portfolio allows). Leading and trailing whitespace is trimmed; a line break, tab or other control character inside it is refused. Created if the account does not have one, and the campaign waits for it.
portfolioIdstring
optional
An existing portfolio, by the id GET /api/v1/portfolios lists, instead of portfolio (send one of the two). It must exist in this marketplace and not be archived, an id the account does not have is validation; to create a portfolio, name it with portfolio.
adGroupsarray
optional
Ad groups to get-or-create inside it by name. An existing adGroupId may also be used when the campaign name resolves to an existing campaign; if the campaign itself has to be created, its children must use name.

Node: campaign (existing)

FieldTypeMeaning
campaignIdstring
required
Must exist in this marketplace. Sponsored Products, or Sponsored Brands when every ad group under it already exists.
adGroupsarray
required
At least one ad group to create in it, or to add leaves to.

Node: adGroup (new)

FieldTypeMeaning
namestring
required
1–128 characters. Leading and trailing whitespace is trimmed; a line break, tab or other control character inside it is refused. Unique within its campaign, "Core terms" in two campaigns is two ad groups. One the campaign already holds is added to rather than created again, and then defaultBid is not needed.
defaultBidnumber
optional
The bid a keyword or clause with no bid of its own uses. In the marketplace currency, greater than 0 (0 or less is validation); Amazon's range for the marketplace and the account's own maximum-bid setting apply exactly as for set_bid (a bid outside them is written at the limit and flagged as adjusted). Required only when the ad group has to be created, an ad group of this name that the campaign already holds keeps its own default bid.
stateenum
ENABLED · PAUSED
optional
Defaults to ENABLED.
asinsarray
optional
ASINs to advertise, as 10-character strings.
keywordsarray
optional
targetsarray
optional

Node: adGroup (existing)

FieldTypeMeaning
adGroupIdstring
required
Must exist in this marketplace. At least one of asins/keywords/targets is required, an existing ad group's own settings are not changed here.
asinsarray
optional
keywordsarray
optional
targetsarray
optional

Node: keyword

FieldTypeMeaning
textstring
required
1–80 characters. Whitespace, tabs and line breaks included, collapses to single spaces; any other control character is refused. An ASIN is refused: bought as keyword text it is a literal string no shopper types, so it costs a write and never serves. Send it under targets.
matchTypeenum
EXACT · PHRASE · BROAD
required
bidnumber
optional
Omit to follow the ad group's default bid. Greater than 0 (0 or less is validation); Amazon's range for the marketplace and the account's own maximum-bid setting apply exactly as for set_bid (a bid outside them is written at the limit and flagged in adjustments).
stateenum
ENABLED · PAUSED
optional
reasonstring
optional
Up to 200 characters, shown to the reviewer. Display only.

Node: target

FieldTypeMeaning
asinstring
optional
A product target. Exactly one of asin or category.
categorystring
optional
An Amazon category id. Exactly one of asin or category.
bidnumber
optional
Omit to follow the ad group's default bid. Greater than 0 (0 or less is validation); Amazon's range for the marketplace and the account's own maximum-bid setting apply exactly as for set_bid (a bid outside them is written at the limit and flagged in adjustments).
stateenum
ENABLED · PAUSED
optional
reasonstring
optional
Up to 200 characters, shown to the reviewer. Display only. Targeting clauses are reviewed in batches; when a batch's clauses carry different reasons, its row shows the first as "<reason> (and N more)", N being the other clauses in that batch.
Unknown fields are refused. Any field not named above is refused rather than ignored, including every internal field of a stored change and of a creation intent (apiCall, desiredKey, specHash, intentId). The server derives all of those, so a caller can never dictate what MerchDash will send to Amazon or what identity it will reserve under.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
runIdstringPoll GET /api/v1/runs/:runId for what a human decides.
countintegerHow many change rows the run holds. Not the number of entities: an ad group's ASINs are batched into rows of at most 1,000, and its targeting clauses into rows per state (ENABLED / PAUSED) of at most 1,000.
intentsintegerHow many containers were reserved, portfolios, campaigns and ad groups.
applyModeenum
review · auto
What this run will actually do, what the key allows, narrowed by whatever the request asked for. review means a human decides; auto means MerchDash is already building it.
statusenum
preview · running · applied · partial · failed · reverted · discarded
The run's status at the instant it was created, which is preview either way, an auto-applied run leaves it within seconds, on its own. Branch on applyMode, not on this. Poll GET /api/v1/runs/:runId for what happened.
alreadyPresentarray
nullable
Up to the first 50 things the marketplace snapshot already held, so they were added to rather than proposed again. Absent when there were none. Each entry is { kind, value } plus the id it resolved to, adGroupId for asin, keyword, target and adGroup, campaignId for campaign, or portfolioId for portfolio.
alreadyPresentCountinteger
nullable
Total number of already-present containers and leaves, including entries omitted from the bounded alreadyPresent sample. Absent when there were none.
alreadyPresentTruncatedboolean
nullable
True when alreadyPresentCount is larger than the returned alreadyPresent sample. Absent when there were no already-present items.
adjustmentsarray
nullable
Values an account or Amazon ceiling moved, with the number that will actually be used. Absent when there were none. Each entry is { path, field, note }.

GET /api/v1/rules

The marketplace's automation rules.

Scope: read

Every automation rule saved for the marketplace, with its script. The same rules the Automation page lists. Rules belong to one marketplace: the same rule in two marketplaces is two rules.

Parameters

ParameterTypeMeaning
profileIdstring
required
The marketplace, as returned by GET /api/v1/profiles. Rules and categories belong to one marketplace each. Unlike the data reads, a linked pair of Amazon accounts is NOT merged here.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: the order the Automation page shows them in. Not paginated: nextCursor is always null.

FieldTypeMeaning
ruleIdstring
profileIdstring
namestring
codestringThe rule's script.
schedulestringSee the schedule field of POST /api/v1/rules. A rule saved long ago may carry an older value the scheduler still understands.
modeenum
review · auto
enabledbooleanWhether the schedule is on.
categoryIdstring
nullable
seasonEnabledboolean
startDatedate
nullable
endDatedate
nullable
createdAttimestamp
nullable
updatedAttimestamp
nullable
lastRunAttimestamp
nullable
When the rule last ran, by hand or on schedule.
lastRunIdstring
nullable
That run, for GET /api/v1/runs/:runId. Null when there is no run to follow: it never ran, or its last run left no readable record, a scheduled run that changed nothing and logged nothing (manual runs record even that) or failed before recording one, a run stopped while it was still evaluating, a review since discarded before any of it was applied (one applied in part first stays readable and named here), or a run hidden from you (lastRunAt still says when it ran). A manual run that fails before recording one changes neither field: they keep naming the run before it.

GET /api/v1/rules/:ruleId

One automation rule.

Scope: read

The same object the list returns. An unknown id and a rule belonging to another account both answer 404 not_found.

Parameters

ParameterTypeMeaning
ruleId (path)string
required
As returned by GET /api/v1/rules.

Response

Single resource, { data: { … } }.

Fields: same as rules.list

POST /api/v1/rules

Create an automation rule.

Scope: automation

Saves a rule the same way the Automation page's editor does. The script is checked first, and a script that would not run is refused with validation and the line it failed on. A rule name the marketplace already uses is refused with 409 conflict, and details carries the existing rule's id. Send an Idempotency-Key when retrying after a timeout so the exact first response is replayed.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.
Idempotency-KeyoptionalRecommended for API-key callers. The same key and request replay the first response; reusing it for different rule contents is 409 idempotency_conflict.

Request body

FieldTypeMeaning
profileIdstring
required
The marketplace the rule belongs to.
namestring
required
1–120 characters, unique within the marketplace (compared case-insensitively, ignoring surrounding spaces and with inner whitespace collapsed, the way RULE("…") finds a rule).
codestring
required
The rule's script in the MerchDash automation language (see /docs/language), at most 200,000 characters. Checked before it is saved: a script that would not run is refused with validation, and details names the line.
schedulestring
optional
When the rule runs by itself: manual, every12h, every24h, weekly, biweekly, monthly, or weekday:<sunday…saturday> or date:YYYY-MM-DD. manual means only when somebody runs it. Defaults to manual on create.
modeenum
review · auto
optional
review puts the changes a run proposes in the review queue. auto writes them to Amazon as soon as the rule runs, with nobody in the loop. Defaults to review on create.
enabledboolean
optional
Whether the schedule is on. A manual rule cannot be enabled, because it has no schedule to turn on, and changing a rule's schedule to manual switches it off. Defaults to false on create, so a new rule never runs by itself until you say so.
categoryIdstring
optional
nullable
A category of the same marketplace, or null for none.
seasonEnabledboolean
optional
Limits scheduled runs to the dates between startDate and endDate.
startDatedate
optional
nullable
YYYY-MM-DD. First day of the season.
endDatedate
optional
nullable
YYYY-MM-DD, not before startDate. Last day of the season.
Unknown fields are refused. Any field not named above is refused rather than ignored. Run history, lastRun* and timestamps are written by MerchDash, never by a caller.

Response

Single resource, { data: { … } }.

Fields: the created rule, same as rules.list

POST /api/v1/rules/copy

Copy saved rules into other marketplaces of the same account.

Scope: automation

The dashboard's copy dialog. Only the rule travels, its script, schedule, mode and season, never its runs or History. A name a target marketplace already uses (compared trimmed, whitespace-collapsed and case-insensitively) is skipped and listed in skipped, never duplicated. A copy keeps the source rule's mode, so an auto rule is copied as auto. Copies start switched off unless activate is true, and even then a rule with no schedule or a script that would not run stays off. A schedule only an operator may set is copied as manual (so that copy stays off too). An unknown rule id is 404; a marketplace this account does not own is 404.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.
Idempotency-KeyoptionalRecommended for API-key callers. The same key and request replay the first response instead of copying again.

Request body

FieldTypeMeaning
profileIdstring
required
The marketplace the rules are copied FROM.
ruleIdsarray
required
Rules of that marketplace to copy, at most 100.
targetProfileIdsarray
required
Marketplaces to copy into, at most 50. The source marketplace itself is ignored.
activateboolean
optional
Switch the copies on. Defaults to false.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
resultsarrayOne entry per target: { profileId, copied, skipped: [rule name], created: [{ sourceRuleId, ruleId }] }.
copiedintegerCopies made, across all targets.
skippedintegerCopies skipped because the name was taken.

PATCH /api/v1/rules/:ruleId

Edit an automation rule: its script, name, schedule, mode, category, season, or whether it is on.

Scope: automation

Only the fields you send change. A new script is checked the same way a create checks it. Turning a rule on also re-checks its current script, so an old rule that no longer runs cannot be switched on. The edit applies from the rule's next run; a run already in flight keeps the script it started with. A run still queued for a slot picks up a new script when it starts, but whether it writes to Amazon (mode, or the apply it was asked with) was settled when it was accepted.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Parameters

ParameterTypeMeaning
ruleId (path)string
required
As returned by GET /api/v1/rules.

Request body

FieldTypeMeaning
namestring
optional
1–120 characters, unique within the marketplace (compared case-insensitively, ignoring surrounding spaces and with inner whitespace collapsed, the way RULE("…") finds a rule).
codestring
optional
The rule's script in the MerchDash automation language (see /docs/language), at most 200,000 characters. Checked before it is saved: a script that would not run is refused with validation, and details names the line.
schedulestring
optional
When the rule runs by itself: manual, every12h, every24h, weekly, biweekly, monthly, or weekday:<sunday…saturday> or date:YYYY-MM-DD. manual means only when somebody runs it. Defaults to manual on create.
modeenum
review · auto
optional
review puts the changes a run proposes in the review queue. auto writes them to Amazon as soon as the rule runs, with nobody in the loop. Defaults to review on create.
enabledboolean
optional
Whether the schedule is on. A manual rule cannot be enabled, because it has no schedule to turn on, and changing a rule's schedule to manual switches it off. Defaults to false on create, so a new rule never runs by itself until you say so.
categoryIdstring
optional
nullable
A category of the same marketplace, or null for none.
seasonEnabledboolean
optional
Limits scheduled runs to the dates between startDate and endDate.
startDatedate
optional
nullable
YYYY-MM-DD. First day of the season.
endDatedate
optional
nullable
YYYY-MM-DD, not before startDate. Last day of the season.
Unknown fields are refused. Any field not named above is refused rather than ignored, profileId included: a rule cannot move to another marketplace. An empty body is refused.

Response

Single resource, { data: { … } }.

Fields: the updated rule, same as rules.list

DELETE /api/v1/rules/:ruleId

Delete an automation rule.

Scope: automation

Stops a run of the rule that is waiting in the queue or in flight, its own evaluation and the writes it makes by itself; an apply of one of its reviews that a person approved is that person's and carries on, and removes the rule. Its runs and change history are kept, so every change it ever made stays readable and revertible in History. Pending reviews from the deleted rule leave the review queue; their run and proposed rows remain retained as audit data, but there is no longer a rule card from which to approve them, and POST /api/v1/runs/:runId/apply refuses them with 409 conflict (their creation reservations were released), discard them instead.

Parameters

ParameterTypeMeaning
ruleId (path)string
required
As returned by GET /api/v1/rules.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
ruleIdstring
deletedbooleanAlways true.

POST /api/v1/rules/:ruleId/run

Run an automation rule now, the same as pressing Run on the Automation page.

Scope: automation

Starts the run in the background and returns immediately. Poll GET /api/v1/rules/:ruleId/run until status is no longer queued or running, then follow its runId. A rule in review mode proposes its changes, and they wait in the review queue; approve them with POST /api/v1/runs/:runId/apply. A rule in auto mode writes its changes to Amazon itself. Asking again while the rule is already queued or running attaches to that run and does not start a second one, except a run in the other mode, or one MerchDash is still finishing after an update or an interruption, which is 409 run_in_progress. Refused with sync_incomplete until the rule's marketplace, and its linked partner, which the run also evaluates and writes, has completed its first full backfill, and while a full sync (a full re-sync included) is queued or running in either; that gate is checked first, so during a full sync asking again under a new Idempotency-Key, or from a dashboard session, which sends none, is sync_incomplete even while the rule is queued or running (a retry with the same key still replays; or follow the run through GET /api/v1/rules/:ruleId/run). During a MerchDash deploy it is refused with 503 restarting before anything starts, so it is safe to send again.

Headers

HeaderRequiredMeaning
Content-TypeoptionalThe body is optional. A body that is just {} is accepted whatever its Content-Type; any other: Must be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.
Idempotency-KeyrequiredRequired for API-key callers; ignored for dashboard sessions. A retry with the same key reattaches to the original start or returns its retained outcome instead of running the rule again.

Parameters

ParameterTypeMeaning
ruleId (path)string
required
As returned by GET /api/v1/rules.

Request body

FieldTypeMeaning
applyboolean
optional
Overrides the rule's own mode for this one run. false only proposes, even on an auto rule. true writes to Amazon straight away, even on a review rule. Omit it to follow the rule's mode.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

Fields: same as rules.runStatus

POST /api/v1/rules/:ruleId/run/cancel

Take a rule's run out of the queue before it starts.

Scope: automation

Only a run still WAITING for a run slot is removed, including one a MerchDash update set aside to start again (GET /api/v1/rules/:ruleId/run reads it queued). A run that has already started is NOT stopped, it is writing to the live Amazon account, and abandoning it halfway is an operator decision, and running says so. After a cancel, retrying POST /api/v1/rules/:ruleId/run with the same Idempotency-Key reports the cancelled run (status: "failed" with the reason in error) instead of starting it; a new key starts a new run. A cancelled apply run gives back the auto-apply token its start spent.

Headers

HeaderRequiredMeaning
Content-TypeoptionalNot checked. A body, if sent, must be an empty JSON object, read as UTF-8, one that is not valid UTF-8, or holds a NUL or an unpaired surrogate, is validation.

Parameters

ParameterTypeMeaning
ruleId (path)string
required
As returned by GET /api/v1/rules.

Request body

Unknown fields are refused. The body must be an empty JSON object.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
ruleIdstring
removedbooleanTrue when a queued run was taken out of the queue.
runningbooleanTrue when nothing was removed because the run has already started.

GET /api/v1/rules/:ruleId/run

The progress and outcome of the rule's latest manual run.

Scope: read

The polling target after POST /api/v1/rules/:ruleId/run. MerchDash keeps a finished run's outcome here for about 15 minutes. A live run remains visible across replicas and restarts through its durable execution marker. After the retained outcome expires, status is idle and runId is the rule's last recorded run, which GET /api/v1/runs/:runId still answers. Polling never uses up the result, so two callers polling the same rule both see it.

Parameters

ParameterTypeMeaning
ruleId (path)string
required
As returned by GET /api/v1/rules.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
ruleIdstring
statusenum
idle · queued · running · done · failed
queued: waiting for one of the account's run slots. running: evaluating or applying. done: finished, and runId says what it did. failed: the run did not finish, and error says why. idle: nothing is being tracked for this rule right now. Closed enum.
runIdstring
nullable
The run this produced, once it is done (or failed with a run to show), null there too when that run is hidden from you: it finished, with no id to follow. When idle, the rule's last recorded run, null when it has never run, or its last run left no readable record (see lastRunId on the rule). Read it with GET /api/v1/runs/:runId.
messagestring
nullable
Progress while queued or running ("Applying change 12 of 240…"). Display only: never parse it.
errorstring
nullable
Why a failed run did not finish.

POST /api/v1/rules/validate

Check a rule script without saving or running it.

Scope: automation

The same check the rule editor runs as you type, and the one POST /api/v1/rules and PATCH run before saving. A script that fails is still answered 200, with valid: false, because asking whether a script is valid is not a bad request. The language is described in /docs/language.md.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Request body

FieldTypeMeaning
codestring
required
The script, at most 200,000 characters.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
validboolean
errorstring
nullable
Why the script would not run. Null when it is valid.
lineinteger
nullable
The line the problem is on, when the check can name one.

POST /api/v1/rules/preview

Dry-run a script: what it would change right now, without saving it and without writing anything.

Scope: automation

The rule editor's Dry run. The script is evaluated against the marketplace's synced data, and each change it proposes is checked against Amazon's current state, so a change that would do nothing is left out. Nothing is saved and nothing is written to Amazon. It runs in the background: poll GET /api/v1/rules/preview/:jobId for the result, usually within seconds and on a large account within minutes. A script that would not run is refused with validation before anything starts. Refused with sync_incomplete until the marketplace and its linked partner (both evaluated) have completed their first full backfill, and while a full sync (a full re-sync included) is queued or running in either, and with 503 restarting during a MerchDash deploy. Send an Idempotency-Key when retrying after a timeout so the first job id is replayed instead of starting the same dry-run twice.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.
Idempotency-KeyoptionalRecommended for API-key callers. The same key and request replay the first job id; reusing it for different preview contents is 409 idempotency_conflict.

Request body

FieldTypeMeaning
profileIdstring
required
The marketplace to evaluate against.
codestring
required
The script to try.
ruleIdstring
optional
A saved rule of the same marketplace this script belongs to, usually an edited version of it. Cool-downs that count "this rule"'s own changes (DAYS_SINCE_CHANGE("bid", "this rule")) then read that rule's history, as the real run would. Without it, the script is tried as a new rule that has never changed anything.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
jobIdstringPoll GET /api/v1/rules/preview/:jobId.
statusenum
running

GET /api/v1/rules/preview/:jobId

The progress and result of a dry run.

Scope: read

A result is kept for at least 24 hours after it finishes, and until then every poll returns it from any application replica. A worker restart cancels its running dry-runs, while their durable status remains available. After the retention window the job is 404 not_found and has to be started again with a new Idempotency-Key.

Parameters

ParameterTypeMeaning
jobId (path)string
required
As returned by POST /api/v1/rules/preview.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
jobIdstring
statusenum
running · done · failed · cancelled
running until the dry run ends. done: result holds the answer. failed: the script failed while it ran (a division by zero, a time limit), and error says why; result still carries its log. A dry run that could not run at all is also failed: result is null and error says why. cancelled: MerchDash stopped it, usually for a deploy; start it again. Closed enum.
messagestring
nullable
Progress while running. Display only: never parse it.
errorstring
nullable
resultobject
nullable
Null while running.
result.proposedintegerHow many changes the rule would make.
result.impactobjectHow much of the account those changes touch.
result.impact.campaignsinteger
result.impact.adGroupsinteger
result.impact.targetingsintegerKeywords, targets and negatives.
result.impact.approximatebooleanTrue when a count stopped at its ceiling and is a lower bound.
result.changesarrayThe first 200 (by default) changes, each { entityType, entityId, entityName, campaignId, campaignName, adGroupId, adGroupName, field, beforeVal, afterVal, reason }, the same fields GET /api/v1/runs/:runId/changes uses, plus the two names.
result.sampledbooleanTrue when changes is only the first part of proposed.
result.truncatedbooleanTrue when the rule hit its own change cap (# MAX CHANGES) and stopped early, so later blocks never ran.
result.logstringWhat the rule wrote with log(), plus MerchDash's notes on what it skipped and why. The first place to look when a rule proposes nothing.

POST /api/v1/rules/preview/:jobId/cancel

Stop a dry run that is still running.

Scope: automation

Cancellation is cooperative: the job stops at its next safe checkpoint. Poll the ordinary preview status endpoint until it reports cancelled. A job that has expired or belongs to another account is 404.

Headers

HeaderRequiredMeaning
Content-TypeoptionalNot checked. A body, if sent, must be an empty JSON object, read as UTF-8, one that is not valid UTF-8, or holds a NUL or an unpaired surrogate, is validation.

Parameters

ParameterTypeMeaning
jobId (path)string
required
As returned by POST /api/v1/rules/preview.

Request body

Unknown fields are refused. The body must be an empty JSON object.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
jobIdstring
statusenum
cancelling · done · failed · cancelled

GET /api/v1/categories

The marketplace's rule categories.

Scope: read

The named groups rules are sorted into on the Automation page. A category that is switched off stops the scheduled runs of every rule inside it, and inside every category nested in it, without changing each rule's own enabled. parentId gives the nesting.

Parameters

ParameterTypeMeaning
profileIdstring
required
The marketplace, as returned by GET /api/v1/profiles. Rules and categories belong to one marketplace each. Unlike the data reads, a linked pair of Amazon accounts is NOT merged here.

Response

Collection, { data: [ … ], nextCursor }, and nextCursor is null on the last page.

Order: the order the Automation page shows them in. Not paginated: nextCursor is always null.

FieldTypeMeaning
categoryIdstring
profileIdstring
namestring
enabledbooleanThe category's own switch. A category nested inside an off one is paused too while this stays true.
parentIdstring
nullable
The category this one sits inside, or null at the top level.
createdAttimestamp
nullable
updatedAttimestamp
nullable

POST /api/v1/categories

Create a rule category.

Scope: automation

The new category goes to the top of the Automation page. A name the marketplace already uses is refused with 409 conflict, and details carries the existing category's id. Put rules in it with categoryId on POST or PATCH /api/v1/rules. Send an Idempotency-Key when retrying after a timeout.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.
Idempotency-KeyoptionalRecommended for API-key callers. The same key and request replay the first response; reusing it for different category contents is 409 idempotency_conflict.

Request body

FieldTypeMeaning
profileIdstring
required
The marketplace the category belongs to.
namestring
required
1–60 characters, unique within the marketplace.
enabledboolean
optional
Off stops the scheduled runs of every rule in the category and in every category nested inside it. Defaults to true on create.
parentIdstring
optional
nullable
The category this one sits inside, of the same marketplace, or null for the top level (the default on create). A category can be nested up to 4 levels deep and never inside itself or one of its own sub-categories; a parent that breaks either rule is refused with 400 validation.
Unknown fields are refused. Any field not named above is refused rather than ignored.

Response

Single resource, { data: { … } }.

Fields: the created category, same as categories.list

PATCH /api/v1/categories/:categoryId

Rename a rule category, move it into another one, or switch it on or off.

Scope: automation

Only the fields you send change. Switching a category off stops its rules' scheduled runs, and those of the categories nested in it, but a rule can still be run by hand. Send parentId: null to take a category out of its parent.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Parameters

ParameterTypeMeaning
categoryId (path)string
required
As returned by GET /api/v1/categories.

Request body

FieldTypeMeaning
namestring
optional
1–60 characters, unique within the marketplace.
enabledboolean
optional
Off stops the scheduled runs of every rule in the category and in every category nested inside it. Defaults to true on create.
parentIdstring
optional
nullable
The category this one sits inside, of the same marketplace, or null for the top level (the default on create). A category can be nested up to 4 levels deep and never inside itself or one of its own sub-categories; a parent that breaks either rule is refused with 400 validation.
Unknown fields are refused. Any field not named above is refused rather than ignored. An empty body is refused.

Response

Single resource, { data: { … } }.

Fields: the updated category, same as categories.list

DELETE /api/v1/categories/:categoryId

Delete a rule category.

Scope: automation

Only the category is deleted. Its rules are kept, become uncategorized, and keep their own schedule and enabled. So a rule that was held back only because its category was off starts running on schedule again. Categories nested in it move up to its own parent.

Parameters

ParameterTypeMeaning
categoryId (path)string
required
As returned by GET /api/v1/categories.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
categoryIdstring
deletedbooleanAlways true.

GET /api/v1/runs/:runId/log

A run's log: what its rule wrote with log(), and MerchDash's own notes.

Scope: read

The same text as the Run log in the dashboard. It holds the lines the rule wrote with log() (at most 200) and MerchDash's notes about the run: entities it skipped and why, a change cap it hit, a time limit. When a rule proposes nothing, this usually says why. Runs the API proposed have no log of their own: theirs is an empty string, or only MerchDash's notes on finishing one after a restart (for example "[recovered automatically after restart]"). Do not use an empty log to tell API runs apart, use trigger.

Parameters

ParameterTypeMeaning
runId (path)string
required

Response

Single resource, { data: { … } }.

FieldTypeMeaning
runIdstring
logstringPlain text, one line per entry. Empty when there is nothing to show.

POST /api/v1/runs/:runId/apply

Approve a pending review and write its changes to Amazon, the same as pressing Apply in the review queue.

Scope: automation

Works on any run awaiting review: status preview, or partial while some of its changes are still proposed (a review applied in part), whether a rule or an API proposal created it. It returns as soon as the apply has started, and the writes happen in the background. Poll GET /api/v1/runs/:runId: it reports running until the writes settle, then applied, partial, failed (every change was refused), reverted (a review applied in part one of whose changes was since rolled back) or the status it had before, preview, or partial for a review already applied in part, for an apply stopped before it wrote anything, or a changeIds apply none of whose changes could be written while the rest of the run still awaits review. Poll until it is no longer running. A second apply of the same run with the same change selection attaches to it, so it does not write anything twice. A different selection while one is in progress is 409 conflict. A run that is no longer awaiting review is 409 conflict. An apply about to start is refused with sync_incomplete until the marketplace has completed its first full backfill, and while a full sync (a full re-sync included) is queued or running in its scope; attaching to one already running is not.

Headers

HeaderRequiredMeaning
Content-TypeoptionalThe body is optional. A body that is just {} is accepted whatever its Content-Type; any other: Must be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Parameters

ParameterTypeMeaning
runId (path)string
required
A run awaiting review: status preview, or partial while some of its changes are still proposed (a review applied in part), see GET /api/v1/runs?status=preview and ?status=partial.

Request body

FieldTypeMeaning
changeIdsarray
optional
Apply only these changes of the run (ids from GET /api/v1/runs/:runId/changes), at most 10000. The rest stay pending, and the run reads partial until they are applied or discarded, or, if none of the selected changes could be written, what it read before (preview, or partial for a review already applied in part). Omit it to apply every pending change.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
runIdstring
statusenum
running
The apply has been accepted. Poll GET /api/v1/runs/:runId for the outcome. When the marketplace already has several applies writing, this one waits for a slot and starts by itself; it reads running meanwhile and writes nothing until its turn.
totalintegerHow many changes this apply will write.

POST /api/v1/runs/:runId/retry-failed

Send a finished run's failed changes to Amazon again, the Retry button in History.

Scope: automation

For a run that reads partial or failed, or a review some of whose approved changes failed. Only changes that are safe to send twice go back: a bid, state, budget or other setting, an archive, and a create Amazon refused outright (the apply looks the entity up by name first, so nothing is built twice). A create whose answer was lost may already exist on Amazon and is left alone; it is counted in skipped. The writes happen in the background exactly as an apply's do: poll GET /api/v1/runs/:runId until it is no longer running. A run still writing, or one with nothing to resend, is 409 conflict; refused with sync_incomplete while the marketplace is backfilling. Each call spends one request of the key's auto-apply budget, as an apply does.

Headers

HeaderRequiredMeaning
Content-TypeoptionalNot checked. A body, if sent, must be an empty JSON object, read as UTF-8, one that is not valid UTF-8, or holds a NUL or an unpaired surrogate, is validation.

Parameters

ParameterTypeMeaning
runId (path)string
required
A run with failed changes: status partial or failed (GET /api/v1/runs?status=partial).

Request body

Unknown fields are refused. The body must be an empty JSON object.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
runIdstring
statusenum
running
The resend has started (or is waiting for one of the account's apply slots). Poll GET /api/v1/runs/:runId.
retriedintegerHow many failed changes go back to Amazon.
skippedintegerFailed changes left as they are, because sending them again could create something twice. Run the rule again to propose them afresh.

POST /api/v1/runs/:runId/discard

Turn down a pending review, the same as pressing Discard in the review queue. Nothing is written to Amazon.

Scope: automation

Works on any run awaiting review: status preview, or partial while some of its changes are still proposed (a review applied in part). What happens to the run afterwards depends on where it came from. An API proposal is kept and reads discarded. A rule's review is deleted, as it is in the dashboard, so GET /api/v1/runs/:runId then answers 404. If part of the review was already applied, the applied changes stay in History, only the rest is discarded, and the run settles on what it wrote (status in the answer). A run that is no longer awaiting review is 409 conflict: an applied run is undone by reverting it in MerchDash, not by discarding it.

Headers

HeaderRequiredMeaning
Content-TypeoptionalNot checked. A body, if sent, must be an empty JSON object, read as UTF-8, one that is not valid UTF-8, or holds a NUL or an unpaired surrogate, is validation.

Parameters

ParameterTypeMeaning
runId (path)string
required
A run awaiting review: status preview, or partial while some of its changes are still proposed (a review applied in part), see GET /api/v1/runs?status=preview and ?status=partial.

Request body

Unknown fields are refused. The body must be an empty JSON object.

Response

Single resource, { data: { … } }.

FieldTypeMeaning
runIdstring
statusenum
discarded · applied · partial · reverted
The status the run now reads. discarded when nothing of it was written. A review part of which was already applied keeps what it wrote and reads applied, partial when some of it failed, or reverted when some of it has since been rolled back.
deletedbooleanTrue when the run was removed entirely (a rule's review with nothing applied). False when it stays readable at its id.

PATCH /api/v1/runs/:runId/changes/:changeId

Change the bid or budget a pending change proposes, before approving it, the review table's own edit.

Scope: automation

Only a change still proposed, and only one that writes a number: a keyword or target bid (field: "bid") or a campaign budget (field: "budget"). The new bid passes the same checks a rule's does, Amazon's range for the marketplace and ad format, and the owner's maximum bids, so afterVal in the answer may differ from what was asked: lower where a ceiling caps it, higher where Amazon's floor raises it. Sending the original value again returns the change to exactly what was proposed. A change that is no longer proposed, whose run is being applied right now, or whose review's rule has since been deleted (that review can only be discarded) is 409 conflict; a change id from a different run is 404.

Headers

HeaderRequiredMeaning
Content-TyperequiredMust be application/json, with the body in UTF-8, a body that is not valid UTF-8 is validation, as is a NUL or an unpaired surrogate (\ud800) in any string. Character limits count UTF-16 code units, as JavaScript's length does (an emoji counts as two). Fields that refuse control characters say so.

Parameters

ParameterTypeMeaning
runId (path)string
required
A run awaiting review: status preview, or partial while some of its changes are still proposed.
changeId (path)string
required
As returned by GET /api/v1/runs/:runId/changes.

Request body

FieldTypeMeaning
valuenumber
required
The new bid (greater than 0) or daily budget (at least 1, Amazon's floor, a smaller one is validation), rounded to cents.
Unknown fields are refused. Any other field is refused rather than ignored.

Response

Single resource, { data: { … } }.

Fields: same as one row of runs.changes

Run statuses

The lifecycle a proposal moves through, as reported by GET /api/v1/runs/{runId}. This is a closed enum: a client may switch on it exhaustively, and MerchDash’s internal bookkeeping states are mapped into these rather than added to them.

StatusMeaningCan become
previewProposed and waiting for a human to approve it in MerchDash. Nothing has been written to Amazon. A rule's review whose rule has since been deleted stays here but can no longer be approved, only discarded (POST /api/v1/runs/:runId/apply answers 409 conflict).running, discarded, partial
runningThe writes are in flight: a human approved it, or it applies by itself (an auto rule or a proposal sent with applyMode: "auto").applied, partial, failed, preview, reverted
appliedEvery change was written to Amazon.reverted
partialSome changes were written and others were not, because they failed, or because they are still awaiting approval. As with preview, a review whose rule has since been deleted can no longer be approved, only discarded.reverted, running, applied
failedThe run ended without writing anything it meant to write, as far as MerchDash could tell. One exception: a create Amazon did not answer in time is looked up afterwards, and if Amazon did make it, the run moves to partial or applied.partial, applied
revertedAt least one applied change has since been rolled back. A review still awaiting approval reads partial instead, even with a rolled-back change, until the rest of it is applied or discarded.nothing, terminal
discardedA human turned the proposal down. Nothing was written to Amazon, and the run stays readable at this id.nothing, terminal

Error codes

Every error response carries one of these as code, alongside a human-readable error. Switch on the code; the message wording may be improved at any time.

CodeHTTPRetry?What happened
invalid_key401stopThe bearer token is not a usable MerchDash API key.
key_revoked401stopThe key was revoked by its owner.
key_expired401stopThe key is past its expiry date.
plan403stopThe account's plan does not include API access. The key is not revoked, an upgrade re-enables it.
scope403fixThe credential does not carry the capability this request requires, a read-only key on a write route, a key without the automation scope on an automation route, a browser session on an endpoint that needs a key, "applyMode": "auto" on a key whose owner has not turned auto-apply on for it, or a marketplace-limited key running, cancelling, dry-running, approving, discarding or reading the log of a rule or run that also covers a linked Amazon account the key does not.
account_unavailable403stopThe account is not currently available. Contact the account administrator.
not_found404fixNo such route, or no such resource in this account. An id belonging to somebody else answers exactly this.
validation400fixThe request could not be read or accepted. A query parameter or body field this endpoint does not document is refused here rather than ignored, so a misspelled filter cannot come back as an unfiltered answer, and so is a query parameter sent more than once. May carry a bounded details array naming each problem.
invalid_cursor400fixThe cursor is not one of ours, or was issued for a different endpoint or different filters.
payload_too_large413fixThe JSON request body exceeds this endpoint's size limit.
conflict409fixThe request conflicts with the resource's current state. Some of these can clear without the request changing, once another proposal or apply on the same entity (or, for a rename, wanting the same name) is decided, or once the Amazon account is reconnected in MerchDash, but whether a given one will cannot be told from the response, so an automatic retry should treat every conflict as fix and leave the rest to a human reading the message.
idempotency_conflict409fixThis Idempotency-Key was already used for a different request body.
run_in_progress409laterThe rule is already running in the other mode (preview vs apply), or its last run is still being written (MerchDash finishing it after an update or an interruption). A request cannot attach to that run, which would answer it with the wrong mode or has no job to attach to; retry once the run has finished, GET /api/v1/rules/{ruleId}/run says when.
creation_conflict409laterA campaign, ad group or portfolio this request wants to create is already reserved by another run, one not yet applied or turned down, or one still creating it on Amazon. Retry once that run is decided, or later for one being created; each details entry names the run and says which. The reservation is what stops the same container being built twice. A new campaign whose name an existing campaign is being renamed to, in a proposal still waiting for approval, is refused the same way.
rate_limited429waitA rate limit was exhausted. Retry-After says how long to wait.
review_queue_full429laterThis marketplace already holds 75 un-answered proposals. Retry once a human has worked through some.
sync_incomplete409laterA marketplace in scope (the message names it, for a linked pair, possibly the partner) has not completed its first full (95-day) backfill yet, after one that failed or was paused, its next sync runs that backfill, or has a full sync, a first backfill or a full re-sync, which rebuilds the archive, queued or running, so proposals cannot be validated against its snapshot yet. Retry later; GET /api/v1/sync/status shows progress, but its initialSyncComplete covers a linked pair whole and can stay false after this request would pass.
restarting503waitMerchDash is mid-deploy. The request was refused before it did anything and is safe to re-send.
temporarily_unavailable503waitA dependency the request needs, shared rate enforcement, for one, could not be reached.
internal500waitMerchDash could not complete the request because of an unexpected server error. Retry with backoff and report the requestId if it persists.