> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gemrate.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors & limits

> Error responses, error codes, quotas, and rate limits.

## Errors

Errors return a non-2xx status and a body with a stable, machine-readable
`code` you can branch on (the `message` is for humans and may change):

```json theme={null}
{
  "error": {
    "code": "cert_not_found",
    "message": "No PSA cert found for cert 12345678.",
    "details": { "grader": "psa", "cert": "12345678" }
  },
  "meta": { "request_id": "req_abc123" }
}
```

### Error codes

Any endpoint can return:

| Code | Status | Meaning |
| - | - | - |
| `bad_request` | `4xx` | The request was rejected before reaching the API (for example, too large). `details.type` says why. |
| `invalid_parameter` | `400` | A parameter is missing or invalid. |
| `invalid_api_key` | `401` | Missing, disabled, or invalid API key. |
| `forbidden` | `403` | Your key isn't allowed to access this resource. |
| `not_found` | `404` | Endpoint does not exist. |
| `rate_limited` | `429` | Too many calls per second — see [Rate limits](#rate-limits). |
| `quota_exceeded` | `429` | Quota used up for this period — see [Quotas](#quotas). |
| `timeout_error` | `504` | The request took too long. Retry after the `Retry-After` value (`120` seconds). |
| `internal_error` | `5xx` | Something went wrong on our end. |

Specific endpoints can also return:

| Code | Status | Meaning | Endpoints |
| - | - | - | - |
| `processing` | `202` | The spec is known but not yet linked to a card — retry shortly. | `/v1/specs/…` |
| `invalid_grader` | `400` | Unknown grader. | `/v1/certs/…`, `/v1/specs/…`, `/v1/cards/{gemrate_id}/...`, `/v1/cards/search/structured` |
| `cert_not_found` | `404` | We have no such cert. | `/v1/certs/…` |
| `card_not_found` | `404` | We have no such card. | `/v1/cards/{gemrate_id}/...` |
| `spec_not_found` | `404` | We have no such spec. | `/v1/specs/…` |
| `as_of_unavailable` | `503` | Historical data is temporarily unavailable — retry later. | `/v1/cards/{gemrate_id}/population/history` |

## Quotas

Your plan sets how many calls you can make per period. Each call is charged
to one **bucket**.

* Endpoints that need an extra permission draw from that permission's own
  bucket **if your plan puts a limit on it**.

  | Endpoint | Bucket |
  | - | - |
  | `GET /v1/certs/{grader}/{cert}/images` | `read:images` |
  | `GET /v1/cards/{gemrate_id}/population/history` | `read:history` |
  | `GET /v1/cards/population/changes` | `read:changes` |

* Every other call — and any of the above when your plan doesn't limit that
  permission separately — draws from your account-wide `base` bucket.

All `5xx`, `429`, and `403` responses will not count against your quota.

When a bucket quota is exceeded, calls return `429` with the
code `quota_exceeded` until the period resets. `Retry-After` says how many
seconds that is.

Every response for a call charged to a limited bucket carries:

| Header | Meaning |
| - | - |
| `X-RateLimit-Bucket` | The bucket this call was charged to, e.g. `base`. |
| `X-RateLimit-Limit` | Calls allowed in this bucket this period. |
| `X-RateLimit-Remaining` | Calls left in this bucket this period, after this one. |
| `X-RateLimit-Reset` | When the period resets, as Unix epoch seconds. |

## Rate limits

Separately from quotas, calls are limited per second. Going over returns
`429` with the code `rate_limited`, even if your quota has calls left.
These responses do not carry `X-RateLimit-*` headers, which
describe quotas only.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.