# Errors

Errors use `{ content, message, errors }`. Plan, bulk and quota errors add `{ error: { code, message } }`.

| Status | Meaning | Shape |

| 400 | Invalid params | `message: "Invalid params"`, `errors: [{ path, message }]` |

| 400 | Source error | `{ project, error, errors, context?, timestamp }` |

| 400 | Bulk cap exceeded | `error.code: "bulk_cap_exceeded"`, `cap`, `submitted` |

| 401 | Missing / invalid key | `message` |

| 403 | Plan gate | `error.code: "plan_upgrade_required"`, `required_plan`, `upgrade_url` |

| 403 | Bulk not enabled | `error.code: "bulk_not_enabled"` |

| 404 | Unknown scraper / endpoint | `message` |

| 405 | Wrong HTTP verb | `content.expected` + `Allow` header |

| 422 | Idempotency key reused with another body | `error.code: "idempotency_key_reuse"` |

| 429 | Rate or monthly limit | `content: { limit, used, window, retryAfterSec }` + `Retry-After` |

| 501 | Endpoint listed but not live yet | `content.status: "planned"` |

| 503 | Disabled or not configured | `message` |

| 504 | Source timed out | `message` (refunded) |
