Governance, API Contract

Systems API

HMIS exposes a versioned REST JSON API at /api/v1. Express route handlers enforce RBAC, clinical branch geography, and record scope on every protected path. Canonical contract: docs/info/API-CONTRACT.md.

Auth

Bearer JWT access token; HttpOnly refresh cookie in production (USE_HTTPONLY_REFRESH=1).

Branch scope

Working-in campus via session activeBranchId / X-Working-Branch-Id on stamped ops.

Rate limits

Default 300 req/min/client; stricter auth and public buckets.

OpenAPI

Full Express inventory in api/openapi/route-descriptors.json (tiered schemas); committed openapi.json; drift fails on undocumented routes in npm run test:deploy.

Authentication flow

POST /api/v1/auth/login          → access JWT (+ refresh cookie when configured)
Authorization: Bearer <jwt>    → all protected REST calls
POST /api/v1/auth/refresh        → rotate refresh token
POST /api/v1/auth/mfa/*          → TOTP verify when mfaRequired (see docs/info/MFA-AUTHENTICATION.md)

Runtime authorization:
  allowed = modulePermission AND branchScope AND recordScope [AND orgUnit scope]

Machine integrations (lab/radiology analyzers) use OAuth client credentials where configured. Public patient share links use a separate PUBLIC_SHARE_JWT_SECRET, not the staff JWT.

Request & response conventions

Requests

  • Content-Type: application/json (multipart for uploads)
  • JSON body limit: 2 MB default (API_JSON_BODY_LIMIT)
  • UUIDs: RFC 4122 strings in path and body
  • Dates: ISO 8601 UTC

Paginated lists

{ "items": [], "total": 100, "page": 1, "pageSize": 25, "totalPages": 4 }

Query: page, pageSize (per-route caps apply).

Error envelope

{ "error": "Human-readable message", "code": "OPTIONAL_MACHINE_CODE", "details": {} }
400Validation failure (Zod flatten in details)
401Missing or invalid token
403Permission denied or branch scope failure
404Resource not found (or hidden by scope)
409Conflict / optimistic lock
413Export row cap exceeded
429Rate limit exceeded

Key route groups

Full surface in generated OpenAPI

/api/v1/authLogin, refresh, password, MFA
Public + authenticated
/api/v1/patientsPatient chart, list
List Register-at scoped; chart-by-id org-wide
/api/v1/billingInvoices, payments, advances
Branch stamped via Working-in
/api/v1/governancePolicies, DR drills, training, helpdesk
Admin-heavy
/api/v1/privacyDSR, erasure jobs
privacy:manage or governance:manage
/api/v1/report-builderDynamic SQL reports
Linked-dataset permission checks
/api/v1/aiAI chat, SQL assistant
Read-only SQL guard on main DB
/api/v1/publicBooking, share validation
Unauthenticated, rate limited
/api/v1/healthLiveness
No auth
/api/v1/metricsPrometheus scrape
METRICS_TOKEN or CIDR allowlist

Idempotency & auditing

Financial and critical writes support client idempotency keys via POST /api/v1/governance/idempotency/claim. Retries with the same key return the original result. Mutations fire AuditLog entries; exports require explicit permissions.

Technical Architecture

FieldTypeInstitutional Role
AuthorizationHeaderBearer JWT on protected routes.
x-hmis-step-upHeaderStep-up token for privileged mutations.
x-permissionsOpenAPI extRequired grants per operation.
x-branch-scopeOpenAPI extWorking-in / Register-at / chart exception notes.

Note: Sensitive fields use AES-256 field-level encryption where applicable.

Governance & Power

settings:admin
audit:export
Repository documentation
  • docs/info/API-CONTRACT.md
  • docs/info/SECURITY-HARDENING.md
  • docs/development/DEPRECATION-REGISTER.md
  • docs/info/ADR-001-branch-vs-orgunit.md
  • docs/info/ADR-002-chat-mongodb-persistence.md
  • docs/info/threat-models/report-builder.md

Regenerate OpenAPI: node scripts/generate-openapi.mjs · Check drift: npm run check:openapi-drift · Live spec: GET /api/v1/openapi.json (settings:admin) · Swagger UI GET /api/v1/docs/ (settings:admin).

Related: Security & Access · System Architecture · Machine Integration

Integrator checklist
  • Obtain service account; confirm Roles grants
  • Set Working-in branch header for campus writes
  • Handle 401 with refresh; respect pagination and export caps
  • Use idempotency keys for invoice/payment creates
  • Never embed PHI in GET query strings; TLS 1.2+ only