Repository navigation
24 API Design
The HealthBook AI API (internal code name: BabyCare) is a JSON-over-HTTPS REST API served by one FastAPI application. The web app, the Android app, the home camera worker, the external scheduler and the public doctor-share page all use it. The route decorators define 187 handlers: 34 in api/main.py and 153 across twelve routers. This page describes the conventions they share and catalogues the endpoints by domain.
- Give every family profile a predictable, scoped address space:
/api/patients/{pid}/.... - Make writes safe to retry (idempotency keys, client keys) and safe under concurrent caregivers (version checks).
- Use status codes consistently, so the clients can tell validation errors, conflicts and throttling apart.
- Never return secrets or storage internals.
as_jsonstrips password and token hashes,storage_name,sha256andextracted_cipher.
| Topic | Rule |
|---|---|
| Prefix | Everything is under /api. Password reset lives under /api/auth/password-reset. The static web app is served from /. |
| Profile-scoped collections |
/api/patients/{pid}/<collection> for create and list. The handler calls own_patient(db, user, pid) first. |
| Resource paths |
/api/<resource>/{id} for read, update and actions (/api/medicines/{mid}/confirm, /api/hospital-visits/{vid}/reschedule). own_resource derives the profile from the row's patient_id. |
| Actions | State changes are POST .../<verb>: confirm, stop, verify, withdraw, reschedule, disable, action. Entries are withdrawn, not DELETEd, wherever history matters. |
| Auth: mobile |
Authorization: Bearer <token>, returned by /api/auth/login with client: "mobile". |
| Auth: web |
client: "web" sets the babycare_session cookie (HttpOnly, SameSite=Strict, Secure in production, 14 days). Every non-GET cookie request must send X-Requested-With: BabyCare, or it gets 403 CSRF check failed. |
| Other credentials |
X-Scheduler-Key (internal scheduler), X-Camera-Worker-Key (camera worker), X-Share-Pin (doctor link PIN). |
| Local clock times | Appointment and administration times are naive local times in the profile's timezone. A UTC suffix gets 422, and nonexistent or ambiguous DST times are rejected. |
| Idempotency |
medication_events.idempotency_key is unique per medicine, and replaying the key returns the existing event. treatment_administrations.idempotency_key and antibiotic_administrations.idempotency_key are globally unique, and reusing a key on another visit gets 409. Daily Care and vitals entries accept a client_key, and a duplicate returns the existing row with existing: true. |
| Optimistic concurrency |
PUT /api/documents/{did}/review and POST .../review/confirm carry version. The update runs WHERE version = :v AND status = 'needs_review', and a lost race gets 409 "Another caregiver changed this review. Reload it." Other mutable rows increment version on every change. |
| Downloads | Binary responses set Content-Disposition. X-Document-Count is exposed for share ZIPs. Mobile clients can use GET variants that take a base64url spec. |
| Code | Meaning in this API |
|---|---|
| 400 | Malformed input, a damaged or password-protected file, or a source document from another profile |
| 401 | No session, invalid or expired session, wrong camera worker key, missing or incorrect share PIN |
| 403 | CSRF header missing, origin not allowed, read-only caregiver writing, non-guardian action, scheduler key rejected |
| 404 | Not found, including profiles the caller cannot access (existence is not revealed) |
| 409 | Conflict: duplicate upload (sha256 or source_ref), possible duplicate vaccine dose (the response lists the candidates; resend with duplicate_confirmed), review already confirmed or changed, event against an unverified medicine, idempotency key reuse, device registered to another account |
| 410 | Doctor link expired or revoked |
| 413 / 415 | File or body too large; unsupported file type |
| 422 | Validation failed, including domain rules (source document required before confirmation, dates out of range or in the future). Review confirmation returns {message, errors:[{row, page, field, reason}]}. |
| 429 | Rate limit (Retry-After: 60), or 8 failed PIN attempts on a doctor link within 15 minutes |
| 502 / 503 | Upstream vision provider failed; storage, OCR, push or email unavailable. Nothing is saved partially. |
sequenceDiagram
participant C as Client
participant M as Middleware
participant A as require_user
participant H as Handler
participant D as Database
C->>M: POST with cookie and X-Requested-With
M->>M: origin check, rate window, size limit
M-->>C: 429 plus Retry-After when throttled
M->>A: forward request
A->>D: look up session by token hash
A->>H: user with write flag
H->>D: own_patient check then validation
H->>D: UPDATE where version matches
D-->>H: rowcount
H-->>C: 200, or 409 when version changed
Paths are relative to /api. {pid} is a profile id. Methods are listed as they appear on the decorators.
| Domain | Endpoints |
|---|---|
| Auth |
POST auth/register, POST auth/login, POST auth/logout, GET me, POST auth/password-reset/request (202, generic answer), POST auth/password-reset/check, POST auth/password-reset/confirm, POST account/delete
|
| Profiles and family |
POST/GET patients, PATCH patients/{pid}, GET profiles/options, GET/PATCH patients/{pid}/profile, PUT patients/{pid}/modules, POST patients/{pid}/invitations, POST invitations/accept, GET patients/{pid}/family, DELETE patients/{pid}/family/{access_id}
|
| Documents |
POST/GET patients/{pid}/documents, PATCH documents/{id}, GET documents/{id}/download, GET documents/{did}/pages/{page}, GET documents/{did}/thumbnail, POST documents/{did}/signed-access, GET files/{ticket}, GET documents/{did}/links
|
| OCR and review |
POST documents/{id}/extract, GET documents/{id}/extraction, GET/PUT documents/{did}/review, POST documents/{did}/review/confirm, GET ai/provider, POST documents/{did}/vision-extract (consent required) |
| Medicines |
POST/GET patients/{pid}/medicines, GET/PATCH medicines/{mid}, POST medicines/{mid}/confirm, GET medicines/{mid}/revisions, POST medicines/{mid}/events, POST medicines/{mid}/stop, GET patients/{pid}/medication-history
|
| Vaccines |
GET/POST patients/{pid}/vaccines, PATCH vaccines/{vid}, GET patients/{pid}/vaccine-reference, POST patients/{pid}/vaccine-reference/import, GET patients/{pid}/vaccination-chart, GET patients/{pid}/vaccination-chart.csv
|
| Labs |
POST/GET patients/{pid}/observations, GET patients/{pid}/lab-trends, GET patients/{pid}/lab-series, GET patients/{pid}/labs.csv
|
| Admissions and visits |
POST/GET patients/{pid}/admissions, PATCH admissions/{aid}, POST/GET patients/{pid}/hospital-visits, PATCH hospital-visits/{vid}, POST patients/{pid}/hospital-visit-series, POST hospital-visits/{vid}/reschedule, POST hospital-visits/{vid}/administrations, GET patients/{pid}/administrations
|
| Episodes |
POST/GET patients/{pid}/episodes, GET patients/{pid}/episode-comparison
|
| Growth | POST/GET patients/{pid}/growth |
| Vitals |
POST/GET patients/{pid}/vitals, GET patients/{pid}/vitals/summary, PATCH vitals/{eid}, POST vitals/{eid}/withdraw
|
| History, timeline, Ask |
GET patients/{pid}/today, GET patients/{pid}/timeline, GET patients/{pid}/search, GET patients/{pid}/dashboard, GET patients/{pid}/history, POST patients/{pid}/ask, GET patients/{pid}/doctor-summary, GET patients/{pid}/record-revisions, GET patients/{pid}/audit (guardian) |
| Daily Care (generic) |
POST/GET patients/{pid}/care/{kind}, PATCH care/{kind}/{eid}, POST care/{kind}/{eid}/withdraw, GET care/{kind}/{eid}/history. Each kind is one of the typed journal schemas (fluid, diaper, stool, medicine, symptom, activity, sleep). |
| Daily Care (views) |
GET patients/{pid}/care/day, PUT patients/{pid}/care/day/{day}/note, GET .../care/timeline, GET .../care/calendar/month, GET .../care/calendar/week, GET .../care/analytics, GET .../care/illnesses, GET .../care/compare, GET .../care/export, GET/PUT .../care/settings, POST .../care/ask, POST .../care/medicine/quick, GET .../care/medicines/today
|
| Stool photos |
POST care/stool/{eid}/photos, POST/GET patients/{pid}/care/stool/intake, GET patients/{pid}/care/stool/photos, GET care/stool-intake/{iid}/image, POST care/stool-intake/{iid}/confirm, DELETE care/stool-intake/{iid}, GET/DELETE care/stool-photos/{photo_id}, POST care/stool/{eid}/observation-review
|
| Lifetime |
GET patients/{pid}/lifetime/{dashboard,fever,antibiotics,illnesses,ecoli,correlation,scan,review-tables,summary,evidence,parent-entries}, POST patients/{pid}/lifetime/{evidence,fever,antibiotics,parent-entries,import-transcription,ask}, PATCH lifetime/fever/{fid}, POST lifetime/fever/{fid}/verify, PATCH lifetime/antibiotics/{cid}, POST lifetime/antibiotics/{cid}/verify, POST lifetime/antibiotics/{cid}/administrations, PATCH lifetime/parent-entries/{eid}, POST lifetime/parent-entries/{eid}/withdraw, GET lifetime/drug-check
|
| Export |
GET export/presets, POST patients/{pid}/export/preview, POST/GET patients/{pid}/export/download, GET patients/{pid}/export/debug.txt, GET patients/{pid}/export (guardian ZIP of all records and originals) |
| Share with Doctor |
GET share/presets, POST patients/{pid}/share/preview, POST/GET patients/{pid}/share/package.zip, POST/GET patients/{pid}/share/summary.pdf, POST/GET patients/{pid}/share/links, GET share/links/{sid}/log, DELETE share/links/{sid}
|
| Public doctor link |
GET share/public/{token}, GET share/public/{token}/document/{n}, GET share/public/{token}/summary.pdf, GET share/public/{token}/package.zip. No session; token plus optional X-Share-Pin. |
| Reminders, notifications, devices |
GET patients/{pid}/reminders, GET patients/{pid}/notifications, POST notifications/{nid}/action (acknowledge or snooze), POST/DELETE devices, DELETE devices/{did}, GET push/web/config, POST/DELETE push/web/subscribe
|
| Camera |
GET/POST patients/{pid}/cameras, PUT/PATCH/DELETE cameras/{cid}, POST cameras/{cid}/{disable,test,worker-key,purge-recordings}, GET cameras/{cid}/preview, GET cameras/{cid}/worker-config and POST cameras/{cid}/worker/ingest (worker key), GET patients/{pid}/camera-observations, POST camera-observations/{oid}/review, POST camera-observations/{oid}/add-to-journal, GET patients/{pid}/camera-analytics
|
| Internal scheduler |
POST internal/scheduler/tick, GET internal/status. Both require an X-Scheduler-Key of at least 24 characters; the feature returns 404 when no key is configured. |
| Health |
GET health. It skips the rate limiter and the database and returns {ok, mode, medical_device: false}. |
-
POST documents/{id}/extractonly ever setsneeds_review. OCR-extracted ≠ clinically verified, and OCR never activates reminders. -
POST medicines/{mid}/confirmrequires a linked source document and doctor-written instructions. AnyPATCHreturns the medicine todraft. -
PATCH hospital-visits/{vid}changes appointment status only. A treatment administration is a separate endpoint that requires a source document. - Vaccine reference imports create unconfirmed rows only, and no reminders are generated until a row is confirmed against a card.
-
POST notifications/{nid}/actionacknowledges or snoozes a notification; it never records a dose.
api/main.py, api/workflows.py, api/care_api.py, api/lifetime_api.py, api/share.py, api/camera_api.py, api/history_api.py, api/export_api.py, api/vitals_api.py, api/profiles_api.py, api/providers.py, api/cloud.py, api/password_reset.py, api/security.py
Backend Architecture · Authentication and Session Security · Family Profile Isolation · OCR and Human Verification Workflow · Share With Doctor Architecture · Security and Privacy Model
Overview
Platform
Identity and access
Medical records
- 10 Document Ingestion
- 11 OCR and Human Verification
- 13 Medicines and Administration
- 14 Vaccination Model
- 15 Labs, Growth, Longitudinal
- 16 Illness and Lifetime Health
Daily care
Output and sharing
Security
Engineering
- 26 Testing and Validation
- 27 Deployment and CI/CD
- 28 Technology Stack
- 29 Design Decisions
- 30 Limitations
- 31 Roadmap