Currently

SDK reference

SDK reference

Last updated 5/2/2026

Currently SDK Reference

Version: 1.0.0 | API Base: https://app.currently.health/api/web


Table of Contents

  1. Installation
  2. Authentication
  3. Client Initialization
  4. Type Definitions
  5. Method Reference
  6. Error Handling
  7. Pagination
  8. Rate Limiting
  9. Webhook Handling

Installation

The Currently SDK is distributed as a TypeScript-native package. Install it alongside @clerk/backend which is the authentication dependency declared in the platform's package.json.

# npm
npm install @currently/sdk @clerk/backend

# yarn
yarn add @currently/sdk @clerk/backend

# pnpm
pnpm add @currently/sdk @clerk/backend

Minimum requirements:

DependencyVersion
Node.js≥ 18.0.0
TypeScript≥ 5.0
@clerk/backend^2.29.5

Authentication

Currently uses Clerk session tokens for all authenticated endpoints. Three authentication patterns are supported depending on your context.

Pattern 1 — Server-side Clerk Session Token

Obtain a short-lived session token from Clerk and pass it as a Bearer token. This is the primary pattern for Next.js server components and route handlers.

import { auth } from '@clerk/nextjs/server';
import { CurrentlyClient } from '@currently/sdk';

export async function GET() {
  const { getToken } = auth();
  const token = await getToken();

  const client = new CurrentlyClient({
    sessionToken: token,
    baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL,
  });
}

Pattern 2 — API Key (HIE / Provider Programmatic Access)

Long-lived API keys are issued per organization through the /api/web/v1/admin/api-keys endpoint. Keys are passed via the Authorization header using the Bearer scheme.

import { CurrentlyClient } from '@currently/sdk';

const client = new CurrentlyClient({
  apiKey: process.env.CURRENTLY_API_KEY,
  baseUrl: 'https://app.currently.health',
});

Pattern 3 — Clerk Organization Context

When making calls scoped to a specific Clerk organization, include the active organization ID. The SDK forwards it as the x-org-id header.

import { auth } from '@clerk/nextjs/server';
import { CurrentlyClient } from '@currently/sdk';

const { getToken, orgId } = auth();

const client = new CurrentlyClient({
  sessionToken: await getToken(),
  organizationId: orgId ?? undefined,
  baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL,
});

Client Initialization

import { CurrentlyClient, CurrentlyClientConfig } from '@currently/sdk';

const client = new CurrentlyClient({
  // Required: one of sessionToken or apiKey
  sessionToken: '<clerk-jwt>',      // Clerk session token
  apiKey: '<currently-api-key>',    // Long-lived API key

  // Optional
  baseUrl: 'https://app.currently.health', // Default
  organizationId: '<clerk-org-id>',        // Scopes org-level requests
  timeout: 30_000,                         // Request timeout in ms (default: 30s)
  retries: 3,                              // Automatic retries on 429/5xx (default: 3)
  retryDelay: 1_000,                       // Base delay in ms, exponential backoff
});

CurrentlyClientConfig

