# Errors

Every error has the same shape, and a `code` to switch on.

```http
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 40
Request-Id: req_7Qm2…

{
  "type": "https://bullpen.news/docs/errors#minute",
  "title": "Minute limit reached",
  "status": 429,
  "detail": "bullpen.news Individual limit reached: 30 calls a minute. Try again in 40 seconds.",
  "code": "minute",
  "retryAfterSeconds": 40,
  "plan": "individual",
  "requestId": "req_7Qm2…"
}
```

- `code` never changes for a given problem. Switch on it, not on `detail`, which is for people.
- `type` links to the problem's section below.
- A `400` for arguments adds `errors`: one `{ parameter, detail }` per bad parameter.
- New codes may be added. Treat one you don't know by its status.

Something wrong? Write to feedback@bullpen.news with the `Request-Id`. Is it everyone? See [status.bullpen.news](https://status.bullpen.news).

## key_in_url

`400`. "Send the key in the Authorization header."
A key was in the URL. Move it to `Authorization: Bearer`, and revoke it if the URL was logged anywhere. Don't retry as is.

## unauthorized

`401`. "Send a bullpen.news API key in the Authorization header."
No key, or not one we know. Check the header, and that the key was copied whole. Don't retry as is.

## revoked

`401`. "This key was revoked."
Make a new key on your [account page](/account).

## invalid_request

`400`. Says what's wrong, such as "limit is a whole number from 1 to 100."
`errors` lists each bad parameter. Fix them. Don't retry as is.

## invalid_cursor

`400`. "That cursor isn't valid. Start again without it."
The cursor was changed, or the other parameters changed with it. Start again without `cursor`.

## not_found

`404`. Says what, such as "bullpen.news has no company with the ticker ZZZZ."
No such ticker, firm, result or recap day, or no such endpoint. It may have been taken down since you saw it.

## method_not_allowed

`405`. Every endpoint is `GET`.

## gone

`410`. "This endpoint was retired. See the changelog."
The endpoint was retired on the day its notice gave. The `Link` header points to the [changelog](/docs/changelog) entry naming what replaces it. Don't retry.

## no_plan

`403`. "Start your 7-day free trial at bullpen.news/mcp to use the API." Or, once the trial's used: "Start a plan at bullpen.news/mcp to use the API."

## ended

`403`. "Your Bullpen.News plan has ended. Start a plan at bullpen.news/mcp."

## unpaid

`403`. "Your first charge didn't go through. Update your card at bullpen.news/account."

## terms

`403`. "Please accept the updated terms at bullpen.news/account."

## disabled

`403`. "This bullpen.news account is disabled. Write to feedback@bullpen.news."

## invite

`403`. "The Bullpen.News API isn't open yet."

## tool

`403`. "That endpoint isn't on your plan."

## minute

`429`. "bullpen.news Individual limit reached: 30 calls a minute. Try again in 40 seconds."
Wait `Retry-After` seconds. See [Limits](/docs/limits).

## day

`429`. "bullpen.news Individual limit reached: 1,000 calls today. It resets at midnight Eastern."
Wait for `Retry-After`, or move to Corporate.

## ceiling

`503`. "bullpen.news is busy. Try again in a minute."
Wait `Retry-After` seconds. It doesn't count against you.

## off

`503`. "The Bullpen.News API is paused."
See [status.bullpen.news](https://status.bullpen.news). Try again later.

## unavailable

`503`. "bullpen.news is having trouble. Try again in a minute."
Wait `Retry-After` seconds, then retry.

## internal

`500`. "Something went wrong on bullpen.news. Try again in a minute."
Our fault. Retry once after a minute. If it keeps happening, write to feedback@bullpen.news with the `Request-Id`.
