# Errors

Every error returns the same body: one machine-readable code and the request id. Branch on error.code, never on message text, and quote meta.request_id when you contact support.

```json
{
  "error": {
    "code": "SCOPE_REQUIRED"
  },
  "meta": {
    "request_id": "3f0c2b8e-7a51-4c1e-9d0a-5b6f1e2d4c3a"
  }
}
```

| HTTP | Code | Meaning | What to do |
|---|---|---|---|
| 400 | `INVALID_PUBLIC_REQUEST` | The request carries a cookie, or a path containing % or \. | Send from a server without cookies, with a clean path. |
| 400 | `DUPLICATE_PUBLIC_HEADER` | Repeated header: Authorization, If-Match, Idempotency-Key or Content-Type. | Send each header once. |
| 400 | `INVALID_QUERY` | The query string is too long, repeats keys, or carries a secret token. | Check the query limits, and never put tokens in the URL. |
| 400 | `INVALID_BODY` | The body is not a JSON object, or was sent with GET. | Send a JSON object with POST and PATCH only. |
| 400 | `INVALID_FILTER` | Invalid filter value, such as a limit outside 1–100. | Correct the value. |
| 400 | `CURSOR_MISMATCH` | The cursor was issued for different filters. | Restart the list with the new filters. |
| 400 | `CURSOR_EXPIRED` | 15 minutes have passed since the first page. | Restart the list, and finish it faster. |
| 400 | `IDEMPOTENCY_KEY_REQUIRED` | The operation requires an Idempotency-Key. | Add a unique key for each operation. |
| 400 | `INVALID_IDEMPOTENCY_KEY` | The key is longer than 128 bytes or contains whitespace. | Use a UUID. |
| 401 | `INVALID_TOKEN` | The access token is missing, malformed or expired. | Refresh the token, then retry the request once. |
| 403 | `SCOPE_REQUIRED` | The token does not carry the required scope. | Call /me. If the merchant revoked the scope, disable the feature or request new consent. |
| 403 | `SCOPE_NOT_AVAILABLE` | The resource is not available to apps. | Do not retry. |
| 403 | `RECONSENT_REQUIRED` | The version's scopes changed and merchant consent is required. | Send the merchant back through authorization. |
| 403 | `PLAN_NOT_ELIGIBLE` | The store's plan does not include apps. | Tell the merchant; apps are included in the Professional plan. |
| 403 | `INSTALLATION_INACTIVE` | The installation was uninstalled or suspended. | Stop all work for this store. |
| 404 | `RESOURCE_NOT_FOUND` | No resource with this ID in this store. A cart that was paid or is no longer abandoned, and a payment still in progress, are not found either. | Check the ID. The resource may have been deleted. |
| 404 | `NOT_FOUND` | The path does not exist. | Check the URL against the API reference. |
| 404 | `STORE_UNREGISTERED` | The store is not registered with LARM. | Stop all work for this store. |
| 405 | `METHOD_NOT_ALLOWED` | The method is not supported on this path. | Use a method listed in the Allow header. |
| 409 | `IDEMPOTENCY_CONFLICT` | The same key was used for a different request. | Use a new key for each distinct operation. |
| 409 | `IDEMPOTENCY_GENERATION_CONFLICT` | The key was used before the app was reinstalled. | Use a new key. |
| 409 | `OPERATION_IN_PROGRESS` | The first request with the same key is still running. | Wait a second and retry with the same key. |
| 409 | `RESOURCE_CONFLICT` | Conflicts with an existing resource. | Read the existing resource. |
| 409 | `INSUFFICIENT_STOCK` | The quantity is not enough for the requested decrease. | Read the current stock. |
| 409 | `ORDER_NOT_PAID` | The order is not paid, so it has no digital content. | Wait for order.paid. |
| 412 | `RESOURCE_CHANGED` | The resource changed after you read it. | Read it again, and rebuild the update on the latest version. |
| 413 | `BODY_TOO_LARGE` | The body is larger than 64 KB. | Split the operation. |
| 415 | `CONTENT_TYPE_REQUIRED` | The body has no Content-Type: application/json. | Add the header. |
| 422 | `UNKNOWN_FIELD` | Unknown field or filter. | Remove it. Field lists are closed. |
| 422 | `EMPTY_MUTATION` | The update changes nothing. | Send at least one field. |
| 422 | `CATEGORY_NOT_FOUND` | The referenced category does not exist. | Create it first, or use an existing name. |
| 422 | `PRICE_CHANGE_TOO_LARGE` | The price change is larger than 90%. | Confirm the price with the merchant. |
| 422 | `PAGE_MEDIA_NOT_SUPPORTED` | The page content contains images or media. | Send text and links only. |
| 428 | `PRECONDITION_REQUIRED` | The update requires If-Match. | Read the resource and send its ETag. |
| 429 | `RATE_LIMITED` | Rate limit exceeded. | Wait for Retry-After, then retry. |
| 500 | `INTERNAL_ERROR` | Unexpected error. | Retry shortly, and send the request_id to support if it persists. |
| 503 | `APPS_SERVICE_UNAVAILABLE` | The apps service is temporarily unavailable. | Retry after Retry-After. |
| 503 | `APPS_DISABLED` | Reads or writes are temporarily disabled. | Retry later. |
| 503 | `STORE_MIGRATING` | The store is moving between servers. | Retry after a few seconds. |
| 503 | `POLICY_UNAVAILABLE` | The app policy could not be verified. | Retry after a second. |
| 503 | `ROUTE_UNVERIFIED` | The store route could not be verified. | Retry after a few seconds. |
| 503 | `APPS_SCOPE_RUNTIME_NOT_READY` | The resource is not enabled on this merchant's store yet. | Retry after a few hours. |
| 400 | `INVALID_GRANT_TYPE` | Unknown grant_type. | Use authorization_code or refresh_token. |
| 400 | `INVALID_GRANT` | Missing fields or wrong token prefix. | Check the request body. |
| 400 | `INVALID_CODE` | The authorization code expired or was not approved. | Authorize again. |
| 400 | `REDIRECT_URI_MISMATCH` | redirect_uri does not match. | Use exactly the same URL. |
| 400 | `PKCE_MISMATCH` | code_verifier does not match code_challenge. | Authorize again with a new verifier. |
| 400 | `INVALID_REFRESH_TOKEN` | The refresh token is unknown or inactive. | Authorize again. |
| 400 | `REFRESH_ALREADY_USED` | The refresh token was already exchanged. | Use the latest token pair you stored. |
| 400 | `TOKEN_REUSE_DETECTED` | Resent after success; all tokens were revoked. | Authorize again, and fix your retry logic. |
| 401 | `INVALID_CLIENT` | Client authentication failed. | Check the Client ID, the secret and its validity. |
| 409 | `RESULT_UNAVAILABLE_REAUTHORIZE` | The result of the token operation was lost. | Call /oauth/operations/recover, then authorize again. |
| 429 | `AUTHORIZE_RATE_LIMITED` | Too many authorization requests. | Wait a minute. |
| 401 | `LAUNCH_EXPIRED` | The launch URL is older than 5 minutes. | Ask the merchant to open the app again. |
| 401 | `LAUNCH_SIGNATURE_INVALID` | The launch URL signature does not match. | Reject the session. |
| 409 | `SUBSCRIPTION_EXISTS` | The installation already has a subscription. | Update the existing one with PATCH. |
| 403 | `ENDPOINT_NOT_APPROVED` | The URL is not registered in the version. | Add it in a new version. |
| 422 | `ENDPOINT_UNSAFE` | The URL is not https or does not resolve to a public address. | Use a public domain with a valid certificate. |
| 403 | `SUBSCRIPTION_EXPANSION_REQUIRES_RECONSENT` | Adding topics with PATCH. | Delete the subscription and create a new one. |
| 400 | `EVENT_NOT_SUBSCRIBED` | Test webhook for a topic you are not subscribed to. | Subscribe to it first. |
| 400 | `INVALID_REPLAY` | The replay range is outside the last 7 days, or the reason is missing. | Correct from, to and reason. |