ParameterTypeRequiredDescription
sessionTokenstringOne ofClerk short-lived JWT
apiKeystringOne ofLong-lived platform API key
baseUrlstringNoAPI base URL (default: https://app.currently.health)
organizationIdstringNoClerk org ID forwarded as x-org-id
timeoutnumberNoRequest timeout in milliseconds
retriesnumberNoRetry attempts for transient failures
retryDelaynumberNoBase delay in ms for exponential backoff

Type Definitions

// ─── Shared primitives ────────────────────────────────────────────────────────

export type UUID = string;
export type ISO8601 = string;
export type HospitalType =
  | 'hospital'
  | 'clinic'
  | 'urgent_care'
  | 'specialty_center'
  | 'lab'
  | 'imaging_center';

export type FileType = 'hl7' | 'cda' | 'fhir';

export type FileStatus =
  | 'pending'
  | 'transferred'
  | 'processing'
  | 'completed'
  | 'failed';

export type RegistrationStatus =
  | 'pending'
  | 'approved'
  | 'rejected'
  | 'suspended';

export type UserRole = 'admin' | 'member' | 'viewer';

// ─── Pagination ────────────────────────────────────────────────────────────────

export interface PaginationParams {
  page?: number;       // 1-based (default: 1)
  limit?: number;      // Items per page (default: 20, max: 100)
  cursor?: string;     // Cursor-based pagination token
}

export interface PaginatedResponse<T> {
  data: T[];
  meta: {
    total: number;
    page: number;
    limit: number;
    hasMore: boolean;
    nextCursor?: string;
  };
}

// ─── Organization ──────────────────────────────────────────────────────────────

export interface Organization {
  id: UUID;
  name: string;
  slug: string;
  clerkOrgId: string | null;
  primaryContactName: string | null;
  primaryContactEmail: string | null;
  primaryContactPhone: string | null;
  isActive: boolean;
  onboardingCompleted: boolean;
  settings: Record<string, unknown>;
  createdAt: ISO8601;
  updatedAt: ISO8601;
}

export interface CreateOrganizationRequest {
  name: string;
  slug: string;
  primaryContactName?: string;
  primaryContactEmail?: string;
  primaryContactPhone?: string;
  settings?: Record<string, unknown>;
}

// ─── Hospital / Facility ───────────────────────────────────────────────────────

export interface Hospital {
  id: UUID;
  organizationId: UUID;
  name: string;
  type: HospitalType;
  npi: string | null;
  facilityId: string | null;
  phone: string | null;
  email: string | null;
  website: string | null;
  addressLine1: string | null;
  addressLine2: string | null;
  city: string | null;
  state: string | null;
  zipCode: string | null;
  country: string;
  isActive: boolean;
  onboardingCompleted: boolean;
  allowedFileTypes: FileType[];
  maxFileSizeMb: number;
  settings: Record<string, unknown>;
  createdAt: ISO8601;
  updatedAt: ISO8601;
}

export interface CreateHospitalRequest {
  name: string;
  type: HospitalType;
  npi?: string;
  facilityId?: string;
  phone?: string;
  email?: string;
  website?: string;
  addressLine1?: string;
  addressLine2?: string;
  city?: string;
  state?: string;
  zipCode?: string;
  country?: string;
  allowedFileTypes?: FileType[];
  maxFileSizeMb?: number;
  settings?: Record<string, unknown>;
}

export interface UpdateHospitalRequest extends Partial<CreateHospitalRequest> {}

// ─── User ──────────────────────────────────────────────────────────────────────

export interface User {
  id: UUID;
  clerkId: string;
  email: string;
  name: string | null;
  organizationId: UUID | null;
  hospitalId: number | null;
  clerkRole: string | null;
  role: UserRole;
  isActive: boolean;
  imageUrl: string | null;
  createdAt: ISO8601;
  updatedAt: ISO8601;
}

export interface SyncUserRequest {
  clerkId: string;
  email: string;
  name?: string;
  imageUrl?: string;
  organizationId?: UUID;
  clerkRole?: string;
}

// ─── File Registry ─────────────────────────────────────────────────────────────

export interface FileRecord {
  id: UUID;
  organizationId: UUID;
  hospitalId: UUID | null;
  uploadedBy: UUID | null;
  fileName: string;
  fileType: FileType;
  fileSizeBytes: number | null;
  fileHash: string | null;
  status: FileStatus;
  createdAt: ISO8601;
  updatedAt: ISO8601;
}

export interface UploadFileRequest {
  file: Blob | File;
  fileType: FileType;
  hospitalId?: UUID;
}

// ─── Registration ──────────────────────────────────────────────────────────────

export interface HIERegistration {
  id: UUID;
  organizationName: string;
  slug: string;
  primaryContactName: string;
  primaryContactEmail: string;
  primaryContactPhone?: string;
  status: RegistrationStatus;
  clerkOrgId?: string;
  createdAt: ISO8601;
  updatedAt: ISO8601;
}

export interface CreateHIERegistrationRequest {
  organizationName: string;
  slug: string;
  primaryContactName: string;
  primaryContactEmail: string;
  primaryContactPhone?: string;
}

export interface FacilityRegistration {
  id: UUID;
  facilityName: string;
  type: HospitalType;
  npi?: string;
  contactName: string;
  contactEmail: string;
  contactPhone?: string;
  addressLine1?: string;
  city?: string;
  state?: string;
  zipCode?: string;
  status: RegistrationStatus;
  organizationId?: UUID;
  createdAt: ISO8601;
  updatedAt: ISO8601;
}

export interface CreateFacilityRegistrationRequest {
  facilityName: string;
  type: HospitalType;
  npi?: string;
  contactName: string;
  contactEmail: string;
  contactPhone?: string;
  addressLine1?: string;
  city?: string;
  state?: string;
  zipCode?: string;
}

// ─── Invitations ───────────────────────────────────────────────────────────────

export interface Invitation {
  id: UUID;
  email: string;
  role: UserRole;
  organizationId: UUID | null;
  token: string;
  expiresAt: ISO8601;
  acceptedAt: ISO8601 | null;
  createdAt: ISO8601;
}

export interface CreateFacilityUserInvitationRequest {
  email: string;
  role: UserRole;
  organizationId: UUID;
  hospitalId?: UUID;
}

export interface CreatePatientInvitationRequest {
  email: string;
  firstName: string;
  lastName: string;
  dateOfBirth?: string;
}

// ─── NPI Verification ──────────────────────────────────────────────────────────

export interface NPIVerificationRequest {
  npi: string;
}

export interface NPIVerificationResult {
  npi: string;
  valid: boolean;
  providerName?: string;
  organizationName?: string;
  credential?: string;
  enumerationType?: 'NPI-1' | 'NPI-2';
  primaryTaxonomy?: string;
  address?: {
    line1: string;
    city: string;
    state: string;
    zipCode: string;
  };
  status?: string;
}

// ─── Pricing ───────────────────────────────────────────────────────────────────

export interface PricingTier {
  id: UUID;
  name: string;
  slug: string;
  monthlyPriceCents: number;
  annualPriceCents: number;
  features: string[];
  limits: Record<string, number>;
  isActive: boolean;
  createdAt: ISO8601;
}

// ─── Revenue / Analytics ───────────────────────────────────────────────────────

export interface RevenueStats {
  totalRevenueCents: number;
  mrr: number;
  arr: number;
  activeSubscriptions: number;
  churnRate: number;
  byTier: Array<{
    tier: string;
    count: number;
    revenueCents: number;
  }>;
  periodStart: ISO8601;
  periodEnd: ISO8601;
}

export interface AnalyticsByOrg {
  organizationId: UUID;
  organizationName: string;
  filesProcessed: number;
  fhirResourcesGenerated: number;
  omopRecordsCreated: number;
  activeUsers: number;
  lastActivityAt: ISO8601 | null;
}

// ─── API Keys ──────────────────────────────────────────────────────────────────

export interface ApiKey {
  id: UUID;
  name: string;
  keyPrefix: string;   // First 8 chars, e.g. "curr_sk_"
  organizationId: UUID;
  scopes: string[];
  lastUsedAt: ISO8601 | null;
  expiresAt: ISO8601 | null;
  createdAt: ISO8601;
}

export interface CreateApiKeyRequest {
  name: string;
  organizationId: UUID;
  scopes: string[];
  expiresAt?: ISO8601;
}

export interface CreateApiKeyResponse extends ApiKey {
  secret: string;   // Full key — shown once only
}

export interface ApiKeyMetrics {
  totalKeys: number;
  activeKeys: number;
  requestsLast24h: number;
  requestsLast7d: number;
  topOrganizations: Array<{
    organizationId: UUID;
    organizationName: string;
    requestCount: number;
  }>;
}

// ─── Audit ─────────────────────────────────────────────────────────────────────

export interface PhiAccessAuditEntry {
  id: UUID;
  userId: UUID;
  userEmail: string;
  organizationId: UUID;
  resourceType: string;
  resourceId: string;
  action: 'read' | 'write' | 'delete' | 'export';
  ipAddress: string | null;
  userAgent: string | null;
  accessedAt: ISO8601;
}

// ─── Subscriptions ─────────────────────────────────────────────────────────────

export interface CheckoutRequest {
  tierId: UUID;
  organizationId: UUID;
  successUrl: string;
  cancelUrl: string;
}

export interface CheckoutResponse {
  checkoutUrl: string;
  sessionId: string;
}

export interface CancelSubscriptionRequest {
  organizationId: UUID;
  reason?: string;
}

// ─── Session ───────────────────────────────────────────────────────────────────

export interface SessionInfo {
  userId: UUID;
  clerkId: string;
  email: string;
  name: string | null;
  role: UserRole;
  organizationId: UUID | null;
  organizationName: string | null;
  clerkOrgId: string | null;
  permissions: string[];
}

// ─── Org Links ─────────────────────────────────────────────────────────────────

export interface OrgLinkApprovalRequest {
  linkId: UUID;
  approved: boolean;
  notes?: string;
}

export interface LinkFacilityToHIERequest {
  facilityOrganizationId: UUID;
  hieOrganizationId: UUID;
}

// ─── Health ────────────────────────────────────────────────────────────────────

export interface HealthStatus {
  status: 'ok' | 'degraded' | 'down';
  version: string;
  timestamp: ISO8601;
  services: Record<string, 'ok' | 'degraded' | 'down'>;
}

// ─── Errors ────────────────────────────────────────────────────────────────────

export interface CurrentlyErrorBody {
  error: string;
  message: string;
  statusCode: number;
  details?: Record<string, unknown>;
  requestId?: string;
}

export class CurrentlyError extends Error {
  constructor(
    public readonly statusCode: number,
    public readonly errorCode: string,
    message: string,
    public readonly details?: Record<string, unknown>,
    public readonly requestId?: string,
  ) {
    super(message);
    this.name = 'CurrentlyError';
  }
}

export class CurrentlyAuthError extends CurrentlyError {}
export class CurrentlyNotFoundError extends CurrentlyError {}
export class CurrentlyValidationError extends CurrentlyError {}
export class CurrentlyRateLimitError extends CurrentlyError {
  constructor(
    message: string,
    public readonly retryAfterMs: number,
  ) {
    super(429, 'RATE_LIMITED', message);
  }
}

Method Reference

Health

health.check()

Returns the platform health status. This endpoint is unauthenticated and suitable for liveness probes.

Signature

health.check(): Promise<HealthStatus>

Returns: HealthStatus

Example

const status = await client.health.check();
// { status: 'ok', version: '1.0.0', timestamp: '2024-01-15T10:00:00Z', services: { db: 'ok', redis: 'ok' } }

Session

session.get()

Returns the currently authenticated user's session context including resolved role, organization membership, and granted permissions.

Signature

session.get(): Promise<SessionInfo>

Returns: SessionInfo

Example

const session = await client.session.get();
console.log(session.role);           // 'admin'
console.log(session.organizationId); // 'org_abc123'
console.log(session.permissions);    // ['records:read', 'records:write']

Errors

CodeDescription
401Missing or invalid Clerk session token

Auth

auth.syncUser(body)

Synchronizes a Clerk user record into the Currently platform database. Called automatically after Clerk sign-up/sign-in webhooks, but can be invoked directly from server-side onboarding flows at web/src/app/api/auth/sync-user/route.ts.

Signature

auth.syncUser(body: SyncUserRequest): Promise<User>

Parameters

ParameterTypeRequiredDescription
clerkIdstringYesClerk user ID (user_*)
emailstringYesUser's primary email
namestringNoDisplay name
imageUrlstringNoAvatar URL from Clerk
organizationIdUUIDNoCurrently org UUID to assign on sync
clerkRolestringNoRole string from Clerk organization membership

Returns: User

Example

const user = await client.auth.syncUser({
  clerkId: 'user_2abc123',
  email: 'provider@riverside.health',
  name: 'Dr. Jane Smith',
  clerkRole: 'org:admin',
});

Errors

CodeDescription
400Validation failure — missing clerkId or email
401Unauthenticated request
409Clerk ID already registered with a different email

Organizations

organizations.listApproved(params?)

Returns all organizations that have completed onboarding and are in approved status.

Signature

organizations.listApproved(params?: PaginationParams): Promise<PaginatedResponse<Organization>>

Parameters

ParameterTypeRequiredDescription
pagenumberNoPage number (default: 1)
limitnumberNoResults per page (default: 20, max: 100)

Returns: PaginatedResponse<Organization>

Example

const { data, meta } = await client.organizations.listApproved({ limit: 50 });
console.log(meta.total); // 142

organizations.checkHIE(slug)

Checks whether a given organization slug belongs to an active HIE. Used during facility registration to validate HIE membership before linking.

Signature

organizations.checkHIE(slug: string): Promise<{ isHIE: boolean; organization?: Organization }>

Parameters

ParameterTypeRequiredDescription
slugstringYesOrganization slug to verify

Example

const result = await client.organizations.checkHIE('riverside-health-network');
if (result.isHIE) {
  console.log(result.organization?.name);
}

HIEs

hies.list(params?)

Lists all Health Information Exchange organizations visible to the authenticated user.

Signature

hies.list(params?: PaginationParams): Promise<PaginatedResponse<Organization>>

Example

const { data } = await client.hies.list({ page: 1, limit: 25 });

hies.get(id)

Retrieves a single HIE organization by its UUID.

Signature

hies.get(id: UUID): Promise<Organization>

Parameters

ParameterTypeRequiredDescription
idUUIDYesOrganization UUID

Example

const hie = await client.hies.get('3e4f5a6b-7c8d-9e0f-1a2b-3c4d5e6f7a8b');

Errors

CodeDescription
404HIE organization not found

orgs.listHIEs()

Returns HIE organizations scoped to the authenticated user's current Clerk organization context. Route: web/src/app/api/orgs/hie/route.ts.

Signature

orgs.listHIEs(): Promise<Organization[]>

Example

const hies = await client.orgs.listHIEs();

Facilities

facilities.list(params?)

Lists facilities (hospitals, clinics, etc.) visible to the authenticated user based on their organization membership.

Signature

facilities.list(params?: PaginationParams): Promise<PaginatedResponse<Hospital>>

Example

const { data, meta } = await client.facilities.list({ page: 1, limit: 20 });

facilities.get(id)

Retrieves a single facility by UUID.

Signature

facilities.get(id: UUID): Promise<Hospital>

Parameters

ParameterTypeRequiredDescription
idUUIDYesFacility UUID

Example

const facility = await client.facilities.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');

Errors

CodeDescription
403Authenticated user lacks access to this facility
404Facility not found

facilities.getHospital(id)

Returns the hospital record associated with a facility. Route: web/src/app/api/facilities/[id]/hospital/route.ts.

Signature

facilities.getHospital(id: UUID): Promise<Hospital>

Parameters

ParameterTypeRequiredDescription
idUUIDYesFacility UUID

Example

const hospital = await client.facilities.getHospital('a1b2c3d4-...');

facilities.getMedicalRecords(id, params?)

Returns medical record metadata (from file_registry) for a facility. No PHI is returned — records include processing status and FHIR/OMOP conversion progress.

Signature

facilities.getMedicalRecords(
  id: UUID,
  params?: PaginationParams & { status?: FileStatus; fileType?: FileType }
): Promise<PaginatedResponse<FileRecord>>

Parameters

ParameterTypeRequiredDescription
idUUIDYesFacility UUID
statusFileStatusNoFilter by processing status
fileTypeFileTypeNoFilter by file type (hl7, cda, fhir)
pagenumberNoPage number
limitnumberNoResults per page

Example

const { data } = await client.facilities.getMedicalRecords(
  'a1b2c3d4-...',
  { status: 'completed', fileType: 'hl7', limit: 50 }
);

data.forEach(record => {
  console.log(`${record.fileName} → ${record.status}`);
});

facilities.linkToHIE(body)

Initiates a link request between a facility organization and an HIE. The link requires HIE admin approval before becoming active. Route: web/src/app/api/facility/link-to-hie/route.ts.

Signature

facilities.linkToHIE(body: LinkFacilityToHIERequest): Promise<{ linkId: UUID; status: 'pending' }>

Parameters

ParameterTypeRequiredDescription
facilityOrganizationIdUUIDYesUUID of the facility's organization
hieOrganizationIdUUIDYesUUID of the target HIE organization

Example

const link = await client.facilities.linkToHIE({
  facilityOrganizationId: 'fac-org-uuid',
  hieOrganizationId: 'hie-org-uuid',
});
console.log(link.linkId); // Pending approval by HIE admin

Hospitals

hospitals.getByFacilityOrg(facilityOrgId)

Returns the hospital record associated with a facility organization ID. Route: web/src/app/api/hospital/by-facility-org/route.ts.

Signature

hospitals.getByFacilityOrg(facilityOrgId: UUID): Promise<Hospital>

Parameters

ParameterTypeRequiredDescription
facilityOrgIdUUIDYesFacility organization UUID

Example

const hospital = await client.hospitals.getByFacilityOrg('org-uuid');

Registrations

registrations.createHIE(body)

Submits a self-service HIE organization registration. The registration enters pending status and requires platform admin approval. Route: web/src/app/api/registrations/hie/route.ts.

Signature

registrations.createHIE(body: CreateHIERegistrationRequest): Promise<HIERegistration>

Parameters

ParameterTypeRequiredDescription
organizationNamestringYesFull legal name of the HIE
slugstringYesURL-safe identifier (lowercase, hyphens)
primaryContactNamestringYesFull name of primary contact
primaryContactEmailstringYesContact email address
primaryContactPhonestringNoContact phone number

Example

const registration = await client.registrations.createHIE({
  organizationName: 'Riverside Health Network',
  slug: 'riverside-health-network',
  primaryContactName: 'Sarah Johnson',
  primaryContactEmail: 'sarah@riverside.health',
  primaryContactPhone: '555-867-5309',
});

console.log(registration.status); // 'pending'

Errors

CodeDescription
400Validation error — invalid slug format or missing required fields
409Slug already taken

registrations.createFacility(body)

Submits a facility registration request. Route: web/src/app/api/registrations/facility/route.ts.

Signature

registrations.createFacility(body: CreateFacilityRegistrationRequest): Promise<FacilityRegistration>

Parameters

ParameterTypeRequiredDescription
facilityNamestringYesFacility name
typeHospitalTypeYesFacility type
npistringNo10-digit NPI number
contactNamestringYesPrimary contact name
contactEmailstringYesPrimary contact email
contactPhonestringNoContact phone
addressLine1stringNoStreet address
citystringNoCity
statestringNoState (2-letter abbreviation)
zipCodestringNoZIP code

Example

const reg = await client.registrations.createFacility({
  facilityName: 'Riverside General Hospital',
  type: 'hospital',
  npi: '1234567890',
  contactName: 'Dr. Marcus Webb',
  contactEmail: 'mwebb@riverside-general.health',
  city: 'Sacramento',
  state: 'CA',
  zipCode: '95814',
});

Invitations

`invitations.

SDK reference · Currently | Midwest