# Errors (/api-reference/errors)

Errors are JSON with a stable `error` code. Most also have a human-readable `message`, and some add fields (`max`, `states`, `type`, `fieldgeist_id`):

```json
{
  "error": "insufficient_credit",
  "message": "This team is out of credit. Add credits at https://app.fieldgeist.com/billing."
}
```

Branch on the HTTP status and `error`. Don't parse `message`: its wording can change.

Errors aren't billed. Only `200` answers are.

## Order of checks [#order-of-checks]

A request is checked in this order, and the first failure is the answer:

1. **API key** (`401`, `429`, `503 unavailable`).
2. **Team status** (`403 team_paused`, then `402`). These are checked before the body, so a paused team gets `403` even for a malformed request.
3. **Request** (`400`, `413`, `422`).
4. **Answer** (`200`, `404`, `500`, `503 matchkey_unavailable`).

## All errors [#all-errors]

| Status | `error` | Endpoints | Cause | What to do |
| --- | --- | --- | --- | --- |
| `400` | `invalid_json` | Parse, Lookup | The body isn't valid JSON. | Fix the body. |
| `400` | `line_required` | Parse | The body has no `line` string. | Send `{"line": "..."}`. |
| `400` | `components_required` | Lookup | The body isn't an object, or a component isn't a string or number. | Send components or a parse response. |
| `400` | `street_required` | Lookup | No `streetName`. | Add the street. |
| `400` | `location_required` | Lookup | No `zip5` or `city`; or a city in more than one state with no `state` (adds `states`, the number of states). | Add `zip5`, or `city` and `state`. |
| `400` | `invalid_id` | Lookup by ID | The ID isn't `adr_` plus a 26-character ULID. | Check the ID. |
| `401` | `invalid_api_key` | All | The `Authorization` header is malformed, or the key is unknown or revoked. Comes with `WWW-Authenticate: Bearer`. | Send `Authorization: Bearer <key>` with an active key. |
| `402` | `insufficient_credit` | All | The team's credit balance is used up. | Add credits in the portal's **Billing** page, or turn on auto recharge. Requests resume within minutes. |
| `402` | `budget_exceeded` | All | The team reached the monthly budget it set. | Raise or remove the budget in **Billing**. Budgets count spend per calendar month (UTC). |
| `403` | `team_paused` | All | Fieldgeist paused the team's API access. | Contact support@fieldgeist.com. |
| `404` | `not_found` | Lookup by ID | No parcel has this ID. Echoes `fieldgeist_id`. Not billed. | Look the address up again. |
| `413` | `line_too_long` | Parse | `line` is longer than 256 characters. Adds `max`. | Shorten the line. |
| `422` | `unsupported_type` | Lookup | The address `type` isn't `street`. Echoes `type`. | Only street addresses have parcels. |
| `422` | `unsupported_id_type` | Lookup by ID | A building ID (`bld_…`). | Use a parcel's `adr_` ID. |
| `429` | `rate_limited` | All | Too many different unrecognized keys from your IP address in a minute. | Fix the key, wait a minute. See [Rate limits](/rate-limits). |
| `500` | `internal_error` | All | Something failed on our side. | Retry with backoff. If it persists, contact support with the `x-request-id`. |
| `503` | `unavailable` | All | We couldn't check the API key. | Retry shortly. |
| `503` | `matchkey_unavailable` | Lookup, Lookup by ID | The parcel index is unavailable. | Retry later. |

A request to a path that doesn't exist (or with the wrong method, such as `GET /v1/verify/parse`) gets `404` with a plain-text body, not JSON.

## 402 and 403 in detail [#402-and-403-in-detail]

The three refusals for a valid key:

```json
{ "error": "insufficient_credit", "message": "This team is out of credit. Add credits at https://app.fieldgeist.com/billing." }
```

```json
{ "error": "budget_exceeded", "message": "This team reached its monthly budget. Raise it at https://app.fieldgeist.com/billing." }
```

```json
{ "error": "team_paused", "message": "This team's API access is paused. Contact support@fieldgeist.com." }
```

- Refused requests appear in the portal's **Logs** with their error code and request ID. They aren't billed.
- A team's billing status is updated shortly after the spend that changes it, so a few requests can be answered after the balance reaches zero. After you add credits, requests resume within minutes.

## Retrying [#retrying]

Every Verify endpoint only reads data, so retrying is safe. Note that each `200` is billed, including a retried one.

| Status | Retry? |
| --- | --- |
| `400`, `401`, `404`, `413`, `422` | No. Fix the request. |
| `402`, `403` | Not until the team's billing or status changes. |
| `429` | After a minute, with a valid key. |
| `500`, `503` | Yes, with exponential backoff. |

## Request IDs [#request-ids]

Every request made with a valid key, including refused ones, gets an `x-request-id` response header (`req_` followed by 26 characters). The same ID is on the request's row in **Logs**. Include it when you write to support@fieldgeist.com.
