Keragon connector
The Blue Banana EHR connector in Keragon holds one of your API keys: its actions call the FHIR API and its triggers register webhook subscriptions.
Every write — from a workflow, the API, the MCP server or the clinician workspace — fires the same subscriptions. Schemas are in the API reference; quotas under Limits.
1 · Connect
- Create a named API key on /account. The Playground key has a lower rate limit.
- In Keragon: Authentications → Create new → Blue Banana EHR, paste the key, save.
- Everything runs in the key owner's tenant:
tenantin trigger payloads, theX-EHR-Tenant-Resolvedresponse header.
2 · Triggers
- Publishing a workflow calls
POST /api/subscriptionswith Keragon's signal URL as thehttpdestination; unpublishing deletes it. - Each enabled trigger uses one subscription from the tenant quota.
- List them with
GET /api/subscriptionsor the MCP toollist_webhook_subscriptions. - Payloads:
criteria.matchedfor write triggers,template.firedfor timed ones — fields in Webhooks · Payload.
| Component | Subscription trigger | Notes |
|---|---|---|
| Patient created | criteria · Patient · meta.versionId = '1' | Every new Patient in your tenant, whatever wrote it. |
| Patient updated | criteria · Patient · meta.versionId != '1' | Payload adds data.previous and data.changes for branching on what changed. |
| Appointment created | criteria · Appointment · meta.versionId = '1' | Patient is data.resource.participant[0].actor.reference (Patient/<id>). |
| Appointment updated | criteria · Appointment · meta.versionId != '1' | Any change, including status transitions. |
| Before appointment starts | template · appointment_reminder · offsetMinutes | Once per appointment at start − offset. The connector offers 30, 60 or 1440 minutes; for another lead time register the subscription yourself (§5). |
3 · Actions
Paths are relative to https://bluebananaehr.com/api/fhir/r4. Writes count against the tenant write quota and fire subscriptions like any API write.
| Component | Request | Notes |
|---|---|---|
| Get patient | GET /Patient/{id} | The raw FHIR Patient. |
| Get patients | GET /Patient?family=&given=&name=&birthdate=&gender=&identifier=&_lastUpdated= | Name searches are prefix matches on each name part. For phone, email, _count or _offset, use an HTTP step. |
| Get patient chart | GET /Patient/{id}/$everything | Every resource in the patient compartment. Can be large. |
| Get appointment | GET /Appointment/{id} | — |
| Get appointments | GET /Appointment?date=&status=&patient=&practitioner=&_lastUpdated= | For patient details in the same call, add _include=Appointment:patient in an HTTP step. |
| Create appointment | POST /Appointment | Inputs: patient, status, start, end, description, duration, practitioner. |
| Create patient | POST /Patient | Family and given name required; gender, birth date, phone, email and address optional. |
| Update patient | PUT /Patient/{id} | Replaces the whole record: blank inputs clear fields. Run Get patient first and pass every field, or PATCH from an HTTP step. |
| Update appointment | PUT /Appointment/{id} | Replaces the whole record, like Update patient. |
| Delete appointment | DELETE /Appointment/{id} | To cancel instead, PATCH { "status": "cancelled" } from an HTTP step. |
| Create clinical document | POST /DocumentReference | Hosted URL or Base64. Fires note.created. A document with docStatus: final (HTTP step) fires note.signed. |
| Create observation | POST /Observation | LOINC code plus a numeric or text value. |
4 · Configuration notes
- Ids, not references. Actions take a bare id (
1a44bf5d-…). Triggers give references (Patient/1a44bf5d-…). Write actions accept either, since the API collapsesPatient/Patient/…toPatient/…; Get actions need the bare id. - Blank optional inputs are safe. The API drops
nullproperties on every write. A blank required field is still a400. - Update actions replace. Read first and send everything back, or
PATCHfrom an HTTP step (§6). - Keep appointment text Latin-1 (e.g.
-, not an em dash) so the appointment pickers in Update and Delete appointment load. - Timestamps are UTC,
YYYY-MM-DDTHH:mm:ssZ. Dates areYYYY-MM-DD. - Synthetic data only. Every resource carries
http://bluebananaehr.com/synthetic-data = true. Never route it into a real clinical workflow.
5 · More triggers: register a subscription
Create a Keragon Webhook trigger, then register a subscription pointing at its URL (with curl or an HTTP step). This is what the connector does on publish.
curl -X POST https://bluebananaehr.com/api/subscriptions \
-H "Authorization: Bearer bb_…" \
-H "Content-Type: application/json" \
-d '{
"name": "Appointment cancelled → Keragon",
"trigger": { "kind": "event", "events": ["appointment.cancelled"] },
"destination": { "kind": "http", "url": "https://webhooks.us-1.keragon.com/…" }
}'One event trigger can list several of the 47 named events. Fields and ranges for every kind: Webhooks · Trigger kinds. To check a subscription fires before wiring Keragon, point it at https://bluebananaehr.com/api/webhooks/echo.
| Component | Subscription trigger | Notes |
|---|---|---|
| Appointment booked / cancelled / rescheduled / completed / no-show | event · appointment.booked | .cancelled | .rescheduled | .completed | .no_show | Status events fire when the status becomes that value. |
| Patient arrived / checked in | event · appointment.arrived | appointment.checked_in | Fired by front-desk check-in in /app or a status PATCH. |
| Form submitted | event · form.submitted | A completed QuestionnaireResponse. |
| Lab result / note signed / encounter finished | event · lab_result.created | lab_result.final | note.signed | encounter.finished | — |
| Inbox task / order / referral / prescription / insurance / claim / charge / invoice / payment | event · task.created | order.created | referral.created | medication.prescribed | coverage.* | claim.* | charge.created | invoice.* | payment.received | Fired by the matching FHIR write. |
| Appointment reminder, any lead time | template · appointment_reminder · offsetMinutes | — |
| No-show (timed) | template · appointment_no_show · offsetMinutes | After start, only if still booked. |
| Patient birthday / every day at / cron | template · patient_birthday | daily_at · hourUtc; cron · expression | One delivery per patient for birthdays. |
| Any resource write | criteria · resourceType, interactions, changed, fhirpath | Any of the 43 resource types. |
6 · Do more with an HTTP step
Keragon's HTTP request step reaches the whole API. Send Authorization: Bearer bb_… and, with a body, Content-Type: application/json. FHIR paths are relative to https://bluebananaehr.com/api/fhir/r4; /api/… paths to https://bluebananaehr.com.
| Component | Request | Notes |
|---|---|---|
| Search / read / create / delete any resource | GET /{type}?… · GET /{type}/{id} · POST /{type} · DELETE /{type}/{id} | Any of the 43 resource types. |
| Partial update | PATCH /{type}/{id} | application/merge-patch+json: only the fields you send change; null removes a field. JSON Patch (application/json-patch+json) also works. |
| Find available slots | GET /Appointment/$find?practitioner=&start=&end=&duration= | Free Slots as a Bundle. Default: next 7 days, 30 minutes. Pass any returned id to Create appointment as the Slot ID. |
| Cancel / reschedule / check in / check out / no-show | PATCH /Appointment/{id} { status } (+ start, end to reschedule) | Each fires the matching appointment.* event. |
| Providers / visit types / locations | GET /Practitioner?name= · GET /HealthcareService · GET /Location?name= | Visit types: New Patient 45, Follow Up 20, Annual Physical 30, Sick Visit 15, Telehealth 20. Locations: Cambridge, Boston, Telehealth. |
| Send a form / read responses / submit | POST /api/forms/links · GET /QuestionnaireResponse?patient= · POST /api/forms/submit | Links are signed and valid 30 days. Submissions write a QuestionnaireResponse. |
| Create / complete inbox task | POST /Task · PATCH /Task/{id} { "status": "completed" } | Category in code.coding[0], system http://bluebananaehr.com/inbox-category: message, refill-request, result-review, general. Shows in /app/inbox. |
| Check insurance eligibility | POST /api/eligibility/$check { patient_id, coverage_id?, payer_id?, member_id? } | Deterministic mock 270/271 response. |
| Clinical writes | POST /ServiceRequest · /MedicationRequest · /AllergyIntolerance · /Condition · /Encounter · GET /DiagnosticReport | Standard FHIR R4 shapes. |
| Billing | POST /ChargeItem · /Invoice · /PaymentReconciliation · GET /Claim?patient= | — |
| Webhook delivery log | GET /api/subscriptions/{id}/deliveries | Status code, duration and error per attempt. |
7 · Verify a workflow end to end
- Publish, then confirm the subscription:
GET /api/subscriptions. - Cause the event: book an appointment in /app/schedule, through the API, or through the MCP server (its write tools report which triggers fired).
- Check delivery:
GET /api/subscriptions/{id}/deliveries. A 2xx means Keragon accepted it. - Check the effect: the run in Keragon, and the resource in /app or via
GET /{type}/{id}.
For graded, repeatable checks, use the testing scenarios.