Breathing in

TB Predict Kenya Research TB Program
Developer documentation

The TB Predict FHIR API

Read patients, observations and predictions as standard HL7 FHIR R4 resources — and request a prediction with a single operation.

At a glance

Standard
HL7 FHIR R4 (4.0.1)
Base URL
http://tbmldashboard.masterclass.co.ke/fhir/
Format
application/fhir+json
Authentication
Bearer token
Token lifetime
12 hours
Page size
50 by default, up to 1,000

Overview

TB Predict scores the risk that a patient's TB treatment ends badly, and keeps the record behind every score. Other systems — a patient management system, a data warehouse, a dashboard — use it through two APIs on the same database and the same prediction pipeline, so nothing can drift between them.

FHIR server /fhir/

HL7 FHIR R4. Every clinical read and write goes through it — this website's included: patients, observations, predictions, follow-ups, alerts, geography, the audit trail, scoring and register upload.

Core API /api/

What FHIR has no resources for: signing in, user administration, and the aggregate analytics — county roll-ups, facility anomaly detection, model evaluation and findings.

Quick start

Three steps from nothing to your first patient read.

  1. 1

    Get an account

    Request access for the facility, sub-county, county or national level your integration serves. A super-administrator approves it; the API then returns exactly the patients that level covers.

  2. 2

    Get a token

    Sign in with the account's username (or email) and password. The response carries a token.

    curl -X POST http://tbmldashboard.masterclass.co.ke/api/auth/login/ \
      -H "Content-Type: application/json" \
      -d '{"username": "your-username", "password": "your-password"}'
    
    # → { "token": "9f2c…", … }
  3. 3

    Call the FHIR server

    Send the token as a Bearer token. Find a patient by TB registration number, then fetch the whole record in one call.

    curl "http://tbmldashboard.masterclass.co.ke/fhir/Patient?identifier=TB123456" \
      -H "Authorization: Bearer <token>" \
      -H "Accept: application/fhir+json"
    
    curl "http://tbmldashboard.masterclass.co.ke/fhir/Patient/<id>/$everything" \
      -H "Authorization: Bearer <token>"

Authentication & access

  • Tokens. POST /api/auth/login/ returns one. Send it on every request as Authorization: Bearer <token> (the FHIR convention) or Authorization: Token <token> — both are accepted everywhere.
  • Expiry. A token stops working 12 hours after it is issued, whatever the activity. Signing in again issues a new one; POST /api/auth/logout/ revokes the current token at once.
  • Scope. Every clinical resource is limited to the account's access level — national, county, sub-county or facility. A record outside it answers 404, exactly like one that does not exist, so probing ids reveals nothing.
  • Audit. Every read of a patient's record is logged, and super-administrators can read the trail as AuditEvent resources.
  • Public, no token needed: /fhir/metadata, the conformance resources, Organization, Location, Device, $validate and /api/health/.
  • Browsers. The server sends no CORS headers: integrations are expected to call it from a server, not from a web page on another site.

Resources

Paths are relative to http://tbmldashboard.masterclass.co.ke/fhir/. Search parameters in the notes; the CapabilityStatement lists every one formally.

ResourceInteractionsAccessNotes
Patientread, search Token ?identifier=<TIBU number or national ID>, ?name=, ?organization=; _revinclude=RiskAssessment:subject.
Observationread, search Token ?patient= (required), &code=, &category= — model inputs, outcomes, lab, CD4, X-ray AI.
RiskAssessmentread, search Token Our predictions (numeric ids) and TIBU's (ids tibu-N). ?patient=, ?method=, ?method:not=, ?date=, ?probability=; _sort=-date; _include=RiskAssessment:subject.
Taskread, search, patch Token High-risk follow-ups. ?status=, ?business-status=, ?patient=; _include=Task:patient, Task:focus. PATCH takes JSON Patch on /status, /businessStatus and /note.
Flagread, search Token Patients whose latest prediction is at or above the alert cutoff, highest first. _include=Flag:patient, Flag:detail.
MedicationStatementread, search Token ?patient= — the TB regimen.
Conditionread, search Token ?patient= — comorbidities (carries a restricted security label).
Organizationread, search Public Facilities. ?name=, ?identifier=<MFL code>, ?address-state=<county>.
Locationread, search Public Counties (?partof:missing=true) and sub-counties (?partof=Location/county-N).
Deviceread Public Model versions.
AuditEventread, search Admin The audit trail, for super-administrators. ?date=ge…&date=le…, ?subtype=<action>, ?agent-name=, ?patient=.

Operations

FHIR operations for what a plain read or search cannot do.

