# Errors, quotas and rate limits

Every 401, 402, 403 and 429 from the API is JSON with a human sentence and fields an agent can act on:

```json
{
  "detail": "bulk endpoints need the Developer plan: https://tickermint.cards/developers#plan",
  "error": "plan_required",
  "required_plan": "developer",
  "how_to_fix": "This endpoint needs Developer or above. Plans and prices: https://tickermint.cards/pricing.json; subscribe at ... (7-day free trial).",
  "upgrade_url": "https://tickermint.cards/developers?ref=api-plan-required&plan=developer#plan",
  "docs_url": "https://tickermint.cards/docs/errors.md#plan-required",
  "pricing_url": "https://tickermint.cards/pricing.json",
  "commercial_use": "Free keys and Developer are for personal and non-commercial use. A store, a paid app or any product a business runs needs API Pro ($49/mo) or above."
}
```

Handle them like this: show `how_to_fix` to the user, link `upgrade_url`, and on 429 wait `Retry-After` seconds before retrying. Never retry 401/402/403 in a loop. Error answers also carry `Link: <docs_url>; rel="help"`.

## key-required

HTTP 401. The endpoint needs a key and none was sent (CSV files without a key, /v1/bulk, /v1/webhooks).

What to do: Send X-API-Key (env var TICKERMINT_API_KEY). Free key: https://tickermint.cards/developers#keys. For /v1/bulk the key must be on Developer or above; for /v1/webhooks on API Pro or above.

## invalid-key

HTTP 401. The key is unknown or was revoked.

What to do: Copy a live key from https://tickermint.cards/developers#keys (log in with the same email) or create a new one.

## plan-required

HTTP 402. The key's plan does not include the endpoint (402 for /v1/bulk below Developer, 403 for /v1/webhooks below API Pro). `required_plan` names the cheapest plan that does.

What to do: Subscribe to required_plan at upgrade_url (7-day free trial). Plans: https://tickermint.cards/pricing.json.

## quota-exceeded

HTTP 429. The daily (no key, free key) or monthly (paid) lookup quota is used up, a trial used its 5,000 lookups, or a call would pass the plan's monthly history cap (quota.unit says which; full history beyond 90 days counts toward it). Retry-After says when it resets.

What to do: No key: get a free key. Free key: Developer for personal use, API Pro for commercial use. Paid: the next plan up (required_plan). Trial: end the trial and pay from the keys panel (upgrade_url), and the full plan starts at once. History cap: ask single cards for ?days=90 or less (never counted); products already fetched this month are free again. Cache answers: prices change once a day.

## trial-limit

HTTP 403. A bulk endpoint (/v1/bulk/history, /v1/bulk/day) was called during an unpaid trial. Trials: 5,000 lookups and no bulk history until the first payment.

What to do: End the trial and pay at upgrade_url (https://tickermint.cards/developers#keys); bulk opens at once. Until then use single-card endpoints within the trial's 5,000 lookups.

## rate-limited

HTTP 429. Too many requests in one minute (burst protection: 120 a minute per IP with no key, 300 on a free key, more on paid plans).

What to do: Wait Retry-After seconds and retry with backoff; cache answers; use a key for its own per-minute bucket.

## Quota headers (every metered answer)

| Header | Meaning |
|---|---|
| `X-Quota-Limit` | lookups allowed in the period |
| `X-Quota-Remaining` | lookups left |
| `X-Quota-Reset` | when the period resets, Unix seconds (UTC midnight for daily, the 1st for monthly) |
| `X-Quota-Period` | `day` or `month` |
| `X-Quota-Plan` | `no-key`, `free`, `developer`, `api_pro`, `api_business`, `api_platform` |
| `Warning` | present when over quota during the soft launch (until 2026-11-09); the call still answers |
| `Retry-After` | on 429: seconds until you may retry |

Cloudflare may answer popular GETs from its cache; such answers are free and uncounted, and their X-Quota-* headers can belong to whoever filled the cache.
