API client and Kong integration
References: API_PATH_CONVENTIONS.md, patient-portal-requirements-doc.md §6, TECHNICAL_REQUIREMENTS.md, apps/patient-portal/README.md (web BFF → same Kong paths), packages/@ghasi/patient-portal-client (PortalApi / SchedulingApi), BACKEND_GAPS_AND_ROADMAP.md (patient-eligible routes and gaps).
1. Allowed paths
The mobile app is a browser-equivalent public client (Bearer to Kong—no Next.js BFF):
- MAY call Kong-public
/v1/...for patient flows, and/fhir/R4/...if the product exposes FHIR through Kong. - The web patient portal uses same-origin
/api/portal/*and/api/clinical/*Route Handlers that forward to the same${base}/v1/...URLs; mobile calls those/v1/...paths directly withAuthorization: Bearer(see apps/patient-portal/README.md §API proxy pattern). - MUST NOT call:
/internal/...(API_PATH_CONVENTIONS.md).
Base URL: https://{tenant-or-global-host} from configuration (KONG_PUBLIC_BASE_URL).
2. Authentication header
All protected calls:
Authorization: Bearer <access_token>
If using multi-tenant host routing, follow deployment docs; tenantId must still come from the token, not from user-editable fields.
JWT and patient binding: For patient-scoped scheduling and results, the access token should include patient_id or patientId matching the portal account’s patient; without it, APIs may return 403 (e.g. PATIENT_ID_CLAIM_REQUIRED). Configure Keycloak mappers accordingly (apps/patient-portal/README.md §Authentication).
3. Primary endpoints (aligned with web forwards)
Implement the logical operations defined by PortalApi and SchedulingApi in @ghasi/patient-portal-client; the HTTP mapping below matches apps/patient-portal Route Handlers (e.g. forwardPortal, forwardClinical). Authorization: many directory/scheduling routes are still staff-oriented in deployment; see BACKEND_GAPS_AND_ROADMAP.md before assuming PATIENT JWT success on every row.
3.1 Portal service (/v1/portal/...)
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/portal/me | Session + portal account; 404 if account not provisioned for IdP subject (apps/patient-portal/README.md §Provisioning errors) |
| GET | /v1/portal/record/summary | Aggregated dashboard / record summary |
| GET / POST | /v1/portal/appointments | Portal appointment requests (request workflow—not the same as confirmed scheduling appointments; see GAP-BOOK-001 in BACKEND_GAPS_AND_ROADMAP.md) |
| POST | /v1/portal/accounts/{accountId}/demographics-requests | Demographics change request |
| (TBD) | /v1/portal/results / policy BFF | Released results list/detail when implemented (GAP-RES-001); web may use GET /v1/results?patientId= via clinical/results until portal BFF is final—follow PortalApi.listReleasedResults() in client package |
Messaging, billing, export: follow module specs when licensed (SPEC.md FR-PORT-010..012).
3.2 Scheduling and provider directory (clinical APIs)
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/practitioners | Provider search (q, status, etc.) |
| GET | /v1/practitioners/{id} | Provider detail |
| GET | /v1/schedules?actorId= | Schedules for an actor |
| GET | /v1/slots?scheduleId=&from=&to= | Available slots (web: slots route) |
| POST | /v1/appointments/self | Patient self-service book (body omits patientId; patient context from JWT—web: appointments/self) |
| GET | /v1/appointments?patientId= | List appointments for patient (must enforce patient binding server-side—GAP-AUTH-001) |
| PUT | /v1/appointments/{id}/cancel-self | Patient cancel own appointment (cancel-self) |
Legacy / staff flows: POST /v1/appointments (non-self) may remain staff-only; mobile SHOULD use /v1/appointments/self and .../cancel-self for self-service parity with web.
Idempotency: send idempotency keys on writes if the backend supports them (patient-portal-requirements-doc.md §6).
4. Error handling
| HTTP | UX behavior |
|---|---|
| 401 | Clear session or attempt refresh; then login screen |
| 403 | Show “not allowed” with safe copy (no internal IDs); may indicate missing patient_id claim or module not licensed |
| 404 | Treat as not found or hidden by policy—do not leak existence of resources; on GET /v1/portal/me, surface account not provisioned (apps/patient-portal/README.md §Provisioning errors) |
| 409 | Conflict (e.g. slot taken)—surface retry per patient-portal-requirements-doc.md AC-Book-2 |
| 429 | Backoff; respect Retry-After if present |
Parse structured error bodies when the API provides code / message for localization.
5. PHI in logs
- Default no request/response body logging in production builds (COMPLIANCE_SECURITY.md §8).
- Crash reporters: disable or filter PHI fields.
6. TLS
Use system trust store; optional certificate pinning only if security architecture mandates it (INTERNATIONAL_STANDARDS_AND_ENTERPRISE_ALIGNMENT.md §2.5).