
# When a call fails

Every failure comes back in the same envelope:

```json
{ "ok": false, "kind": "bad_request", "friendly": "...", "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.

## 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` `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. |
| `404` `merchant_not_found` | The merchant selector matched nothing. | No. See [Identify a merchant](/knowledge-base/builder-platform/reference/merchant-identifiers). |
| `429` `throttled` | Rate limiting, ours or Amazon's. | Yes, after backing off. Honour `Retry-After`. |
| `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.

## `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 Amazon's own words:

- `amazon_error_code` is Amazon's code, such as `InvalidInput` or `InvalidParameterValue`.
- `status` is Amazon's own HTTP status, separate from ours.
- `responsePayload` is Amazon's full response, 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:

1. the **operation id**, for example `fulfillment_inbound.get_shipments`
2. the **`amazon_error_code`** and the `message` from the envelope
3. 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](mailto: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

- [Identify a merchant: sellerId and legacySellerId](/knowledge-base/builder-platform/reference/merchant-identifiers)
- [Limits and guardrails](/knowledge-base/builder-platform/reference/limits-and-guardrails)
- [Work with live Amazon operations](/knowledge-base/builder-platform/how-to/work-with-live-amazon-operations)
- Operation-level reference: [mcp.mixshift.io/developers](https://mcp.mixshift.io/developers)