# Errors

Every machine-readable error code, its HTTP status, whether it is retryable, and what to do about it.

Every error response is [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) `application/problem+json` with a stable `code`. Switch on `code`, never on the human `title` or `detail` — codes are append-only and never change meaning; the texts may. The `type` URI of every code resolves to its row on this page.

## The problem+json envelope

```json
{
  "type": "https://pay.mmokick.com/developers/errors#rate_limited",
  "title": "Rate limited",
  "status": 429,
  "code": "rate_limited",
  "detail": "Write limit of 120 requests per minute exceeded.",
  "instance": "/api/v1/offers"
}
```

## HTTP 400

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `invalid_json` | Invalid JSON | no | The request body is not parseable JSON. Fix the request body. |
| `invalid_cursor` | Invalid cursor | no | The pagination cursor is unknown or expired. Restart the listing without a cursor. |
| `idempotency_key_invalid` | Invalid idempotency key | no | The `Idempotency-Key` header is empty or longer than 200 characters. Send a valid key. |

## HTTP 401

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `unauthenticated` | Unauthenticated | no | The `Authorization` header is missing or malformed. Send `Authorization: Bearer <token>`. |
| `invalid_token` | Invalid token | no | The token is unknown. Check the token, or create a new one in the portal. |
| `token_revoked` | Token revoked | no | The token was revoked in the portal. Issue a new token. |
| `wrong_environment` | Wrong environment | no | A `ck_test_` token was used on production, or a `ck_live_` token on sandbox. Use the token that matches the host. |

## HTTP 403

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `insufficient_scope` | Insufficient scope | no | The token lacks a scope the endpoint requires. Issue a token with the needed scope. |
| `supplier_suspended` | Supplier suspended | no | The supplier account is suspended by staff. Contact support. |

## HTTP 404

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `not_found` | Not found | no | No such resource, or it does not belong to your supplier. Check the id. |

## HTTP 405

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `method_not_allowed` | Method not allowed | no | The HTTP method is not allowed on this path. Fix the verb. |

## HTTP 409

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `offer_exists` | Offer already exists | no | An offer already exists for this product. Update the existing offer instead of creating a second. |
| `invalid_state` | Invalid state | no | The requested transition is not allowed from the resource's current state. Read the current state first. |
| `stock_mode_mismatch` | Stock mode mismatch | no | An inventory operation was sent to a declared-stock offer, or a stock declaration to an uploaded offer. Use the operation that matches the offer's stock mode. |
| `idempotency_conflict` | Idempotency conflict | no | The `Idempotency-Key` was reused with a different request body. Use a new key. |
| `idempotency_in_flight` | Idempotency in flight | yes | The original request for this idempotency key is still running. Retry after the `Retry-After` interval. |

## HTTP 413

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `payload_too_large` | Payload too large | no | The request body exceeds 1 MB. Split the batch into smaller requests. |

## HTTP 415

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `unsupported_media_type` | Unsupported media type | no | The `Content-Type` is not `application/json`. Fix the header. |

## HTTP 422

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `validation_failed` | Validation failed | no | One or more fields failed validation (see the `errors` map in the response). Fix the fields. |
| `product_not_sellable` | Product not sellable | no | The product is archived or paused for new offers. Pick another product. |
| `fulfilment_unreachable` | Fulfilment endpoint unreachable | yes | The inline healthcheck of your fulfilment endpoint failed on activation or URL change. Fix your endpoint, then retry. |
| `inventory_rejected` | Inventory rejected | no | A strict-mode upload contained invalid items (see `rejected_items`). Fix the items or upload in `partial` mode. |

## HTTP 429

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `rate_limited` | Rate limited | yes | A rate limit was hit. Honor the `Retry-After` header and back off. See the rate limits page. |

## HTTP 500

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `internal_error` | Internal error | yes | An error on our side, logged under the response `trace_id`. Retry with backoff; report it if it persists. |

## HTTP 503

| `code` | Title | Retryable | What it means / what to do |
|---|---|---|---|
| `service_unavailable` | Service unavailable | yes | A maintenance window is in effect (carries `Retry-After`). Retry after the given interval. |
