---
title: Error codes & retry semantics
description: Complete list of error codes the API returns, when to retry, and how to back off. Only 2xx responses are billed.
order: 20
---

# Error codes

Every non-2xx response is free. That's the contract - if we didn't give you a clean product, you didn't pay for it.

All errors return a JSON body with the same shape:

```json
{
  "error": "string_code",
  "message": "human-readable explanation",
  "docs_url": "https://amazonscraperapi.com/docs/guides/errors#string_code",
  "request_id": "req_9f2c8a1b3e4d"
}
```

The `request_id` is what we'll ask for if you email support. `docs_url` deep-links to the row in this table.

## Error table

| HTTP | `error` code | When it happens | Retry? |
|---|---|---|---|
| `400` | `invalid_params` | ASIN not 10 alphanumeric chars, unsupported `domain` value, `language` not in the enum, missing `query`. | No - fix the request. |
| `401` | `unauthorized` | Missing `Authorization` header, malformed Bearer token, or unknown key. | No - get a valid key. |
| `401` | `revoked` | Key was rotated out. | No - use your current key. |
| `402` | `insufficient_credits` | You're out of credits and have no active auto-top-up. | Yes, after topping up. |
| `403` | `forbidden_region` | Egress to the requested country isn't available on your plan. | No - upgrade or drop the `country` param. |
| `404` | `not_found` | You hit an unknown path. Check the endpoint URL. | No. |
| `408` | `upstream_timeout` | Amazon took > 45s to respond. | **Yes** - retry up to 3 times with 2s backoff. |
| `422` | `blocked_by_amazon` | Amazon served a challenge page or 503. We already retried internally. | Yes, but with a 60s+ delay. |
| `429` | `rate_limited` | You exceeded your per-key QPS or concurrency ceiling. Check the `Retry-After` header. | **Yes** - respect `Retry-After`. |
| `500` | `internal_error` | Unhandled exception on our side. Always get logged. | Yes, after ~5s. |
| `501` | `not_implemented` | You passed a roadmap param (`render_js`, `screenshot`). | No - wait for the feature. |
| `502` | `target_unreachable` | Amazon blocked every internal retry. | Yes, with a 60s+ delay. |
| `502` | `extraction_failed` | Amazon served HTML that our extractor couldn't parse. Usually a new A/B layout; we auto-file a ticket. | Yes, typically works on retry. |
| `502` | `asin_mismatch` | You asked for B1, Amazon redirected to B2 (usually a new-edition swap). | No - the source ASIN is what's stale. |
| `502` | `generic_gallery_page` | Amazon served a placeholder shelf (the product is delisted). | No - remove the ASIN from your set. |
| `503` | `capacity` | We're rate-limiting you to protect the shared pool. Rare. | Yes, after `Retry-After`. |

## Retry semantics - the defaults we recommend

Use **exponential backoff with jitter** for anything marked "Yes" above. Here's a canonical loop you can port to any language:

```javascript
async function scrapeWithRetry(fetchFn, maxAttempts = 4) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fetchFn();
    if (res.ok) return res.json();

    // Don't retry permanent errors.
    if ([400, 401, 402, 403, 404, 501].includes(res.status)) {
      throw new Error(`permanent: ${res.status}`);
    }

    if (attempt === maxAttempts) throw new Error(`gave up after ${attempt}`);

    // Respect our Retry-After if we sent one.
    const retryAfter = Number(res.headers.get("Retry-After")) * 1000;
    const backoff = retryAfter || Math.min(2 ** attempt * 1000, 30_000);
    await new Promise(r => setTimeout(r, backoff + Math.random() * 1000));
  }
}
```

Our official SDKs (Node, Python, Go, CLI) apply this policy automatically. You only need to bake it in yourself if you're calling the raw HTTP API.

## Debugging a failed request

Every response carries `request_id` in the body. If you email <info@amazonscraperapi.com> with that ID, we can pull the full internal trace - upstream status, attempts, latency per attempt, extractor output. Keep it in your own logs for at least 7 days so we don't both have to guess later.

## Related

- [Authentication](/docs/guides/authentication) - key format + rotation
- [Rate limits & concurrency](/docs/guides/rate-limits) - per-plan ceilings
- [Billing policy](/docs/guides/billing) - only-2xx rule in detail
