Consent
Consent Ledger: signed receipts and lifecycle webhooks your backend can verify.
Versioned consent receipts and signed, retryable webhooks for every grant, revocation, and sync.
The patient authorizes FinchNode to collect the requested categories, then separately consents to share what is available with your application. Each sharing decision is a versioned receipt you can fetch by ID, and consent, sync, record-change, revocation, expiry, and deletion events arrive as signed, retryable webhooks.
What it is
Built for: Teams that need to know exactly what each patient authorized and react when that consent changes.
Base URL: https://api.finchnode.com/api/v1
Authentication: Send an app-scoped key as a Bearer token from your backend: Authorization: Bearer ck_test_... for sandbox keys, which read only sandbox connections, or Authorization: Bearer ck_live_... for live keys, which read only production connections and which eligible applications create in the self-service console. Keys are hashed at rest, revocable, and must never be embedded in browser or mobile code.
Create a free account to get sandbox keys: https://finchnode.com/signup
At a glance
- Status
- Available
- Auth
- Sandbox or live API key
- Contract
- OpenAPI 3.1
- Authenticated MCP endpoint (API key)
https://api.finchnode.com/api/mcp
Documents for this product
Try it in 30 seconds
Set FINCHNODE_API_KEY once in the shell that runs these commands or starts your agent client (replace ck_test_... with your sandbox key; it is the only key value to substitute)
export FINCHNODE_API_KEY=ck_test_...
Fetch a consent receipt
curl https://api.finchnode.com/api/v1/consents/$RECEIPT_ID -H "Authorization: Bearer $FINCHNODE_API_KEY"
RECEIPT_ID is a consent receipt ID. Receipt IDs are available in record responses, as consent.receiptIds on each health_record, and in webhook events. GET /users lists the app’s subjects in cursor pages; follow nextCursor while hasMore is true.
Expected response: 200 with the receipt: requested categories, effective shared categories, sync status, source watermark, granted scopes, expiry, and revocation status.
For coding agents
Three ways in for a coding agent: connect the MCP endpoint below, load the OpenAPI document (https://finchnode.com/openapi.yaml), or fetch this page as markdown (https://finchnode.com/products/consent-ledger.md). https://finchnode.com/llms.txt lists every product’s markdown twin.
Authenticated MCP endpoint (API key)
- MCP endpoint
https://api.finchnode.com/api/mcp- Transport
- Streamable HTTP (JSON-RPC over POST)
- Auth
- Authorization: Bearer ck_test_... (sandbox keys) or Authorization: Bearer ck_live_... (live keys)
- Clients
- Server-side and desktop MCP clients only; the endpoint is not CORS-enabled
- MCP Registry name
- com.finchnode/health-records
Tools at https://api.finchnode.com/api/mcp
Claude Code
claude mcp add --scope project --transport http finchnode https://api.finchnode.com/api/mcp --header 'Authorization: Bearer ${FINCHNODE_API_KEY}'
Claude Code writes this server to the project's .mcp.json, which is meant to be checked into version control and shared with the project, and expands ${FINCHNODE_API_KEY} when it connects, so the file never holds the key: set FINCHNODE_API_KEY in the shell that runs Claude Code.
Codex CLI
codex mcp add finchnode --url https://api.finchnode.com/api/mcp --bearer-token-env-var FINCHNODE_API_KEY
Cursor (.cursor/mcp.json)
{
"mcpServers": {
"finchnode": {
"url": "https://api.finchnode.com/api/mcp",
"headers": {
"Authorization": "Bearer ${env:FINCHNODE_API_KEY}"
}
}
}
}
Machine-readable resources
How it works
Get a sandbox subject
Create a Connect session with a sandbox key (POST /connect/sessions, with the body Hosted Connect documents; its id is SESSION_ID). A sandbox session needs no real patient: either open its hosted url yourself and choose one of the FinchNode Scenario Sandbox organizations listed above the search, which connects a synthetic source without a hospital sign-in (the account and consent steps are unchanged), or POST /connect/sessions/{sessionId}/simulate with a scenario and poll the session until simulation.state is completed. Either way the completed session exposes the subject (its id is SUBJECT), and GET /users lists the app’s subjects.
curl -X POST https://api.finchnode.com/api/v1/connect/sessions/$SESSION_ID/simulate -H "Authorization: Bearer $FINCHNODE_API_KEY" -H "Content-Type: application/json" -d '{"scenario":"baseline-adult"}'
Receive lifecycle events
Your application’s lifecycle webhook URL receives eight event types: consent.granted, consent.revoked, consent.expired, deletion.requested, sync.completed, sync.partial, sync.failed, and records.updated. Events are written to the outbox before network delivery. Set the lifecycle and sync webhook URL on the application in the console under Applications, when you create it (New application) or with Edit on its Configuration tab; once a URL is saved, the Webhook signatures panel on that tab reveals and rotates the signing secret.
POST {your lifecycle webhook URL}
FinchNode-Event-Id: evt_...
FinchNode-Signature: t={unix seconds},v1={hex HMAC-SHA256}
Content-Type: application/json
Verify the signature on the raw body
Compute HMAC-SHA256 with your webhook secret over the timestamp, a period, and the exact raw request body, and compare it with each v1 value in constant time. Reject a timestamp more than 300 seconds from now. Secret rotation invalidates the previous version immediately.
expected = hex(HMAC_SHA256(FINCHNODE_WEBHOOK_SECRET, t + "." + rawBody))
valid = timingSafeEqual(expected, v1) and abs(now - t) <= 300
Deduplicate and acknowledge quickly
Delivery is at least once, so deduplicate on FinchNode-Event-Id. Return any 2xx within five seconds and queue slow work in your own system. FinchNode retries failures with backoff, moves exhausted events to a dead-letter state, and supports replay from the application console.
HTTP/1.1 204 No Content
Stop reading when consent ends
Once all relevant share consent is revoked or expired, every read returns 410 consent_inactive, including category and change-feed routes. Stop reading and apply your deletion and retention policy.
curl -i "https://api.finchnode.com/api/v1/users/$SUBJECT/records" -H "Authorization: Bearer $FINCHNODE_API_KEY" # 410 consent_inactive once all relevant share consent is inactive
Reference
The webhook payload and its signature headers are described under webhooks.finchnodeEvent in the OpenAPI document.
Endpoints| Method | Path | OpenAPI operationId |
|---|
| GET | https://api.finchnode.com/api/v1/consents/{receiptId} | getConsentReceipt |
What it does not do
- It does not deliver exactly once: delivery is at least once, so deduplicate on FinchNode-Event-Id.
- It does not keep an old webhook secret valid after rotation: update the stored secret as soon as the rotation response is returned.
- It never records a share receipt while sync is unfinished or when none of the requested categories are shareable.
- It does not keep serving reads once all relevant share consent is revoked or expired: every read returns 410 consent_inactive.
Frequently asked questions
What is the difference between the two consents?
The patient first authorizes FinchNode to collect the requested categories and signs in at the source. After the import, the patient reviews what is actually available and gives a separate sharing consent to your application. The receipts the API returns record that sharing decision (action: share), and every read checks them again.
Which webhook events does FinchNode send?
consent.granted, consent.revoked, consent.expired, deletion.requested, sync.completed, sync.partial, sync.failed, and records.updated.
How do I verify a FinchNode webhook?
Read t and v1 from FinchNode-Signature, compute HMAC-SHA256 with your webhook secret over the timestamp, a period, and the exact raw body, compare in constant time, and reject a timestamp more than 300 seconds from now. Then deduplicate on FinchNode-Event-Id.
What happens when my endpoint is down?
FinchNode retries failures with backoff, moves exhausted events to a dead-letter state, and supports replay from the application console. Return any 2xx within five seconds and queue slow work in your own system.