# Batch check

`POST https://api.inplan.io/v1/check/batch`

The check answer for up to 100 provider-plan pairs in one call. Each pair is answered as a single check would be; a bad pair gets its own `error` and the rest still answer.

Builder plan and up · 1 call per item. Source: https://inplan.io/docs/api/check-batch

## When to use it

Use it for rosters: every doctor of an employee against every plan on offer, or a nightly re-check of saved pairs. See [Batch checks](https://inplan.io/docs/batch-checks) for counting and limits.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `items` | body | object[] · 1 to 100 | Required | The pairs to check. Each item: `npi` (string, required), `plan_id` (string, required), `year` (integer, optional). |
| `year` | body | integer | Optional | Default plan year for items without their own `year`. Example: `2026`. |

## Request

curl:

```bash
curl https://api.inplan.io/v1/check/batch \
  -H "Authorization: Bearer $INPLAN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items": [
        {"npi": "1184617268", "plan_id": "29276OH0970001"},
        {"npi": "1184617268", "plan_id": "H2526-001-000"}
      ]}'
```

JavaScript:

```javascript
const res = await fetch("https://api.inplan.io/v1/check/batch", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.INPLAN_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    items: [
      {
        npi: "1184617268",
        plan_id: "29276OH0970001"
      },
      {
        npi: "1184617268",
        plan_id: "H2526-001-000"
      }
    ]
  }),
});
const body = await res.json();
console.log(body.data.summary, body.data.results);
```

Python:

```python
import os, requests

res = requests.post(
    "https://api.inplan.io/v1/check/batch",
    json={
        "items": [
            {
                "npi": "1184617268",
                "plan_id": "29276OH0970001"
            },
            {
                "npi": "1184617268",
                "plan_id": "H2526-001-000"
            }
        ]
    },
    headers={"Authorization": f"Bearer {os.environ['INPLAN_KEY']}"},
    timeout=30,
)
body = res.json()
print(body["data"]["summary"])
```

## Response fields

Every response has the envelope `request_id`, `data_as_of`, `data`, `sources` and `notes`. Fields of `data`:

| Field | Type | Description |
| --- | --- | --- |
| `count` | integer | The number of items you sent. |
| `summary` | object | Counts of the answers in this batch. |
| `summary.listed` | integer | Items answered `listed`. |
| `summary.not_found` | integer | Items answered with `in_network: null`. |
| `summary.invalid` | integer | Items that failed validation and carry an `error`. |
| `results` | object[] | One result for each item, in the order you sent them. |
| `results[].index` | integer | The position of the item in your `items` array, starting at 0. |
| `results[].npi` | string | The NPI you checked. |
| `results[].plan_id` | string | The plan we checked. Marketplace ids are normalized to the 14-character plan id. |
| `results[].input_plan_id` | string | The plan id exactly as you sent it. |
| `results[].market` | string | `aca` for marketplace plans, `ma` for Medicare Advantage plans. |
| `results[].plan_years_listed` | integer[] | Plan years in which the directory lists the provider for this plan. |
| `results[].in_network` | true \| null | `true`: the directory lists the provider for this plan. `null`: no listing found in current directory data. It is never a statement that the provider is out of network. |
| `results[].answer` | string | `listed`, `not_found`, or `no_provider_network` for a prescription drug plan id (contract ids that start with S). |
| `results[].explanation` | string | One plain sentence that states the answer. Safe to show to users as it is. |
| `results[].evidence` | object[] | One entry for each listing we found. Empty when the answer is `not_found`. |
| `results[].evidence[].plan_id` | string | The plan of this listing. |
| `results[].evidence[].plan_year` | integer | The plan year of this listing. |
| `results[].evidence[].network_tier` | string | Marketplace plans: the tier the directory names, for example `PARTICIPATING` or `PREFERRED`. Several tiers are joined with commas. |
| `results[].evidence[].source` | object | Where this listing comes from. |
| `results[].evidence[].source.type` | string | `insurer_directory` for marketplace plans, `plan_directory` for Medicare Advantage plans. |
| `results[].evidence[].source.as_of` | date | The date we read that directory. |
| `results[].evidence[].accepting_new_patients` | boolean \| null | Medicare Advantage plans: whether the directory says the provider accepts new patients (`null` when it does not say). |
| `results[].evidence[].provider_kind` | string | Medicare Advantage plans: the kind of provider listed, for example `practitioner`. |
| `results[].plan_year` | integer \| null | The plan year this answer is about: the `year` you sent, else the newest year listed, else the newest plan year we hold. |
| `results[].plan` | object \| null | Plan details. `null` when we hold no details for this plan id. |
| `results[].plan.plan_name` | string | The plan name as the insurer publishes it. |
| `results[].plan.issuer` | object | Marketplace plans: the insurer. |
| `results[].plan.issuer.id` | string | The 5-digit insurer id (the first 5 characters of the plan id). |
| `results[].plan.issuer.name` | string | The insurer name. |
| `results[].plan.state` | string | Marketplace plans: the state the plan is sold in. |
| `results[].plan.metal_level` | string | Marketplace plans: Bronze, Expanded Bronze, Silver, Gold, Platinum or Catastrophic. |
| `results[].plan.plan_type` | string | HMO, PPO, EPO, POS and similar. |
| `results[].plan.variant` | string \| null | Marketplace plans: the 2-digit variant you sent (for example `01`), else `null`. |
| `results[].plan.organization` | string | Medicare Advantage plans: the organization that offers the plan. |
| `results[].plan.service_area_states` | string[] | Medicare Advantage plans: the states in the plan's service area. |
| `results[].source` | object | The source type of the answer and its date. |
| `results[].source.type` | string | `insurer_directory` or `plan_directory`. |
| `results[].source.as_of` | date \| null | The date we read the directory that gave this answer. |
| `results[].as_of` | date \| null | The date we read the directory that gave this answer (same as `source.as_of`). |
| `results[].error` | object | Only on an item that failed validation. The other fields of a check are then absent. |
| `results[].error.type` | string | The problem type, for example `invalid_npi`. |
| `results[].error.title` | string | A short summary. |
| `results[].error.detail` | string | What is wrong with this item. |

## Responses

### 200

One result for each item, in order. `summary` counts `listed`, `not_found` and `invalid` items.

Response (200 OK · application/json):

```json
{
  "request_id": "req_KHtLEQJ46JLKLkZZ",
  "data_as_of": "2026-10-29",
  "data": {
    "count": 4,
    "summary": {
      "listed": 2,
      "not_found": 1,
      "invalid": 1
    },
    "results": [
      {
        "index": 0,
        "npi": "1184617268",
        "plan_id": "29276OH0970001",
        "input_plan_id": "29276OH0970001",
        "market": "aca",
        "plan_years_listed": [
          2026
        ],
        "in_network": true,
        "answer": "listed",
        "explanation": "The insurer's network directory lists this provider for this plan.",
        "evidence": [
          {
            "plan_id": "29276OH0970001",
            "plan_year": 2026,
            "network_tier": "PARTICIPATING",
            "source": {
              "type": "insurer_directory",
              "as_of": "2026-07-27"
            }
          }
        ],
        "plan_year": 2026,
        "plan": {
          "plan_name": "Anthem Bronze Pathway 10600 ($0 Virtual PCP + $0 Select Drugs)",
          "issuer": {
            "id": "29276",
            "name": "Anthem Blue Cross and Blue Shield"
          },
          "state": "OH",
          "metal_level": "Bronze",
          "plan_type": "HMO",
          "variant": null
        },
        "source": {
          "type": "insurer_directory",
          "as_of": "2026-07-27"
        },
        "as_of": "2026-07-27"
      },
      {
        "index": 1,
        "npi": "1184617268",
        "plan_id": "H2526-001-000",
        "input_plan_id": "H2526-001-000",
        "market": "ma",
        "plan_years_listed": [
          2027
        ],
        "in_network": true,
        "answer": "listed",
        "explanation": "The plan's network directory lists this provider for this plan.",
        "evidence": [
          {
            "plan_id": "H2526-001-000",
            "plan_year": 2027,
            "accepting_new_patients": true,
            "provider_kind": "practitioner",
            "source": {
              "type": "plan_directory",
              "as_of": "2026-10-29"
            }
          }
        ],
        "plan_year": 2027,
        "plan": {
          "plan_name": "DEVOTED CHOICE 001 OH (PPO)",
          "organization": "Devoted Health",
          "plan_type": "PPO",
          "service_area_states": [
            "OH"
          ]
        },
        "source": {
          "type": "plan_directory",
          "as_of": "2026-10-29"
        },
        "as_of": "2026-10-29"
      },
      {
        "index": 2,
        "npi": "1376006148",
        "plan_id": "13262AR0230002",
        "input_plan_id": "13262AR0230002",
        "market": "aca",
        "plan_years_listed": [],
        "in_network": null,
        "answer": "not_found",
        "explanation": "No listing found in current directory data for this provider and plan.",
        "evidence": [],
        "plan_year": 2026,
        "plan": {
          "plan_name": "HA Silver AH",
          "issuer": {
            "id": "13262",
            "name": "Health Advantage"
          },
          "state": "AR",
          "metal_level": "Silver",
          "plan_type": "POS",
          "variant": null
        },
        "source": {
          "type": "insurer_directory",
          "as_of": "2026-10-28"
        },
        "as_of": "2026-10-28"
      },
      {
        "index": 3,
        "npi": "1234567890",
        "plan_id": "29276OH0970001",
        "error": {
          "type": "invalid_npi",
          "title": "Invalid NPI",
          "detail": "\"1234567890\" fails the NPI check digit (Luhn with prefix 80840)."
        }
      }
    ]
  },
  "sources": [
    {
      "type": "insurer_directory",
      "description": "Provider network directories published by health insurers",
      "as_of": "2026-10-29"
    },
    {
      "type": "plan_catalog",
      "description": "Published health plan catalogs",
      "as_of": "2026-10-28"
    },
    {
      "type": "plan_directory",
      "description": "Provider network directories published by Medicare Advantage plans",
      "as_of": "2026-10-29"
    }
  ],
  "notes": [
    "in_network=null means no listing was found in current directory data. It is not a statement that the provider is out of network.",
    "Network directories change. Confirm with the plan or the provider before care."
  ]
}
```

### 400

More than 100 items (`batch_too_large`), or a body without an `items` array (`invalid_request`).

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"
}
```

### 401

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

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

```json
{
  "type": "unauthorized",
  "title": "Missing API key",
  "status": 401,
  "detail": "Send `Authorization: Bearer ip_live_...`.",
  "instance": "/v1/check/batch",
  "request_id": "req_GeDGBDA_JgNwi3Hq",
  "docs": "https://inplan.io/docs/errors#unauthorized"
}
```

### 403

The key is on the Free plan. Batch checks start on Builder.

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"
}
```

### 415

The `Content-Type` is not `application/json`.

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"
}
```

## Errors

Errors use `application/problem+json` (RFC 7807): `type`, `title`, `status`, `detail`, `instance`, `request_id`, `docs`. Other statuses this endpoint can return: `413` (body over 64 KB), `429` (rate limit or quota; a batch is refused whole when the quota cannot cover it) and `503` (busy or timed out; the batch is not counted). See [Errors](https://inplan.io/docs/errors).

## Rate-limit headers

Every response that passes the key and plan checks carries `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`, `RateLimit-Policy`, `X-Quota-Limit`, `X-Quota-Remaining`, `X-Quota-Reset` and `X-Request-Id`. See [Rate limits and quotas](https://inplan.io/docs/rate-limits).
