# Errors

Errors use `application/problem+json` (RFC 7807). Branch your code on `type`, log `detail`, and keep `request_id` for support.

Source: https://inplan.io/docs/errors · Updated 2026-10-30

## The problem format

Response (400 Bad Request · application/problem+json):

```http
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json; charset=utf-8
RateLimit-Limit: 60
RateLimit-Remaining: 106
RateLimit-Reset: 1
RateLimit-Policy: 60;w=1;burst=120
X-Quota-Limit: 2000000
X-Quota-Remaining: 1997025
X-Quota-Reset: 1793491200
X-Request-Id: req_tyeV9VkOEHSgXbbW
```

```json
{
  "type": "invalid_npi",
  "title": "Invalid NPI",
  "status": 400,
  "detail": "\"1234567890\" fails the NPI check digit (Luhn with prefix 80840).",
  "instance": "/v1/check",
  "request_id": "req_tyeV9VkOEHSgXbbW",
  "docs": "https://inplan.io/docs/errors#invalid_npi"
}
```

| Field | Type | Description |
| --- | --- | --- |
| `type` | string | Short problem type. Branch your code on this value. See [Errors](https://inplan.io/docs/errors). |
| `title` | string | A short, readable summary. |
| `status` | integer | The HTTP status code. |
| `detail` | string | What went wrong with this request, in one sentence. |
| `instance` | string | The path you called. |
| `request_id` | string | Unique to this request. Quote it to support. |
| `docs` | string | A link to the matching entry on the errors page. |
| `current_plan` | string | `plan_upgrade_required` only: the plan of the key you sent. |
| `required_plan` | string | `plan_upgrade_required` only: the smallest plan that includes the endpoint. |
| `sample_npis` | string[] | `demo_restricted` only: the NPIs the demo key answers for. |

## Statuses at a glance

| Status | Types | Retry? |
| --- | --- | --- |
| 400 | [`invalid_request`](#invalid_request), [`invalid_npi`](#invalid_npi), [`invalid_plan_id`](#invalid_plan_id), [`invalid_cursor`](#invalid_cursor), [`batch_too_large`](#batch_too_large), [`depth_limit`](#depth_limit) | No. Fix the request. |
| 401 | [`unauthorized`](#unauthorized) | No. Fix the key. |
| 403 | [`account_suspended`](#account_suspended), [`plan_upgrade_required`](#plan_upgrade_required), [`demo_restricted`](#demo_restricted) | No. |
| 404 | [`not_found`](#not_found), [`plan_not_found`](#plan_not_found) | No. |
| 413, 415 | [`payload_too_large`](#payload_too_large), [`unsupported_media_type`](#unsupported_media_type) | No. Fix the body. |
| 429 | [`rate_limited`](#rate_limited), [`quota_exceeded`](#quota_exceeded) | Yes, after `Retry-After`. |
| 500, 501 | [`internal_error`](#internal_error), [`not_implemented`](#not_implemented) | 500: yes. 501: no. |
| 503 | [`busy`](#busy), [`timeout`](#timeout) | Yes, after `Retry-After`. |

In a batch, an item that fails validation does not fail the call: it carries its own `error` with `type`, `title` and `detail`. See [Batch checks](https://inplan.io/docs/batch-checks).

## Every problem type

### 400 invalid_request

**When:** A parameter is missing or invalid: no `npi` or `plan_id`, a bad `year`, `state`, `market`, `zip`, `limit` or `offset`, or a batch body that is not `{"items": [...]}` JSON.

**What to do:** Fix the request. `detail` names the parameter.

Response (400 Bad Request · application/problem+json):

```json
{
  "type": "invalid_request",
  "title": "Missing parameter",
  "status": 400,
  "detail": "`plan_id` is required.",
  "instance": "/v1/check",
  "request_id": "req_xS54q-lq-95-CNO7",
  "docs": "https://inplan.io/docs/errors#invalid_request"
}
```

### 400 invalid_npi

**When:** The NPI is not 10 digits, or fails its check digit.

**What to do:** Check the NPI for a typo. Send it as a string.

Response (400 Bad Request · application/problem+json):

```json
{
  "type": "invalid_npi",
  "title": "Invalid NPI",
  "status": 400,
  "detail": "\"1234567890\" fails the NPI check digit (Luhn with prefix 80840).",
  "instance": "/v1/check",
  "request_id": "req_tyeV9VkOEHSgXbbW",
  "docs": "https://inplan.io/docs/errors#invalid_npi"
}
```

### 400 invalid_plan_id

**When:** The plan id matches neither the marketplace nor the Medicare Advantage format.

**What to do:** See [Plans and plan years](https://inplan.io/docs/plans-and-plan-years#ids) for the formats.

### 400 invalid_cursor

**When:** The `cursor` was changed, or belongs to another plan.

**What to do:** Pass `page.next_cursor` from the previous page unchanged.

Response (400 Bad Request · application/problem+json):

```json
{
  "type": "invalid_cursor",
  "title": "Invalid cursor",
  "status": 400,
  "detail": "Pass the next_cursor value from the previous page unchanged.",
  "instance": "/v1/plans/29276OH0970001/providers",
  "request_id": "req_kicZeaYEQF_Xcf0U",
  "docs": "https://inplan.io/docs/errors#invalid_cursor"
}
```

### 400 batch_too_large

**When:** A batch has more than 100 items.

**What to do:** Split it into batches of 100 or fewer. A rejected batch still counts its first 100 items.

Response (400 Bad Request · application/problem+json):

```json
{
  "type": "batch_too_large",
  "title": "Batch too large",
  "status": 400,
  "detail": "At most 100 pairs per call; got 101.",
  "instance": "/v1/check/batch",
  "request_id": "req_hxtwDDAeyVY4wVMP",
  "docs": "https://inplan.io/docs/errors#batch_too_large"
}
```

### 400 depth_limit

**When:** Paging through a plan's providers reached 5,000 listings.

**What to do:** Narrow with `state`, `zip` or `specialty`, or ask us about data files.

### 401 unauthorized

**When:** The `Authorization` header is missing or malformed, or the key is unknown or revoked.

**What to do:** Send `Authorization: Bearer ip_live_...` with an active key.

Response (401 Unauthorized · application/problem+json):

```json
{
  "type": "unauthorized",
  "title": "Invalid API key",
  "status": 401,
  "detail": "The key is unknown or revoked.",
  "instance": "/v1/check",
  "request_id": "req_zH72k5VrnZm8eUI0",
  "docs": "https://inplan.io/docs/errors#unauthorized"
}
```

### 403 account_suspended

**When:** The account behind the key is not active.

**What to do:** Write to support.

### 403 plan_upgrade_required

**When:** The endpoint is not in the plan of this key: batch needs Builder, plan-to-provider search needs Growth. The body adds `current_plan` and `required_plan`.

**What to do:** Move to a larger plan, or use single checks.

Response (403 Forbidden · application/problem+json):

```json
{
  "type": "plan_upgrade_required",
  "title": "Plan upgrade required",
  "status": 403,
  "detail": "This endpoint needs the builder plan or higher; this key is on free.",
  "instance": "/v1/check/batch",
  "request_id": "req_RL1ifh22It4kUXjz",
  "docs": "https://inplan.io/docs/errors#plan_upgrade_required",
  "current_plan": "free",
  "required_plan": "builder"
}
```

### 403 demo_restricted

**When:** The Playground demo key was used for an NPI outside its sample list.

**What to do:** Use a sample NPI, or create a free key for any NPI.

Response (403 Forbidden · application/problem+json):

```json
{
  "type": "demo_restricted",
  "title": "Demo key restriction",
  "status": 403,
  "detail": "The playground key works only for the sample NPIs. Create a free key for any NPI.",
  "instance": "/api/v1/check",
  "request_id": "req_mW3y_sM0mgptQFPy",
  "docs": "https://inplan.io/docs/errors#demo_restricted",
  "sample_npis": [
    "1376006148",
    "1427468453",
    "1306032347",
    "1538462239",
    "1629458435"
  ]
}
```

### 404 not_found

**When:** We hold no provider record and no plan listing for this NPI.

**What to do:** Check the NPI. A valid NPI can still be unknown to us.

Response (404 Not Found · application/problem+json):

```json
{
  "type": "not_found",
  "title": "Provider not found",
  "status": 404,
  "detail": "No provider found for NPI 1999999984.",
  "instance": "/v1/providers/1999999984",
  "request_id": "req_eHYrIWCixJ4RIl52",
  "docs": "https://inplan.io/docs/errors#not_found"
}
```

### 404 plan_not_found

**When:** We hold no plan with this id (or no plan year you asked for) on `/v1/plans`.

**What to do:** Check the id and `year`. `/v1/check` answers `not_found` instead of 404 for an unknown plan.

Response (404 Not Found · application/problem+json):

```json
{
  "type": "plan_not_found",
  "title": "Plan not found",
  "status": 404,
  "detail": "No plan found for 99999OH0010001.",
  "instance": "/v1/plans/99999OH0010001",
  "request_id": "req_yJz9v1z9Xg6vHNi9",
  "docs": "https://inplan.io/docs/errors#plan_not_found"
}
```

### 413 payload_too_large

**When:** A request body is over 64 KB.

**What to do:** Send fewer items in each batch.

### 415 unsupported_media_type

**When:** A batch request does not have `Content-Type: application/json`.

**What to do:** Set the header.

Response (415 Unsupported Media Type · application/problem+json):

```json
{
  "type": "unsupported_media_type",
  "title": "JSON required",
  "status": 415,
  "detail": "Send `Content-Type: application/json`.",
  "instance": "/v1/check/batch",
  "request_id": "req_zdyooaUKchC18Eiy",
  "docs": "https://inplan.io/docs/errors#unsupported_media_type"
}
```

### 429 rate_limited

**When:** More requests a second than the key allows.

**What to do:** Wait `Retry-After` seconds, then retry. Not counted against your quota.

Response (429 Too Many Requests · application/problem+json):

```json
{
  "type": "rate_limited",
  "title": "Too many requests",
  "status": 429,
  "detail": "This key allows 2 requests per second.",
  "instance": "/v1/coverage",
  "request_id": "req_TrHd8LO8HNbLoZ_D",
  "docs": "https://inplan.io/docs/errors#rate_limited"
}
```

### 429 quota_exceeded

**When:** Your account used its calls for this month (all its keys share them), or a batch needs more calls than are left. The body adds `quota`, `used`, `cost` and `resets_at`.

**What to do:** Wait for the reset on the 1st of the month, UTC (`Retry-After` holds the seconds), or move to a larger plan. Never billed.

### 500 internal_error

**When:** Something failed on our side.

**What to do:** Retry. If it repeats, send us the `request_id`. Not counted against your quota.

### 501 not_implemented

**When:** Plan-to-provider search was called with a Medicare Advantage plan id.

**What to do:** Use `/v1/check` or `/v1/providers/{npi}/plans` for Medicare Advantage plans.

Response (501 Not Implemented · application/problem+json):

```json
{
  "type": "not_implemented",
  "title": "Available for Marketplace plans",
  "status": 501,
  "detail": "Provider search by plan is available for Marketplace plans. For Medicare Advantage plans use /v1/check or /v1/providers/{npi}/plans.",
  "instance": "/v1/plans/H2526-001-000/providers",
  "request_id": "req_91oTGyIEJwKXhH2R",
  "docs": "https://inplan.io/docs/errors#not_implemented"
}
```

### 503 busy

**When:** The API is under heavy load or paused for maintenance.

**What to do:** Retry after `Retry-After` seconds. Not counted against your quota.

### 503 timeout

**When:** A lookup took too long.

**What to do:** Retry after `Retry-After` seconds. Not counted against your quota.
