# Blue Banana EHR — LLM context pack Drop this file into a fresh LLM session and it has enough context to integrate against the Blue Banana FHIR R4 sandbox without fetching anything else. Working surface only; experimental endpoints are listed at the end with one-line redirects to the docs. Spec version: 0.1.0 Base URL: `https://bluebananaehr.com` ## Auth & tenancy - Every authed request needs `Authorization: Bearer bb_…` (an API key minted on `/account`). - Tenant is implicit: derived from the key. No `X-EHR-Tenant` header to set. - Successful responses echo the resolved tenant in `X-EHR-Tenant-Resolved`. - Per-key rate limit: `30 req/min` production keys, `10 req/min` playground keys. Headers `X-RateLimit-{Limit,Remaining,Reset}` are returned on every response; 429 carries `Retry-After`. ## Reference patient - John Smith, id `eb1f768e-226a-c047-0f2f-8331341167c2`, birthDate 1948-01-11. Every prefilled example targets this patient. - ~1,000 Synthea-generated patients in the seed pool. Search by family name (`?family=Smith` / `Shanahan` / `Casper`). ## Synthetic data marker - Every resource carries `extension: [{ "url": "http://bluebananaehr.com/synthetic-data", "valueBoolean": true }]`. Treat it as a hard signal that the resource MUST NOT be used in clinical workflows. ## Errors Every 4xx/5xx is a FHIR `OperationOutcome` with `issue[]`. Common codes: `security` (401), `forbidden` (403), `not-found` (404), `business-rule` (422), `throttled` (429). ## Working endpoints - `POST /api/eligibility/$check` — Run a mock 270/271 eligibility check - `GET /api/fhir/r4/Appointment` — List John's upcoming appointments - `GET /api/fhir/r4/Appointment/{id}` — Read a single Appointment - `GET /api/fhir/r4/Patient` — Search patients - `GET /api/fhir/r4/Patient/{id}` — Read John Smith's record - `GET /api/fhir/r4/Patient/{id}/$everything` — Patient $everything (full chart) - `GET /api/fhir/r4/metadata` — CapabilityStatement - `GET /api/fhir/r4/{resourceType}` — Search resources of a given type - `POST /api/fhir/r4/{resourceType}` — Create a resource - `DELETE /api/fhir/r4/{resourceType}/{id}` — Delete a resource - `GET /api/fhir/r4/{resourceType}/{id}` — Read a single resource - `PUT /api/fhir/r4/{resourceType}/{id}` — Update (upsert) a resource - `POST /api/inspector/{tenant}/{token}` — Capture a webhook delivery in the simulator's inspector - `POST /api/intake/{formId}/submissions` — Submit an intake form (anonymous) - `GET /api/intake/{formId}/subscriptions` — List my subscriptions on this form - `POST /api/intake/{formId}/subscriptions` — Create a webhook subscription for this form - `DELETE /api/intake/{formId}/subscriptions/{id}` — Delete a subscription - `PATCH /api/intake/{formId}/subscriptions/{id}` — Rename or toggle a subscription - `POST /api/patient-sim/email` — Simulate an inbound email to a patient - `POST /api/patient-sim/sms` — Simulate an inbound SMS to a patient - `GET /api/subscriptions` — List subscriptions for the tenant - `POST /api/subscriptions` — Create a subscription - `DELETE /api/subscriptions/{id}` — Delete a subscription - `GET /api/subscriptions/{id}` — Read a subscription - `PUT /api/subscriptions/{id}` — Replace a subscription For the `/{resourceType}` and `/{resourceType}/{id}` catchall routes, the supported resource types are advertised by the live `GET /api/fhir/r4/metadata` CapabilityStatement — 31 R4 types in total (Patient, Encounter, Observation, Condition, MedicationRequest, MedicationAdministration, AllergyIntolerance, Immunization, Procedure, DiagnosticReport, CarePlan, CareTeam, Goal, Practitioner, Organization, Location, Device, ImagingStudy, Coverage, Claim, ExplanationOfBenefit, SupplyDelivery, Appointment, Schedule, Slot, DocumentReference, Communication, Provenance, QuestionnaireResponse, Task, ServiceRequest). All five interactions (search, read, create, update, delete) verified working on every type. ## Experimental — not currently working The following endpoints are documented for forward compatibility but reject bearer-API-key auth or fail validation against every published example. Do not build against them. See the full OpenAPI spec at `https://bluebananaehr.com/openapi.json` for shapes. - `POST /api/agent` - `GET /api/agent/runs` - `GET /api/agent/runs/stream` Outbound webhook payload shapes (`criteria.matched`, `intake.submission.created`, `template.fired`) are documented in the OpenAPI spec but are not currently delivered. ## Examples (working surface only) ### allergy-intolerance-create Summary: POST /api/fhir/r4/AllergyIntolerance — body ```json { "resourceType": "AllergyIntolerance", "clinicalStatus": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical", "code": "active" } ] }, "patient": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2" }, "code": { "coding": [ { "system": "http://snomed.info/sct", "code": "763875007", "display": "Penicillin" } ] }, "recordedDate": "2026-05-19" } ``` ### appointment-create Summary: POST /api/fhir/r4/Appointment — body ```json { "resourceType": "Appointment", "status": "booked", "start": "2026-05-20T15:00:00Z", "end": "2026-05-20T15:30:00Z", "participant": [ { "actor": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2", "display": "John Smith" }, "status": "accepted" } ] } ``` ### appointment-search-by-patient-response Summary: GET /api/fhir/r4/Appointment?patient={ref} — response Demo dev tenants get three near-future Appointments anchored at signup (`now + 2/7/32 min`); the IDs include a random suffix so this fixture shows the shape rather than the exact id. ```json { "resourceType": "Bundle", "type": "searchset", "total": 1, "link": [ { "relation": "self", "url": "https://bluebananaehr.com/fhir/r4/Appointment?patient=eb1f768e-226a-c047-0f2f-8331341167c2" } ], "entry": [ { "fullUrl": "https://bluebananaehr.com/fhir/r4/Appointment/demo-appt-1-abcd1234", "resource": { "resourceType": "Appointment", "id": "demo-appt-1-abcd1234", "status": "booked", "description": "Demo appointment for John Smith", "start": "2026-05-20T17:38:45Z", "end": "2026-05-20T18:08:45Z", "extension": [ { "url": "http://bluebananaehr.com/synthetic-data", "valueBoolean": true } ], "participant": [ { "actor": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2", "display": "John Smith" }, "status": "accepted" } ] }, "search": { "mode": "match" } } ] } ``` ### bundle-searchset-empty Summary: Empty searchset — no matches ```json { "resourceType": "Bundle", "type": "searchset", "total": 0, "link": [ { "relation": "self", "url": "https://bluebananaehr.com/fhir/r4/Patient?family=NonExistent" } ], "entry": [] } ``` ### condition-create Summary: POST /api/fhir/r4/Condition — body ```json { "resourceType": "Condition", "clinicalStatus": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/condition-clinical", "code": "active" } ] }, "subject": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2" }, "code": { "coding": [ { "system": "http://snomed.info/sct", "code": "44054006", "display": "Type 2 diabetes mellitus" } ] }, "recordedDate": "2026-05-19" } ``` ### encounter-create Summary: POST /api/fhir/r4/Encounter — body ```json { "resourceType": "Encounter", "status": "finished", "class": { "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "AMB", "display": "ambulatory" }, "subject": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2" }, "period": { "start": "2026-05-19T09:00:00Z", "end": "2026-05-19T09:30:00Z" } } ``` ### immunization-create Summary: POST /api/fhir/r4/Immunization — body ```json { "resourceType": "Immunization", "status": "completed", "patient": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2" }, "vaccineCode": { "coding": [ { "system": "http://hl7.org/fhir/sid/cvx", "code": "208", "display": "COVID-19 mRNA" } ] }, "occurrenceDateTime": "2026-04-15" } ``` ### medication-request-create Summary: POST /api/fhir/r4/MedicationRequest — body ```json { "resourceType": "MedicationRequest", "status": "active", "intent": "order", "subject": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2" }, "medicationCodeableConcept": { "coding": [ { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "860975", "display": "metformin 500 MG Oral Tablet" } ] }, "authoredOn": "2026-05-19" } ``` ### observation-create Summary: POST /api/fhir/r4/Observation — body ```json { "resourceType": "Observation", "status": "final", "subject": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2" }, "code": { "coding": [ { "system": "http://loinc.org", "code": "4548-4", "display": "Hemoglobin A1c" } ] }, "valueQuantity": { "value": 6.8, "unit": "%" }, "effectiveDateTime": "2026-05-19T10:00:00Z" } ``` ### observation-create-response Summary: POST /api/fhir/r4/Observation — 201 response Server adds the `id` (uuid) plus the synthetic-data extension. Response carries a `Location: /fhir/r4/Observation/{id}` header. ```json { "resourceType": "Observation", "id": "0e9d1a8a-aaaa-4b2b-9b1c-001122334455", "extension": [ { "url": "http://bluebananaehr.com/synthetic-data", "valueBoolean": true } ], "status": "final", "subject": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2" }, "code": { "coding": [ { "system": "http://loinc.org", "code": "4548-4", "display": "Hemoglobin A1c" } ] }, "valueQuantity": { "value": 6.8, "unit": "%" }, "effectiveDateTime": "2026-05-19T10:00:00Z" } ``` ### operation-outcome-401 Summary: 401 — missing or invalid Authorization header ```json { "resourceType": "OperationOutcome", "issue": [ { "severity": "error", "code": "security", "diagnostics": "Missing Authorization header. Send `Authorization: Bearer bb_…`." } ] } ``` ### operation-outcome-403 Summary: 403 — caller cannot access the requested tenant ```json { "resourceType": "OperationOutcome", "issue": [ { "severity": "error", "code": "forbidden", "diagnostics": "Your API key resolves but is not authorized for tenant `qa-acme`." } ] } ``` ### operation-outcome-404 Summary: 404 — resource not found in the tenant overlay ```json { "resourceType": "OperationOutcome", "issue": [ { "severity": "error", "code": "not-found", "diagnostics": "Patient/abc123 not found in tenant dev-xyz" } ] } ``` ### operation-outcome-422 Summary: 422 — validation failure ```json { "resourceType": "OperationOutcome", "issue": [ { "severity": "error", "code": "business-rule", "diagnostics": "criteria.resourceType must be one of: Appointment, QuestionnaireResponse, Patient, Encounter, Observation, Communication" } ] } ``` ### operation-outcome-429 Summary: 429 — rate limit / write quota exceeded ```json { "resourceType": "OperationOutcome", "issue": [ { "severity": "error", "code": "throttled", "diagnostics": "Visitor tenants are limited to 50 requests per minute. Try again in 30s." } ] } ``` ### patient-create Summary: POST /api/fhir/r4/Patient — request body A minimal Patient resource. Blue Banana accepts any valid FHIR R4 Patient; this fixture shows the typical shape Synthea would produce. ```json { "resourceType": "Patient", "name": [ { "use": "official", "family": "Smith", "given": [ "John" ] } ], "gender": "male", "birthDate": "1948-01-11" } ``` ### patient-everything-response Summary: GET /api/fhir/r4/Patient/{id}/$everything — response Bundle (searchset) with the Patient resource plus every resource that references it via `subject` or `patient`. ```json { "resourceType": "Bundle", "type": "searchset", "total": 3, "entry": [ { "fullUrl": "https://bluebananaehr.com/fhir/r4/Patient/eb1f768e-226a-c047-0f2f-8331341167c2", "resource": { "resourceType": "Patient", "id": "eb1f768e-226a-c047-0f2f-8331341167c2", "extension": [ { "url": "http://bluebananaehr.com/synthetic-data", "valueBoolean": true } ], "name": [ { "family": "Smith", "given": [ "John" ] } ] } }, { "fullUrl": "https://bluebananaehr.com/fhir/r4/Encounter/enc_001", "resource": { "resourceType": "Encounter", "id": "enc_001", "status": "finished", "subject": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2" }, "extension": [ { "url": "http://bluebananaehr.com/synthetic-data", "valueBoolean": true } ] } }, { "fullUrl": "https://bluebananaehr.com/fhir/r4/Observation/obs_001", "resource": { "resourceType": "Observation", "id": "obs_001", "status": "final", "subject": { "reference": "Patient/eb1f768e-226a-c047-0f2f-8331341167c2" }, "code": { "coding": [ { "system": "http://loinc.org", "code": "8480-6", "display": "Systolic BP" } ] }, "valueQuantity": { "value": 128, "unit": "mmHg" }, "extension": [ { "url": "http://bluebananaehr.com/synthetic-data", "valueBoolean": true } ] } } ] } ``` ### patient-read-response Summary: GET /api/fhir/r4/Patient/{id} — response A single Patient resource. Every resource returned by Blue Banana carries the `http://bluebananaehr.com/synthetic-data` extension. ```json { "resourceType": "Patient", "id": "eb1f768e-226a-c047-0f2f-8331341167c2", "extension": [ { "url": "http://bluebananaehr.com/synthetic-data", "valueBoolean": true } ], "name": [ { "use": "official", "family": "Smith", "given": [ "John" ] } ], "gender": "male", "birthDate": "1948-01-11" } ``` ### patient-search-response Summary: GET /api/fhir/r4/Patient?family=Smith — response ```json { "resourceType": "Bundle", "type": "searchset", "total": 1, "link": [ { "relation": "self", "url": "https://bluebananaehr.com/fhir/r4/Patient?family=Smith" } ], "entry": [ { "fullUrl": "https://bluebananaehr.com/fhir/r4/Patient/eb1f768e-226a-c047-0f2f-8331341167c2", "resource": { "resourceType": "Patient", "id": "eb1f768e-226a-c047-0f2f-8331341167c2", "extension": [ { "url": "http://bluebananaehr.com/synthetic-data", "valueBoolean": true } ], "name": [ { "use": "official", "family": "Smith", "given": [ "John" ] } ], "gender": "male", "birthDate": "1948-01-11" }, "search": { "mode": "match" } } ] } ```