Production access is free and self-serve with an account. · Synthetic demo · no account needed

FinchNode

Patient-authorized EHR integration

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.

Create one

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):

{
  "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:

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

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.