OperationMethodAccessWhat it does
Patient/$predict-outcomePOST Token Parameters in: a Patient plus Observations. Scores with the live model, saves the assessment and raises a follow-up Task when the patient is flagged. Parameters out: the RiskAssessment and, when raised, the Task.
Patient/{id}/$predict-outcomePOST Token Re-scores a known patient from their latest assessment, with optional what-if values.
Patient/{id}/$everythingGET Token The whole record in one Bundle: predictions, TIBU's score, observations, regimen, comorbidities, follow-ups and alerts.
$ingest-registerPOST Admin Bulk upload of a DSTB register export (a base64 CSV Attachment). Idempotent by serial number; dryRun and score flags.
$calibrationGET Token Predicted against observed unfavourable-outcome rate, by model version. Small cells are suppressed.
{Type}/$validatePOST Public Checks a resource against one of the published profiles and returns an OperationOutcome.

Requesting a prediction

Post a Parameters resource carrying the patient and whatever observations are known — only age, sex and county are required. The answer is the prediction as a RiskAssessment, and the follow-up Task when the patient is flagged.

POST /fhir/Patient/$predict-outcome
Authorization: Bearer <token>
Content-Type: application/fhir+json

{
  "resourceType": "Parameters",
  "parameter": [
    { "name": "patient",
      "resource": { "resourceType": "Patient", … } },
    { "name": "observation",
      "resource": { "resourceType": "Observation", … } }
  ]
}
HTTP/1.1 200 OK
Content-Type: application/fhir+json

{
  "resourceType": "Parameters",
  "parameter": [
    { "name": "riskAssessment",
      "resource": { "resourceType": "RiskAssessment", … } },
    { "name": "task",
      "resource": { "resourceType": "Task", … } }
  ]
}

Searching & paging

  • Searches return searchset Bundles with total, a fullUrl and search.mode on every entry, and self / next / previous links.
  • Page with _count — 50 by default, up to 1,000 — and follow the next link rather than building page URLs yourself.
  • _summary=count returns the total only; _elements returns a marked subset of each resource.
  • _include and _revinclude are honoured where the resource declares them (see Resources), and _sort on RiskAssessment (date), Task (authored-on) and AuditEvent (date).

Errors

The FHIR server answers every error with an OperationOutcome saying what went wrong. The core API answers {"error": "…"} — or {"detail": "…"} for sign-in failures — with a standard status code.

  • 400The request is malformed, or a search parameter is not supported.
  • 401No token, or an expired one. Carries a WWW-Authenticate: Bearer challenge.
  • 403Signed in, but the action needs a higher role.
  • 404No such resource — or one outside your access level; the two look the same.
  • 405 / 406 / 415Wrong method, an Accept the server cannot satisfy, or a body in an unsupported format.
  • 422The body is well-formed FHIR but fails validation (for example, a missing required input).
  • 503The prediction model is not loaded.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer

{
  "resourceType": "OperationOutcome",
  "issue": [{
    "severity": "error",
    "code": "login",
    "diagnostics": "…"
  }]
}

Conformance

  • GET /fhir/metadata returns the CapabilityStatement — the machine-readable list of every resource, search parameter and operation this server supports.
  • Every profile, code system and value set it uses is published on the server too, under StructureDefinition, CodeSystem, ValueSet, OperationDefinition and SearchParameter.
  • Output is checked with the official HL7 FHIR validator in the backend's test suite, and every reference a resource carries resolves on this server.
  • Check your own resources before sending them with POST /fhir/{Type}/$validate.

Core API

Paths are relative to http://tbmldashboard.masterclass.co.ke/api/.

MethodPathAccessWhat it does
POSTauth/login/ Public Sign in; returns a token.
POSTauth/logout/ Token Revoke the current token.
GETauth/me/ Token The signed-in user's profile, role and access level.
POSTauth/register/ Public Request an account (it waits for approval).
POSTauth/password-reset/ Public Email a password-reset link.
GET/POSTauth/… Admin Approvals, suspensions, roles, access levels and settings.
GEThealth/ Public Liveness and model-load status.
GETmodel/info/ Public Which champion and base models are loaded.
GETanalytics/findings/ Token The sensitivity analysis and recommendations behind the Findings page.
GETanalytics/county-risk/ Token Aggregated risk by county.
GETanalytics/alerts/ Token Facility case-count anomalies (CUSUM) and the alert cutoff.
GETanalytics/model-performance/ Public Training-pipeline metrics for the candidate models.
GETaudit/summary/ Admin Audit counts by action, day and user.
Administrators

The interactive API explorer

Every core API endpoint with its request and response schemas, and a Try it out button that sends real requests with your session. Because those requests act on live data, the explorer is open to administrators only.