Patient-authorized EHR integration
After the patient connects
Tie a finished session to your own user by storing the session ID when you create it and reading the subject when it completes.
The patient finishes on FinchNode's pages, not yours. Your server learns the result from FinchNode, never from the browser.
Store the session when you create it
Save three values with your user before you send the patient to url:
| Value | Where it comes from |
|---|---|
| Your user's ID | Your own system |
sessionId |
The id in the create response |
externalId |
What you sent, if anything |
Learn when sharing is approved
Only success is pushed. Use the webhook, the session, or both.
The consent.granted webhook arrives after the patient approves sharing. Verify its signature first, then match its data.sessionId to the row you stored. This abbreviated, synthetic event shows the fields you'll use:
{
"id": "evt_9f2c4b1a0d7e6c5b3a21",
"object": "event",
"type": "consent.granted",
"createdAt": "2026-09-30T18:04:12.000Z",
"data": {
"subject": "u_4f3a9c1e2b7d6a05",
"receiptId": "rcpt_3F9A1C0B7E2D",
"sessionId": "cs_4b2e9d0c7a1f5e3d8c6b",
"externalId": "user_123",
"environment": "sandbox",
"categories": ["medications", "labs"],
"requestedCategories": ["medications", "labs", "allergies"],
"missingCategories": ["allergies"],
"syncMode": "one-time"
}
}
missingCategories lists what you asked for that this share doesn't include: the patient didn't approve it, or the source couldn't provide it. A patient who connects two health systems produces one consent.granted for each, with the same sessionId.
Webhooks are delivered in the background, so one can arrive a little after the session already reads completed.
Reading the session works without a webhook. GET /connect/sessions/{sessionId} returns status: "completed" and the subject once sharing is approved.
Handle cancel, expiry, and partial imports
No webhook fires for these. Read the session from your server:
| You see | Means | Do this |
|---|---|---|
canceled |
The patient or your server canceled. | Offer to try again with a new session. |
expired |
Nobody finished within 24 hours. | Create a new session when the user returns. |
pending |
They haven't started, or they left on the first screen. | It may still be open in their tab. Check again later. |
completed with sync.status: "partial" |
Some categories didn't arrive. | Use what arrived; missingCategories says what didn't. |
If nothing could be shared at all, the patient sees an error at the sharing step and the session doesn't complete.
Don't trust the return URL
Arriving at your returnUrl proves nothing. A patient who cancels is sent there straight away, or to FinchNode's home page if you didn't set one. A patient who finishes sees a "Return to" button with your app's name. FinchNode adds nothing to the URL, and anyone can open it.
On your return page, look up the session you stored and read its status from your server.
Never pick the first subject
GET /users returns a page of subjects who currently share with your app. Don't take the first one after a session completes; it may be someone else. Always use the subject from this session or its webhook.