Currently

OpenAPI spec

OpenAPI spec

Last updated 5/2/2026

Currently Healthcare Data Platform — OpenAPI 3.1 Specification

Endpoint Summary Table

#MethodPathTagAuth RequiredDescription
1GET/api/web/healthSystemNoPlatform health check
2GET/api/web/sessionAuthYesGet current session and user context
3POST/api/web/auth/sync-userAuthYesSync Clerk user to platform database
4GET/api/web/facilitiesFacilitiesYesList facilities for authenticated org
5POST/api/web/facilitiesFacilitiesYesCreate a new facility
6GET/api/web/facilities/{id}FacilitiesYesGet facility by ID
7PATCH/api/web/facilities/{id}FacilitiesYesUpdate facility metadata
8DELETE/api/web/facilities/{id}FacilitiesYesSoft-delete a facility
9GET/api/web/facilities/{id}/hospitalFacilitiesYesGet hospital record linked to facility
10GET/api/web/facilities/{id}/medical-recordsFacilitiesYesList medical records for a facility
11GET/api/web/hiesHIEsYesList all HIE organizations
12POST/api/web/hiesHIEsYesCreate a new HIE organization
13GET/api/web/hies/{id}HIEsYesGet HIE organization by ID
14PATCH/api/web/hies/{id}HIEsYesUpdate HIE organization
15GET/api/web/orgs/hieOrganizationsYesGet current user's HIE org
16GET/api/web/organizations/approvedOrganizationsYesList approved organizations
17GET/api/web/organizations/check-hieOrganizationsYesCheck if org is a registered HIE
18POST/api/web/facility/link-to-hieOrganizationsYesLink a facility to an HIE
19GET/api/web/hospital/by-facility-orgOrganizationsYesGet hospital record by facility org context
20GET/api/web/filesFilesYesList uploaded files for org
21POST/api/web/filesFilesYesUpload a clinical file (HL7/CDA/FHIR)
22GET/api/web/invitationsInvitationsYesList pending invitations
23POST/api/web/invitationsInvitationsYesCreate a new invitation
24GET/api/web/invitations/{token}InvitationsNoResolve invitation by token
25POST/api/web/npi/verifyNPIYesVerify an NPI number against NPPES
26POST/api/web/onboarding/patientOnboardingYesComplete patient onboarding
27POST/api/web/registrations/hieRegistrationsNoSubmit HIE self-registration
28POST/api/web/registrations/facilityRegistrationsNoSubmit facility self-registration
29GET/api/web/admin/pricing/tiersAdminYesList available pricing tiers
30POST/api/web/admin/facility-orgs/createAdminYesPlatform admin: create facility org
31POST/api/web/admin/invitations/facility-userAdminYesPlatform admin: invite facility user
32POST/api/web/admin/invitations/patientAdminYesPlatform admin: invite patient
33POST/api/web/admin/org-links/approveAdminYesPlatform admin: approve org link
34GET/api/web/admin/registrations/facilityAdminYesList pending facility registrations
35GET/api/web/admin/registrations/facility/{id}AdminYesGet facility registration by ID
36PUT/api/web/admin/registrations/facility/{id}AdminYesUpdate facility registration status
37POST/api/web/admin/registrations/facility/hie-initiateAdminYesAdmin: initiate HIE-side facility registration
38GET/api/web/admin/registrations/hieAdminYesList pending HIE registrations
39GET/api/web/admin/registrations/hie/{id}AdminYesGet HIE registration by ID
40PUT/api/web/admin/registrations/hie/{id}AdminYesApprove or reject HIE registration
41GET/api/web/admin/revenue/statsAdminYesPlatform revenue statistics
42GET/api/web/v1/admin/analytics/by-orgAnalyticsYesPer-org analytics breakdown
43GET/api/web/v1/admin/api-keysAPI KeysYesList API keys for org
44POST/api/web/v1/admin/api-keysAPI KeysYesCreate an API key
45DELETE/api/web/v1/admin/api-keysAPI KeysYesRevoke an API key
46GET/api/web/v1/admin/api-keys/metrics/platformAPI KeysYesPlatform-wide API key usage metrics
47POST/api/web/v1/admin/approve-providerAdminYesApprove a provider account
48GET/api/web/v1/admin/audit/phi-accessAuditYesPHI access audit log
49POST/api/web/subscriptions/checkoutBillingYesCreate a subscription checkout session
50POST/api/web/subscriptions/cancelBillingYesCancel active subscription
51GET/api/web/dev/email-previewDevNoPreview 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