# Child keys

URL: https://docs.healthcare.dev/child-keys

A child key is an extra key on your account that can do less than your account can: call only some
route groups, make fewer requests a second, and spend up to a monthly cap. Give one to each
customer, service or contractor, see what each one uses, and revoke it without touching your other
keys. Child keys are on Pro and Team; see [Plans](/plans).

Everything a child key does is your account's usage: its calls count toward your monthly calls,
your rate limit and your spend cap, and they appear on your invoice. Its own limits only ever apply
on top of the account's.

## Create one

Call `POST /v1/keys` with a parent key (any of your account's ordinary keys), or use the API keys
page in the dashboard.

```sh
curl -X POST https://api.healthcare.dev/v1/keys \
  -H "Authorization: Bearer $HDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Clinic",
    "scopes": ["codes", "drugs"],
    "rps_limit": 5,
    "monthly_cap_cents": 2000
  }'
```

The response's `data.key` is the full key. It is shown this once and never stored; save it now. The
SDK has `client.keys.create(...)`, `list`, `get`, `update` and `revoke`.

| Field               | What it does                                                                                                                                                                                                                                         |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`              | What the key is for. Required.                                                                                                                                                                                                                       |
| `env`               | `live` (default) or `test`. Test child keys get test-key limits and are never billed.                                                                                                                                                                |
| `scopes`            | Route groups the key may call. Leave it out for every group but `webhooks`.                                                                                                                                                                          |
| `rps_limit`         | Requests a second for this key. At most your account's own limit, which still applies; a higher value is refused with `400`.                                                                                                                         |
| `monthly_cap_cents` | This key's spend per UTC month, in cents: its billable calls at your plan's per-call rate (Pro: 0.15 cents a call). Leave it out for no cap of its own. Live keys only (test keys are never billed). Calls made before a cap is set count toward it. |

## Scopes

A scope is a route group: the first path segment after `/v1/`.

| Scope                | Routes                                                                                                         |
| -------------------- | -------------------------------------------------------------------------------------------------------------- |
| `codes`              | `/v1/codes/...`                                                                                                |
| `drugs`              | `/v1/drugs/...` (NDC, RxNorm, NADAC, ASP, labels, safety)                                                      |
| `providers`          | `/v1/providers/...` (including enrollment, opt-out and exclusion checks by NPI)                                |
| `exclusions`         | `/v1/exclusions` (search OIG exclusions by name)                                                               |
| `taxonomies`         | `/v1/taxonomies/...`                                                                                           |
| `coverage`           | `/v1/coverage/...` and `/v1/policies/...` (a coverage policy's history)                                        |
| `care-categories`    | `/v1/care-categories/...`                                                                                      |
| `search`             | `/v1/search`                                                                                                   |
| `datasets`           | `/v1/datasets/...`                                                                                             |
| `changes`            | `/v1/changes`                                                                                                  |
| `issues`             | `/v1/issues` (report a data issue)                                                                             |
| `webhooks`           | `/v1/webhooks/...` (manage the account's [webhooks](/webhooks)); only when named, see below                    |
| `eval-packs`         | `/v1/eval-packs/...` ([eval packs](/eval-packs), Team)                                                         |
| `payers`             | `/v1/payers/...` ([payer prior authorization metrics](/datasets/payer-pa-metrics))                             |
| `prior-auth`         | `/v1/prior-auth` ([prior authorization requirements](/datasets/prior-auth), preview)                           |
| `medicare-advantage` | `/v1/medicare-advantage/...` ([Medicare Advantage internal criteria](/datasets/ma-internal-criteria), preview) |

A call outside the key's scopes gets `403` with `type` `https://healthcare.dev/problems/forbidden`,
a `detail` naming the missing scope and the scopes the key has, and `required_scope`:

```json
{
  "type": "https://healthcare.dev/problems/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "This key is missing the `providers` scope; it may call `codes`, `drugs`",
  "required_scope": "providers"
}
```

A key without scopes may call every route group except `webhooks`: managing webhooks changes the
account (where its data is sent), so a key gets it only when its scopes name it.

Scopes don't widen what the plan includes: a scoped key on Pro still can't call a Team feature.

## Limits and caps

- **Rate limit:** a child key's `rps_limit` applies first, then the account's limit, which all your
  keys share. `RateLimit-Limit` shows the key's own limit. Past either one: `429 rate-limited`.
- **Monthly cap:** when a key's calls this month reach its cap, its billable calls get `429` with
  `type` `https://healthcare.dev/problems/spend-cap-reached`, the same answer as the account's own
  spend cap. Raise or remove the cap (`PATCH /v1/keys/{id}`) and calls resume at once. Free routes
  such as `/v1/status` keep working.
- **Account caps** still apply to every child key: the account's spend cap and monthly calls.

`GET /v1/keys` and `GET /v1/keys/{id}` show each key's `month_to_date` calls and spend, updated
every few minutes.

## Change or revoke

```sh
curl -X PATCH https://api.healthcare.dev/v1/keys/3f1c9a52-6b0e-4d7a-9c2e-8a4b7d1e0f63 \
  -H "Authorization: Bearer $HDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scopes": ["codes"], "monthly_cap_cents": null}'

curl -X DELETE https://api.healthcare.dev/v1/keys/3f1c9a52-6b0e-4d7a-9c2e-8a4b7d1e0f63 \
  -H "Authorization: Bearer $HDEV_API_KEY"
```

Send only the fields to change; `null` removes a limit. Changes apply within 30 seconds, and a
revoked key stops working within 30 seconds. Revoking a parent key doesn't affect the child keys it
created: they belong to the account.

## Who can manage keys

Only parent keys and the dashboard. A child key calling `/v1/keys` gets `403 forbidden`, so a key
you hand out can't make more keys or lift its own limits. An account can hold 100 active child
keys, apart from its other keys.

## If you move below Pro

Your child keys are kept, with every setting, but they stop working: their calls get
`403 plan-upgrade-required` naming Pro. You can still list and revoke them with a parent key or in
the dashboard. Move back to Pro or Team and they work again, unchanged. They never keep working
without their scopes and limits, since that would quietly give a key you handed out more access
than you granted.

## Errors

| Status | `type`                  | When                                                                       |
| ------ | ----------------------- | -------------------------------------------------------------------------- |
| `400`  | `invalid-request`       | A bad field, an unknown scope, or an `rps_limit` above the account's limit |
| `403`  | `plan-upgrade-required` | Creating or changing child keys below Pro, or using a child key below Pro  |
| `403`  | `forbidden`             | A child key calling `/v1/keys`, or a route outside the key's scopes        |
| `404`  | `not-found`             | No child key with that id on your account                                  |
| `409`  | `conflict`              | The account already holds 100 active child keys                            |
| `429`  | `spend-cap-reached`     | The key's monthly cap (or the account's spend cap) is reached              |

Managing keys is free on every plan: `/v1/keys` calls are never metered.
