# Errors

Every error has the same JSON body:

```json
{ "error": "plan_required", "message": "This endpoint is part of the Growth plan. Your key is on Free." }
```

Branch on `error`, show `message` to a person. Some errors add fields, listed below.

| Status | `error` | What happened | What to do |
| --- | --- | --- | --- |
| 400 | `invalid_parameter`, `invalid_cursor`, `cursor_mismatch` | A parameter is missing, malformed, or a cursor was reused with different filters. | Fix the request. The message names the parameter. |
| 401 | `invalid_api_key` | The key is missing, mistyped or revoked. | Check the key in the [dashboard](https://developers.motorsdynamic.com/dashboard). |
| 402 | `plan_required` | The endpoint is on a higher plan. Body: `required_plan`, `current_plan`, `upgrade_url`. | Upgrade, or call an endpoint on your plan. |
| 403 | `account_suspended`, `not_entitled`, `page_cap` | The account is suspended, the data is outside your contract, or a capped search passed its last page. | Contact support, or narrow the search. |
| 404 | `vin_not_found`, `not_found` | Nothing matches the VIN or id. | Check the identifier. |
| 429 | `rate_limited` | Too many requests this second or minute. Header: `Retry-After`. | Wait and retry. |
| 429 | `quota_exceeded` | The Free monthly calls are used up. Body: `limit`, `resets_at`, `upgrade_url`. | Upgrade or wait for the reset. |
| 429 | `search_cap` | The daily search allowance on the MCP server is used up. | Wait until 00:00 UTC or upgrade. |
| 500 | `internal_error` | Something failed on our side. Not billed. | Retry with backoff. |
| 504 | `query_timeout` | The query passed its 4 second budget. Not billed. | Narrow the filters or lower `limit`. |

Only 2xx responses are billed, so retrying an error never costs a call.
