# Delegated agent credentials

> Hand an agent a short-lived credential for one patient and a few categories instead of your app key.

Your app key can read every patient who shares with your app. When an agent only needs one, delegate a narrower credential from your server. Delegated credentials work with the REST API, not the [MCP server](/docs/ai-agents/mcp-server).

## Create one

```bash
TOKEN_FILE=$(mktemp)
RESPONSE=$(curl -X POST "https://api.finchnode.com/api/v1/agent-credentials" -s --fail-with-body \
  -H "Authorization: Bearer $FINCHNODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "u_4f3a9c1e2b7d6a05",
    "categories": ["medications"],
    "purpose": "Summarize current medications",
    "operations": ["records:read"],
    "durationSeconds": 900
  }') &&
  printf '%s' "$RESPONSE" | jq -er .access_token > "$TOKEN_FILE" &&
  printf '%s' "$RESPONSE" | jq 'del(.access_token)'
```

The token goes to a private temporary file, and only the rest of the response is printed. The subject in that example is synthetic.

| Field | Rules |
| --- | --- |
| `subject` | One patient who shares with your app. An unknown subject returns `404 not_found`. |
| `categories` | Categories that patient shares. If some aren't shared, you get `403 consent_scope_exceeded`; if none are, `410 consent_inactive`. An unknown name returns `400 invalid_categories`. |
| `purpose` | Why the agent needs it, up to 500 characters. The patient can see it, so leave out names, dates, and clinical details. |
| `operations` | Any of `records:read`, `changes:read`, `receipts:read`. Defaults to all three. |
| `durationSeconds` | A whole number from 1 to 3600. Defaults to 900. |

## Use the response

Without the capture, you'd get a `201` like this (synthetic):

```json
{
  "access_token": "fn_agent_...",
  "token_type": "Bearer",
  "expires_in": 900,
  "grant_id": "0b7e4c2a-9d31-4f6e-8a52-3c1d7e9f4b60",
  "credential_id": "5f2a8d1c-6b43-4e7a-9c05-e8d3b2a1f794",
  "scope": "records:medications"
}
```

- `access_token` appears once. Store it on your server.
- Save `credential_id`; you need it to revoke.
- Give the token to the agent's HTTP client through an environment variable, never in a prompt. Anything in a prompt can end up in transcripts and logs.
- Add `fn_agent_` to the patterns your secret scanning looks for.

The agent then reads with it:

```bash
export FINCHNODE_AGENT_TOKEN=$(cat "$TOKEN_FILE")
curl "https://api.finchnode.com/api/v1/users/$SUBJECT/records/medications" \
  -H "Authorization: Bearer $FINCHNODE_AGENT_TOKEN"
```

## Know its limits

- It reads only that subject, those categories, and those operations. Each read checks consent again.
- It can't list patients, create sessions, or delegate further.
- It doesn't create consent. The patient must already share those categories.
- It keeps the receipts it was created with. If the patient shares again later, delegate a new credential.
- It stops working when it expires, when you revoke it, or when you revoke the app key that created it.
- Delegated credentials for an app and environment share one rate limit.

## Revoke one

```bash
curl -X DELETE "https://api.finchnode.com/api/v1/agent-credentials/$CREDENTIAL_ID" \
  -H "Authorization: Bearer $FINCHNODE_API_KEY"
```

`$CREDENTIAL_ID` is the `credential_id` from the response. A `204` means it's revoked.

## Follow changes

A credential's snapshot has `meta.changeCursor: null`. Use `meta.changeCursors[category]`, or the `changeCursor` from a category page.
