When a call fails
Every failure comes back in the same envelope:
{ "ok": false, "kind": "bad_request", "source": "amazon_rejected", "retryable": false,
"friendly": "...", "message": "...",
"amazon": { "status": 400, "code": "InvalidInput", "message": "..." },
"amazon_error_code": "InvalidInput", "status": 400 }
Branch on kind, not on the HTTP status. friendly is safe to show a person as-is. message is the specific reason, and it is the field to read when you are trying to fix something.
Two fields answer the questions below in one word each. source says whose problem it is: request (fix your request), account (the account owner acts: scopes, re-authorization, activation), amazon_rejected (Amazon said no to this specific request, and its own words are under amazon), amazon_unavailable (temporary; wait and retry) or mixshift (ours; tell us). retryable says whether sending the same call again can ever succeed; when it is false, a retry loop cannot end. Some failures also carry fix, a concrete next step. On the MCP tools, a failed call carries the same envelope as its result text and also sets the result's isError: true.
The only question that matters first: whose problem is it?
Retrying the wrong kind of failure is the most common way to lose an afternoon here, so the answer is meant to be obvious from the response alone.
| You get | Whose problem | Retry? |
|---|---|---|
400 invalid_request |
Yours, caught before Amazon. An operation id not in the catalog, a missing path parameter, a body where none is taken, or a malformed body. Nothing was sent to Amazon. | No. Fix the request; friendly and fix say what to change. These used to arrive as 500 unknown. |
400 bad_request |
Yours. Amazon rejected the request itself. | No. It is deterministic and will fail identically forever. Change the request. |
403 restricted_report |
An access or role gap. | No. Re-authorize the merchant, or use a different operation. |
409 reauth_required |
The merchant's Amazon connection lapsed. | Re-connect the account first, then yes. |
422 merchant_inactive |
The merchant is real and its authorization is fine, but it is not activated for Amazon Ads in MixShift, so Amazon will not serve its campaign data. | No, and do not re-authorize. Needs a person to activate the merchant in MixShift. |
403 profile_not_authorized |
The advertising login this merchant is connected through does not have access to it at Amazon. The MixShift connection itself is working. | No, and re-authorizing will not change it. Check the advertising login's access at Amazon, or ask us to re-map it. On reporting_v1.create_report, where you name the accounts yourself, check the ids first: a DSP seat id in place of the dspAdvertiserId fails exactly this way. |
404 merchant_not_found |
The merchant selector matched nothing. | No. See Identify a merchant. |
429 throttled |
Rate limiting, by us or by Amazon. | Yes, after backing off. Honour Retry-After. One exception: a 429 from reporting_v1.create_report means reports are already in flight, a concurrency cap, and backing off will not clear it. Delete a report you no longer need, or wait for one to finish. |
502 upstream_unavailable or host_unreachable |
Amazon's, or the network. | Yes, later. For writes, check whether it applied first. |
500 unknown |
Ours, and now rare. | Once. If it persists, tell us. |
The write caveat on 502 is worth reading twice: a server error does not prove Amazon rejected your change before acting on it. Re-read the entity before you re-send, or you can apply the same change twice.
merchant_inactive and profile_not_authorized are newer, and they are a split rather than an addition: until 2026-09-15 an inactive merchant and an unmapped advertiser both arrived as 409 reauth_required, which sent callers into a re-authorize loop that could never succeed. If your integration branches on the HTTP status rather than on kind, these two now land somewhere you may not handle.
The rest of the set
The table above is triage, not the full list. The service serves 27 kinds in total, and the ones it does not cover fall into two families you will meet as soon as you go past reads.
Guarded listings writes. A change set is proposed, approved, then committed, and each step has its own way of going wrong. None of these are worth a blind retry; each one tells you which step to go back to.
| You get | What happened | Retry? |
|---|---|---|
404 change_set_not_found |
The id does not exist, or was never yours. | No. |
409 change_set_expired |
It aged out before you committed it. | No. Propose it again. |
409 change_set_already_committed |
It already applied. | No, and do not re-propose without re-reading: the change is live. |
409 approval_mismatch / stale_approval |
The approval does not match what you are committing, or the listing moved underneath it. | No. Re-read, re-propose, re-approve. |
409 schema_drift |
Amazon changed the product type's schema since the change set was built. | No. Rebuild against the current schema. |
422 patch_not_allowed |
The attribute cannot be patched this way. | No. |
403 listings_write_not_enabled |
Writes are not enabled for this account. | No. Talk to us. |
503 listings_write_disabled / listings_media_write_disabled |
MixShift has the surface switched off globally. | Later, yes. |
Reports.
| You get | What happened | Retry? |
|---|---|---|
400 report_retired |
Amazon retired that report type. Nothing was sent. | No. Use a current type. |
502 report_fatal |
Amazon accepted the report then failed to produce it. | Not as the same request (retryable is false). Check the parameters, such as the date range, before you create it again. |
Configuration. 503 spapi_not_configured and 503 ads_not_configured
mean the relevant Amazon API is not switched on for the MixShift service; 403
insufficient_scope means your credential is missing a scope the surface needs,
which an admin grants at /admin.
bad_request: what Amazon actually said
This is the one to know, because it used to be the confusing one. A request Amazon refused because of its own parameters used to come back as a 500, which reads as an outage and invites a retry that could never work. It now comes back as a 400 and carries the words Amazon used:
amazon_error_codeis the code Amazon returned, such asInvalidInputorInvalidParameterValue.statusis the HTTP status Amazon returned, separate from ours.responsePayloadis the full response from Amazon, when we captured it.
In the plugin, the same information prints to the terminal, and --json carries amazon_error_code, amazon_status and amazon_response. Scripts get exit code 12, which is distinct from the generic failure code precisely so a script can stop instead of retrying.
Most of the time this means a parameter is missing, misspelled, or in the wrong case. The operation catalog (GET /api/amazon/spapi/operations) documents the required parameters and the casing rules for each call, and it is the first thing to check.
Reporting a failure, and why it is worth your thirty seconds
Sometimes the request was wrong because our documentation said to make it that way.
The operation catalog is maintained by hand. Amazon occasionally enforces a parameter it does not document, or requires two parameters only in combination, and until someone hits it our notes look complete. When our notes are wrong, every caller walks into the same wall.
Here is the asymmetry that makes your report valuable: we can see that a call failed and which operation it was. We cannot see your parameters. You are holding the half we are missing.
So please send three things:
- the operation id, for example
fulfillment_inbound.get_shipments - the
amazon_error_codeand themessagefrom the envelope - the parameters you sent, minus anything you consider sensitive
Where to send it:
- Plugin users: run
mixshift feedback. It attaches the context for you. - Everyone else: support@mixshift.io.
We record the Amazon error code against the operation, so the same code repeating on the same call surfaces as a pattern on our side. A confirmed gap normally turns into a catalog note that the next caller never trips over. That is the whole loop, and it starts with someone bothering to tell us.
Related
Shifty is the MixShift docs assistant. Pick a question or open the chat for anything else.