---
title: "Errors"
description: "Status codes, error codes and what to do about each."
canonical: "https://docs.nimbusmint.bot/errors/"
---
> Index: https://docs.nimbusmint.bot/llms.txt

# Errors

Every error is JSON with a stable `code` and a human-readable `message`:

```json
{ "code": "ip_not_allowed", "message": "this address may not use this key" }
```

Branch on `code`, never on `message`: messages can change at any time. New codes can be added within v1, so treat
an unknown code by its HTTP status.

## Error codes

| Status | `code` | Meaning | What to do |
| --- | --- | --- | --- |
| 400 | `invalid_request` | A parameter is missing or invalid (for example a malformed `contract` or `top` above 50). Also sent with `405` for a wrong HTTP method. | Fix the request. Do not retry unchanged. |
| 400 | `window_too_large` | The window from `since` to `until` is longer than allowed (currently 31 days). | Ask for a shorter window, or split it into several calls. |
| 401 | `invalid_key` | The key is missing, malformed, unknown, expired or revoked, or your partner access is disabled. | Check the header format and the key. If it is correct, check its expiry date (`/health` shows it while the key works), or contact us. |
| 403 | `ip_not_allowed` | The request did not come from an address on the key's allowlist. | Send us the server's public egress IP. See [IP allowlist](https://docs.nimbusmint.bot/authentication.md#ip-allowlist). |
| 403 | `scope_missing` | The key does not have the scope this route needs. | Ask for the scope (for `/hits`: `read:hits`). |
| 404 | `not_found` | There is no such route. | Check the path and the base URL `https://api.nimbusmint.bot/partner/v1`. |
| 429 | `rate_limited` | Too many requests for this key, or for the API as a whole. | Wait `Retry-After` seconds. See [Rate limits](https://docs.nimbusmint.bot/rate-limits.md). |
| 503 | `tenant_api_disabled` | The partner API is switched off. | Retry later; contact us if it lasts. |
| 503 | `ip_trust_unconfigured` | The API cannot verify client addresses right now, so it refuses every request rather than guess. | Retry later; this is on our side. |
| 503 | `internal` | The API is temporarily unable to answer. | Retry after `Retry-After` seconds when sent, otherwise with backoff. |

Authentication runs before routing, so a request without a valid key gets `401 invalid_key` on every path, including
paths that do not exist.

## Why a 401 does not say more

Every key problem returns the same `401 invalid_key`. Saying "unknown key" versus "wrong secret" versus "revoked"
would help someone guessing keys, so the API never does. If you are sure the key is right, check its expiry date,
then ask us: we can see why it failed.

## Retrying

- **Retry** `429` and `503` after `Retry-After` seconds when it is sent, otherwise with exponential backoff (for
  example 1 s, 2 s, 4 s, capped at 60 s).
- **Do not retry** `400`, `401`, `403` or `404` without changing something first.
- In user-facing features such as a Discord command, fail soft: show your own data and skip NimbusMint's rather than
  erroring.
