OpenAPI spec
OpenAPI spec
Last updated 5/2/2026
Currently Healthcare Data Platform — OpenAPI 3.1 Specification
Endpoint Summary Table
| # | Method | Path | Tag | Auth Required | Description |
|---|---|---|---|---|---|
| 1 | GET | /api/web/health | System | No | Platform health check |
| 2 | GET | /api/web/session | Auth | Yes | Get current session and user context |
| 3 | POST | /api/web/auth/sync-user | Auth | Yes | Sync Clerk user to platform database |
| 4 | GET | /api/web/facilities | Facilities | Yes | List facilities for authenticated org |
| 5 | POST | /api/web/facilities | Facilities | Yes | Create a new facility |
| 6 | GET | /api/web/facilities/{id} | Facilities | Yes | Get facility by ID |
| 7 | PATCH | /api/web/facilities/{id} | Facilities | Yes | Update facility metadata |
| 8 | DELETE | /api/web/facilities/{id} | Facilities | Yes | Soft-delete a facility |
| 9 | GET | /api/web/facilities/{id}/hospital | Facilities | Yes | Get hospital record linked to facility |
| 10 | GET | /api/web/facilities/{id}/medical-records | Facilities | Yes | List medical records for a facility |
| 11 | GET | /api/web/hies | HIEs | Yes | List all HIE organizations |
| 12 | POST | /api/web/hies | HIEs | Yes | Create a new HIE organization |
| 13 | GET | /api/web/hies/{id} | HIEs | Yes | Get HIE organization by ID |
| 14 | PATCH | /api/web/hies/{id} | HIEs | Yes | Update HIE organization |
| 15 | GET | /api/web/orgs/hie | Organizations | Yes | Get current user's HIE org |
| 16 | GET | /api/web/organizations/approved | Organizations | Yes | List approved organizations |
| 17 | GET | /api/web/organizations/check-hie | Organizations | Yes | Check if org is a registered HIE |
| 18 | POST | /api/web/facility/link-to-hie | Organizations | Yes | Link a facility to an HIE |
| 19 | GET | /api/web/hospital/by-facility-org | Organizations | Yes | Get hospital record by facility org context |
| 20 | GET | /api/web/files | Files | Yes | List uploaded files for org |
| 21 | POST | /api/web/files | Files | Yes | Upload a clinical file (HL7/CDA/FHIR) |
| 22 | GET | /api/web/invitations | Invitations | Yes | List pending invitations |
| 23 | POST | /api/web/invitations | Invitations | Yes | Create a new invitation |
| 24 | GET | /api/web/invitations/{token} | Invitations | No | Resolve invitation by token |
| 25 | POST | /api/web/npi/verify | NPI | Yes | Verify an NPI number against NPPES |
| 26 | POST | /api/web/onboarding/patient | Onboarding | Yes | Complete patient onboarding |
| 27 | POST | /api/web/registrations/hie | Registrations | No | Submit HIE self-registration |
| 28 | POST | /api/web/registrations/facility | Registrations | No | Submit facility self-registration |
| 29 | GET | /api/web/admin/pricing/tiers | Admin | Yes | List available pricing tiers |
| 30 | POST | /api/web/admin/facility-orgs/create | Admin | Yes | Platform admin: create facility org |
| 31 | POST | /api/web/admin/invitations/facility-user | Admin | Yes | Platform admin: invite facility user |
| 32 | POST | /api/web/admin/invitations/patient | Admin | Yes | Platform admin: invite patient |
| 33 | POST | /api/web/admin/org-links/approve | Admin | Yes | Platform admin: approve org link |
| 34 | GET | /api/web/admin/registrations/facility | Admin | Yes | List pending facility registrations |
| 35 | GET | /api/web/admin/registrations/facility/{id} | Admin | Yes | Get facility registration by ID |
| 36 | PUT | /api/web/admin/registrations/facility/{id} | Admin | Yes | Update facility registration status |
| 37 | POST | /api/web/admin/registrations/facility/hie-initiate | Admin | Yes | Admin: initiate HIE-side facility registration |
| 38 | GET | /api/web/admin/registrations/hie | Admin | Yes | List pending HIE registrations |
| 39 | GET | /api/web/admin/registrations/hie/{id} | Admin | Yes | Get HIE registration by ID |
| 40 | PUT | /api/web/admin/registrations/hie/{id} | Admin | Yes | Approve or reject HIE registration |
| 41 | GET | /api/web/admin/revenue/stats | Admin | Yes | Platform revenue statistics |
| 42 | GET | /api/web/v1/admin/analytics/by-org | Analytics | Yes | Per-org analytics breakdown |
| 43 | GET | /api/web/v1/admin/api-keys | API Keys | Yes | List API keys for org |
| 44 | POST | /api/web/v1/admin/api-keys | API Keys | Yes | Create an API key |
| 45 | DELETE | /api/web/v1/admin/api-keys | API Keys | Yes | Revoke an API key |
| 46 | GET | /api/web/v1/admin/api-keys/metrics/platform | API Keys | Yes | Platform-wide API key usage metrics |
| 47 | POST | /api/web/v1/admin/approve-provider | Admin | Yes | Approve a provider account |
| 48 | GET | /api/web/v1/admin/audit/phi-access | Audit | Yes | PHI access audit log |
| 49 | POST | /api/web/subscriptions/checkout | Billing | Yes | Create a subscription checkout session |
| 50 | POST | /api/web/subscriptions/cancel | Billing | Yes | Cancel active subscription |
| 51 | GET | /api/web/dev/email-preview | Dev | No | Preview email templates (dev only) |
OpenAPI 3.1 Specification
openapi: '3.1.0'
info:
title: Currently Healthcare Data Platform API
version: '1.0.0'
description: |
REST API for the Currently Healthcare Data Platform — an AI-powered HL7/CCDA
processing pipeline that converts raw clinical documents from health information
exchanges (HIEs) into FHIR R4 and OMOP CDM 5.4.
## Authentication
All protected endpoints require a valid Clerk session JWT passed as a Bearer
token in the `Authorization` header. Tokens are short-lived and must be
refreshed via the Clerk frontend SDK.
## Environments
| Environment | Base URL |
|-------------|----------|
| Production | `https://app.currently.health` |
| Staging | `https://staging.currently.health` |
| Development | `http://localhost:3000` |
## API Versioning
Legacy routes live under `/api/web/`. Versioned routes (v1+) live under
`/api/web/v1/`. All new integrations should target the versioned surface.
## PHI Policy
No PHI is stored or transmitted through this API surface. Clinical data
references are de-identified identifiers (MRN hash, file hash). Raw clinical
documents are written directly to GCS by the pipeline workers and never
pass through the web API.
contact:
name: Currently Platform Engineering
email: engineering@currently.health
url: https://currently.health
license:
name: Proprietary
url: https://currently.health/terms
servers:
- url: https://app.currently.health
description: Production (Vercel)
- url: https://staging.currently.health
description: Staging
- url: http://localhost:3000
description: Local development
# ---------------------------------------------------------------------------
# Security
# ---------------------------------------------------------------------------
security:
- ClerkBearerAuth: []
components:
securitySchemes:
ClerkBearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
Clerk-issued short-lived JWT. Obtain via `clerk.session.getToken()` in
the browser or via the Clerk backend SDK (`@clerk/backend ^2.29.5`).
The token encodes the user's `clerk_id`, active organization
(`clerk_org_id`), and assigned role.
# -------------------------------------------------------------------------
# Shared Parameters
# -------------------------------------------------------------------------
parameters:
PathId:
name: id
in: path
required: true
schema:
type: string
format: uuid
description: UUID primary key of the resource.
PathToken:
name: token
in: path
required: true
schema:
type: string
description: Opaque invitation token.
QueryPage:
name: page
in: query
required: false
schema:
type: integer
minimum: 1
default: 1
description: Page number for paginated results.
QueryLimit:
name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
description: Number of results per page.
QueryOrgId:
name: orgId
in: query
required: false
schema:
type: string
format: uuid
description: Filter results to a specific organization UUID.
# -------------------------------------------------------------------------
# Shared Schemas
# -------------------------------------------------------------------------
schemas:
# --- Primitives ---------------------------------------------------------
Timestamp:
type: string
format: date-time
description: ISO 8601 timestamp with timezone offset.
example: '2024-11-15T14:30:00.000Z'
UUID:
type: string
format: uuid
example: '3fa85f64-5717-4562-b3fc-2c963f66afa6'
ErrorResponse:
type: object
required: [error]
properties:
error:
type: string
description: Human-readable error message.
example: 'Resource not found.'
code:
type: string
description: Machine-readable error code.
example: 'NOT_FOUND'
details:
type: object
additionalProperties: true
description: Optional structured context for the error.
PaginationMeta:
type: object
properties:
page:
type: integer
example: 1
limit:
type: integer
example: 20
total:
type: integer
example: 142
totalPages:
type: integer
example: 8
# --- Organization -------------------------------------------------------
Organization:
type: object
required: [id, name, slug, isActive, createdAt, updatedAt]
properties:
id:
$ref: '#/components/schemas/UUID'
name:
type: string
maxLength: 255
example: 'Midwest HIE Consortium'
slug:
type: string
maxLength: 100
pattern: '^[a-z0-9-]+$'
example: 'midwest-hie'
clerkOrgId:
type: string
nullable: true
example: 'org_2abc123'
primaryContactName:
type: string
nullable: true
example: 'Dr. Jane Doe'
primaryContactEmail:
type: string
format: email
nullable: true
example: 'jane.doe@midwesthie.org'
primaryContactPhone:
type: string
nullable: true
example: '+1-312-555-0100'
isActive:
type: boolean
example: true
onboardingCompleted:
type: boolean
example: false
settings:
type: object
additionalProperties: true
description: Arbitrary org-level configuration JSON.
createdAt:
$ref: '#/components/schemas/Timestamp'
updatedAt:
$ref: '#/components/schemas/Timestamp'
OrganizationCreate:
type: object
required: [name, slug]
properties:
name:
type: string
maxLength: 255
example: 'Midwest HIE Consortium'
slug:
type: string
maxLength: 100
pattern: '^[a-z0-9-]+$'
example: 'midwest-hie'
primaryContactName:
type: string
example: 'Dr. Jane Doe'
primaryContactEmail:
type: string
format: email
example: 'jane.doe@midwesthie.org'
primaryContactPhone:
type: string
example: '+1-312-555-0100'
settings:
type: object
additionalProperties: true
OrganizationUpdate:
type: object
properties:
name:
type: string
maxLength: 255
primaryContactName:
type: string
primaryContactEmail:
type: string
format: email
primaryContactPhone:
type: string
isActive:
type: boolean
onboardingCompleted:
type: boolean
settings:
type: object
additionalProperties: true
# --- Hospital / Facility ------------------------------------------------
Hospital:
type: object
required: [id, organizationId, name, type, isActive, createdAt, updatedAt]
properties:
id:
$ref: '#/components/schemas/UUID'
organizationId:
$ref: '#/components/schemas/UUID'
name:
type: string
maxLength: 255
example: 'Northwestern Memorial Hospital'
type:
type: string
enum:
- hospital
- clinic
- urgent_care
- specialty_center
- lab
- imaging_center
example: 'hospital'
npi:
type: string
maxLength: 20
nullable: true
example: '1234567890'
facilityId:
type: string
maxLength: 100
nullable: true
example: 'FAC-00123'
phone:
type: string
nullable: true
example: '+1-312-926-2000'
email:
type: string
format: email
nullable: true
website:
type: string
format: uri
nullable: true
addressLine1:
type: string
nullable: true
example: '251 E Huron St'
addressLine2:
type: string
nullable: true
city:
type: string
nullable: true
example: 'Chicago'
state:
type: string
nullable: true
example: 'IL'
zipCode:
type: string
nullable: true
example: '60611'
country:
type: string
default: 'USA'
example: 'USA'
isActive:
type: boolean
example: true
onboardingCompleted:
type: boolean
example: false
allowedFileTypes:
type: array
items:
type: string
enum: [hl7, cda, fhir]
example: ['hl7', 'cda', 'fhir']
maxFileSizeMb:
type: integer
example: 100
settings:
type: object
additionalProperties: true
createdAt:
$ref: '#/components/schemas/Timestamp'
updatedAt:
$ref: '#/components/schemas/Timestamp'
HospitalCreate:
type: object
required: [organizationId, name, type]
properties:
organizationId:
$ref: '#/components/schemas/UUID'
name:
type: string
maxLength: 255
example: 'Northwestern Memorial Hospital'
type:
type: string
enum:
- hospital
- clinic
- urgent_care
- specialty_center
- lab
- imaging_center
npi:
type: string
maxLength: 20
facilityId:
type: string
maxLength: 100
phone:
type: string
email:
type: string
format: email
website:
type: string
format: uri
addressLine1:
type: string
addressLine2:
type: string
city:
type: string
state:
type: string
zipCode:
type: string
country:
type: string
default: 'USA'
allowedFileTypes:
type: array
items:
type: string
enum: [hl7, cda, fhir]
maxFileSizeMb:
type: integer
default: 100
settings:
type: object
additionalProperties: true
HospitalUpdate:
type: object
properties:
name:
type: string
type:
type: string
enum:
- hospital
- clinic
- urgent_care
- specialty_center
- lab
- imaging_center
npi:
type: string
phone:
type: string
email:
type: string
format: email
addressLine1:
type: string
addressLine2:
type: string
city:
type: string
state:
type: string
zipCode:
type: string
isActive:
type: boolean
allowedFileTypes:
type: array
items:
type: string
enum: [hl7, cda, fhir]
maxFileSizeMb:
type: integer
settings:
type: object
additionalProperties: true
# --- User ---------------------------------------------------------------
User:
type: object
required: [id, clerkId, email, role, isActive, createdAt, updatedAt]
properties:
id:
$ref: '#/components/schemas/UUID'
clerkId:
type: string
example: 'user_2abc123'
email:
type: string
format: email
example: 'provider@clinic.org'
name:
type: string
nullable: true
example: 'Dr. Marcus Webb'
organizationId:
$ref: '#/components/schemas/UUID'
nullable: true
clerkRole:
type: string
nullable: true
example: 'org:provider'
role:
type: string
example: 'member'
isActive:
type: boolean
example: true
imageUrl:
type: string
format: uri
nullable: true
createdAt:
$ref: '#/components/schemas/Timestamp'
updatedAt:
$ref: '#/components/schemas/Timestamp'
# --- Session ------------------------------------------------------------
SessionResponse:
type: object
required: [user, organization]
properties:
user:
$ref: '#/components/schemas/User'
organization:
$ref: '#/components/schemas/Organization'
nullable: true
role:
type: string
description: Clerk organization role for the active session.
example: 'org:admin'
permissions:
type: array
items:
type: string
example: ['read:records', 'write:records', 'manage:users']
# --- File Registry ------------------------------------------------------
FileRecord:
type: object
required: [id, organizationId, fileName, fileType, status, createdAt]
properties:
id:
$ref: '#/components/schemas/UUID'
organizationId:
$ref: '#/components/schemas/UUID'
hospitalId:
$ref: '#/components/schemas/UUID'
nullable: true
uploadedBy:
$ref: '#/components/schemas/UUID'
nullable: true
fileName:
type: string
maxLength: 500
example: 'ADT_A01_20241115_001.hl7'
fileType:
type: string
enum: [hl7, cda, fhir]
example: 'hl7'
fileSizeBytes:
type: integer
format: int64
nullable: true
example: 204800
fileHash:
type: string
maxLength: 64
nullable: true
description: SHA-256 hash for deduplication.
example: 'a3f5e2b8c1d0...'
status:
type: string
enum:
- pending
- transferred
- processing
- completed
- failed
example: 'completed'
createdAt:
$ref: '#/components/schemas/Timestamp'
updatedAt:
$ref: '#/components/schemas/Timestamp'
FileUploadRequest:
type: object
required: [fileName, fileType, content]
properties:
fileName:
type: string
example: 'ORU_R01_20241115.hl7'
fileType:
type: string
enum: [hl7, cda, fhir]
hospitalId:
$ref: '#/components/schemas/UUID'
description: Target hospital UUID for this upload.
content:
type: string
format: byte
description: |
Base64-encoded file content. Maximum decoded size governed by the
hospital's `maxFileSizeMb` setting (default 100 MB).
FileListResponse:
type: object
properties:
files:
type: array
items:
$ref: '#/components/schemas/FileRecord'
pagination:
$ref: '#/components/schemas/PaginationMeta'
# --- Medical Records ----------------------------------------------------
MedicalRecordSummary:
type: object
description: De-identified summary of a clinical record — no PHI.
required: [id, facilityId, fileType, status, createdAt]
properties:
id:
$ref: '#/components/schemas/UUID'
facilityId:
$ref: '#/components/schemas/UUID'
fileType:
type: string
enum: [hl7, cda, fhir]
mrnHash:
type: string
description: SHA-256 hash of the patient MRN. Not reversible from this API.
example: 'b3d9f1a2e4c6...'
status:
type: string
enum: [pending, processing, completed, failed]
fhirBundleAvailable:
type: boolean
example: true
omopRecordsAvailable:
type: boolean
example: true
createdAt:
$ref: '#/components/schemas/Timestamp'
MedicalRecordListResponse:
type: object
properties:
records:
type: array
items:
$ref: '#/components/schemas/MedicalRecordSummary'
pagination:
$ref: '#/components/schemas/PaginationMeta'
# --- Invitations --------------------------------------------------------
Invitation:
type: object
required: [id, email, role, status, createdAt]
properties:
id:
$ref: '#/components/schemas/UUID'
email:
type: string
format: email
example: 'newprovider@clinic.org'
role:
type: string
example: 'org:provider'
invitedBy:
$ref: '#/components/schemas/UUID'
nullable: true
organizationId:
$ref: '#/components/schemas/UUID'
nullable: true
token:
type: string
description: Opaque single-use token. Only present in the creation response.
status:
type: string
enum: [pending, accepted, expired, revoked]
example: 'pending'
expiresAt:
$ref: '#/components/schemas/Timestamp'
nullable: true
createdAt:
$ref: '#/components/schemas/Timestamp'
InvitationCreateRequest:
type: object
required: [email, role]
properties:
email:
type: string
format: email
example: 'newprovider@clinic.org'
role:
type: string
description: Clerk organization role to assign on acceptance.
example: 'org:provider'
organizationId:
$ref: '#/components/schemas/UUID'
description: >
Required when called from the platform admin context to invite into a
specific org. Omit when inviting into the caller's own org.
InvitationResolveResponse:
type: object
required: [invitation, organization]
properties:
invitation:
$ref: '#/components/schemas/Invitation'
organization:
$ref: '#/components/schemas/Organization'
nullable: true
# --- Registrations ------------------------------------------------------
HIERegistrationRequest:
type: object
required: [name, slug, primaryContactName, primaryContactEmail]
properties:
name:
type: string
maxLength: 255
example: 'Great Lakes HIE'
slug:
type: string
maxLength: 100
pattern: '^[a-z0-9-]+$'
example: 'great-lakes-hie'
primaryContactName:
type: string
example: 'Alice Tran'
primaryContactEmail:
type: string
format: email
example: 'alice@greatlakeshie.org'
primaryContactPhone:
type: string
example: '+1-414-555-0199'
message:
type: string
description: Optional message to the platform admin reviewers.
FacilityRegistrationRequest:
type: object
required: [facilityName, facilityType, npi, contactName, contactEmail]
properties:
facilityName:
type: string
maxLength: 255
example: 'Oak Park Urgent Care'
facilityType:
type: string
enum:
- hospital
- clinic
- urgent_care
- specialty_center
- lab
- imaging_center
npi:
type: string
maxLength: 20
example: '1234567890'
contactName:
type: string
example: 'Bob Kowalski'
contactEmail:
type: string
format: email
example: 'bob@oakparkuc.com'
contactPhone:
type: string
hieOrgId:
$ref: '#/components/schemas/UUID'
description: UUID of the HIE this facility wishes to join.
addressLine1:
type: string
city:
type: string
state:
type: string
zipCode:
type: string
message:
type: string
RegistrationRecord:
type: object
required: [id, status, createdAt]
properties:
id:
$ref: '#/components/schemas/UUID'
status:
type: string
enum: [pending, approved, rejected, under_review]
example: 'pending'
submittedData:
type: object
additionalProperties: true
description: The original registration payload.
reviewedBy:
$ref: '#/components/schemas/UUID'
nullable: true
reviewedAt:
$ref: '#/components/schemas/Timestamp'
nullable: true
reviewNotes:
type: string
nullable: true
createdAt:
$ref: '#/components/schemas/Timestamp'
updatedAt:
$ref: '#/components/schemas/Timestamp'
RegistrationStatusUpdate:
type: object
required: [status]
properties:
status:
type: string
enum: [approved, rejected, under_review]
example: 'approved'
reviewNotes:
type: string
example: 'All documentation verified. NPI confirmed via NPPES.'
# --- NPI ----------------------------------------------------------------
NPIVerifyRequest:
type: object
required: [npi]
properties:
npi:
type: string
pattern: '^\d{10}$'
example: '1234567890'
NPIVerifyResponse:
type: object
required: [valid, npi]
properties:
valid:
type: boolean
example: true
npi:
type: string
example: '1234567890'
providerName:
type: string
nullable: true
example: 'Northwestern Memorial Hospital'
providerType:
type: string
nullable: true
description: NPI enumeration type (individual or organization).
example: 'organization'
taxonomy:
type: string
nullable: true
example: '282N00000X'
address:
type: object
nullable: true
properties:
line1:
type: string
city:
type: string
state:
type: string
zip:
type: string
# --- Onboarding ---------------------------------------------------------
PatientOnboardingRequest:
type: object
required: [dateOfBirth, consentGiven]
properties:
dateOfBirth:
type: string
format: date
example: '1985-06-20'
consentGiven:
type: boolean
description: >
Patient must explicitly consent to data processing. Must be `true`
to proceed.
example: true
preferredName:
type: string
example: 'Samantha'
phone:
type: string
example: '+1-773-555-0177'
PatientOnboardingResponse:
type: object
required: [success, userId]
properties:
success:
type: boolean
example: true
userId:
$ref: '#/components/schemas/UUID'
portalUrl:
type: string
format: uri
example: 'https://app.currently.health/portal'
# --- Pricing ------------------------------------------------------------
PricingTier:
type: object
required: [id, name, priceMonthly, features]
properties:
id:
type: string
example: 'tier_starter'
name:
type: string
example: 'Starter'
priceMonthly:
type: number
format: float
example: 299.00
priceAnnual:
type: number
format: float
nullable: true
example: 2990.00
features:
type: array
items:
type: string
example:
- 'Up to 5 facilities'
- '10,000 records/month'
- 'FHIR R4 export'
isActive:
type: boolean
example: true
# --- Revenue / Analytics ------------------------------------------------
RevenueStats:
type: object
properties:
mrr:
type: number
format: float
description: Monthly Recurring Revenue (USD).
example: 48750.00
arr:
type: number
format: float
description: Annual Recurring Revenue (USD).
example: 585000.00
activeSubscriptions:
type: integer
example: 37
churnRate:
type: number
format: float
description: Monthly churn rate as a decimal.
example: 0.018
newSubscriptionsTh