# Providers in a plan

`GET https://api.inplan.io/v1/plans/{plan_id}/providers`

The providers a marketplace plan lists, page by page, with filters for state, ZIP and radius, and specialty. Each provider carries the network tiers the directory names.

Growth plan and up · 1 call per page. Source: https://inplan.io/docs/api/plan-providers

## When to use it

Use it to build provider search inside a plan, for example "cardiologists near 43230 in this plan". For Medicare Advantage plans, use [`GET /v1/check`](https://inplan.io/docs/api/check) or [`GET /v1/providers/{npi}/plans`](https://inplan.io/docs/api/provider-plans). Paging is described in [Pagination](https://inplan.io/docs/pagination).

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `plan_id` | path | string | Required | A marketplace plan id. Medicare Advantage ids answer `501`. Example: `29276OH0970001`. |
| `state` | query | string | Optional | Only providers with a practice location in this state. Example: `OH`. |
| `specialty` | query | string | Optional | Part of a specialty name, any case, for example `cardio`. Example: `cardio`. |
| `zip` | query | string | Optional | A 5-digit ZIP. Without `radius`: providers with a location in this ZIP. Example: `43230`. |
| `radius` | query | integer | Optional | Miles from the center of `zip`, 1 to 100. Needs `zip`. Example: `10`. |
| `year` | query | integer | Optional | The plan year of the listings. Default: the newest year we hold. Example: `2026`. |
| `limit` | query | integer · default 50 · max 100 | Optional | Providers per page. With filters a page can hold fewer. |
| `cursor` | query | string | Optional | `page.next_cursor` from the previous page, unchanged. |

## Request

curl:

```bash
curl https://api.inplan.io/v1/plans/29276OH0970001/providers \
  -H "Authorization: Bearer $INPLAN_KEY" \
  -G -d limit=2
```

JavaScript:

```javascript
const url = new URL("https://api.inplan.io/v1/plans/29276OH0970001/providers");
url.search = new URLSearchParams({ limit: "2" });

const res = await fetch(url, {
  headers: { Authorization: `Bearer ${process.env.INPLAN_KEY}` },
});
const body = await res.json();
console.log(body.data.providers, body.data.page.next_cursor);
```

Python:

```python
import os, requests

res = requests.get(
    "https://api.inplan.io/v1/plans/29276OH0970001/providers",
    params={"limit": "2"},
    headers={"Authorization": f"Bearer {os.environ['INPLAN_KEY']}"},
    timeout=10,
)
body = res.json()
print(body["data"]["providers"], body["data"]["page"]["next_cursor"])
```

## Response fields

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

| Field | Type | Description |
| --- | --- | --- |
| `plan_id` | string | The plan id. |
| `plan_year` | integer | The plan year of these listings. |
| `plan_name` | string | The plan name. |
| `issuer` | object | The insurer. |
| `issuer.id` | string | The 5-digit insurer id. |
| `issuer.name` | string | The insurer name. |
| `filters` | object | The filters you sent (`null` when not sent). |
| `filters.state` | string \| null | State filter. |
| `filters.zip` | string \| null | ZIP filter. |
| `filters.radius` | integer \| null | Radius in miles around `zip`. |
| `filters.specialty` | string \| null | Specialty filter, in upper case. |
| `providers` | object[] | Providers on this page, in directory order. |
| `providers[].npi` | string | The NPI. |
| `providers[].name` | string \| null | Display name with credential. |
| `providers[].credential` | string \| null | The credential as published. |
| `providers[].primary_specialty` | string \| null | The primary specialty. |
| `providers[].network_tiers` | string[] | Tiers the directory names for this provider in this plan. |
| `providers[].locations` | object[] | Up to 5 practice locations that match your filters. |
| `providers[].locations[].city` | string | City. |
| `providers[].locations[].state` | string | State. |
| `providers[].locations[].zip` | string | ZIP code. |
| `providers[].locations[].distance_miles` | number \| null | Miles from the `zip` you sent, when you sent `radius`. Else `null`. |
| `providers[].profile_found` | boolean | `true` when we hold identity details for this NPI. |
| `page` | object | Paging state. See [Pagination](https://inplan.io/docs/pagination). |
| `page.limit` | integer | The page size you asked for. |
| `page.rows_scanned` | integer | Listing rows read for this page. |
| `page.scanned_through` | integer | Listing rows read so far, across pages. |
| `page.max_depth` | integer | The most listing rows paging reads for one plan. |
| `page.next_cursor` | string \| null | Pass it as `cursor` for the next page. `null` on the last page. |
| `source` | object | The source type and date of these listings. |
| `source.type` | string | Always `insurer_directory`. |
| `source.as_of` | date | The date we read the directory. |

## Responses

### 200

A page of providers. Pass `page.next_cursor` as `cursor` for the next page.

Response (200 OK · application/json):

```json
{
  "request_id": "req_k-SKujLq8DN5VkZE",
  "data_as_of": "2026-10-29",
  "data": {
    "plan_id": "29276OH0970001",
    "plan_year": 2026,
    "plan_name": "Anthem Bronze Pathway 10600 ($0 Virtual PCP + $0 Select Drugs)",
    "issuer": {
      "id": "29276",
      "name": "Anthem Blue Cross and Blue Shield"
    },
    "filters": {
      "state": null,
      "zip": null,
      "radius": null,
      "specialty": null
    },
    "providers": [
      {
        "npi": "1457438566",
        "name": "Pamella J. Kibbe, NP",
        "credential": "NP",
        "primary_specialty": "Nurse Practitioner",
        "network_tiers": [
          "PARTICIPATING"
        ],
        "locations": [
          {
            "city": "Columbus",
            "state": "OH",
            "zip": "43214",
            "distance_miles": null
          }
        ],
        "profile_found": true
      },
      {
        "npi": "1154167203",
        "name": "Morgan E. Brockhouse, DMD",
        "credential": "DMD",
        "primary_specialty": "Dentist",
        "network_tiers": [
          "PARTICIPATING"
        ],
        "locations": [
          {
            "city": "East Peoria",
            "state": "IL",
            "zip": "61611",
            "distance_miles": null
          }
        ],
        "profile_found": true
      }
    ],
    "page": {
      "limit": 2,
      "rows_scanned": 2,
      "scanned_through": 2,
      "max_depth": 5000,
      "next_cursor": "eyJvIjoyLCJ5IjoyMDI2LCJwIjoiMjkyNzZPSDA5NzAwMDEifQ"
    },
    "source": {
      "type": "insurer_directory",
      "as_of": "2026-07-27"
    }
  },
  "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": "provider_registry",
      "description": "National provider registry and practice records",
      "as_of": "2026-10-29"
    }
  ],
  "notes": [
    "With filters a page can hold fewer than `limit` providers. Follow next_cursor until it is null.",
    "Network directories change. Confirm with the plan or the provider before care."
  ]
}
```

### 200 filtered

With `specialty=cardio`.

Response (200 OK · application/json):

```json
{
  "request_id": "req_LIWkkbLXmx_TZSaD",
  "data_as_of": "2026-10-29",
  "data": {
    "plan_id": "29276OH0970001",
    "plan_year": 2026,
    "plan_name": "Anthem Bronze Pathway 10600 ($0 Virtual PCP + $0 Select Drugs)",
    "issuer": {
      "id": "29276",
      "name": "Anthem Blue Cross and Blue Shield"
    },
    "filters": {
      "state": null,
      "zip": null,
      "radius": null,
      "specialty": "CARDIO"
    },
    "providers": [
      {
        "npi": "1023120250",
        "name": "Jayanta T. Mukherjee, MD",
        "credential": "MD",
        "primary_specialty": "Cardiovascular Disease (cardiology)",
        "network_tiers": [
          "PARTICIPATING"
        ],
        "locations": [
          {
            "city": "Kettering",
            "state": "OH",
            "zip": "45429",
            "distance_miles": null
          }
        ],
        "profile_found": true
      }
    ],
    "page": {
      "limit": 2,
      "rows_scanned": 200,
      "scanned_through": 200,
      "max_depth": 5000,
      "next_cursor": "eyJvIjoyMDAsInkiOjIwMjYsInAiOiIyOTI3Nk9IMDk3MDAwMSJ9"
    },
    "source": {
      "type": "insurer_directory",
      "as_of": "2026-07-27"
    }
  },
  "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": "provider_registry",
      "description": "National provider registry and practice records",
      "as_of": "2026-10-29"
    }
  ],
  "notes": [
    "With filters a page can hold fewer than `limit` providers. Follow next_cursor until it is null.",
    "Network directories change. Confirm with the plan or the provider before care."
  ]
}
```

### 400

A changed or foreign cursor (`invalid_cursor`), paging past 5,000 listings (`depth_limit`), or an invalid filter.

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

### 403

The key is on Free or Builder. Plan-to-provider search starts on Growth.

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

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

### 501

A Medicare Advantage plan id.

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

## Errors

Errors use `application/problem+json` (RFC 7807): `type`, `title`, `status`, `detail`, `instance`, `request_id`, `docs`. Other statuses this endpoint can return: `401`, `404` (`plan_not_found`), `429` and `503`. The Playground demo key cannot call this endpoint. 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).
