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
- Installation
- Authentication
- Client Initialization
- Type Definitions
- Method Reference
- Health
- Session
- Auth
- Organizations
- HIEs
- Facilities
- Hospitals
- Registrations
- Invitations
- Files
- NPI Verification
- Onboarding
- Subscriptions
- Admin — Registrations
- Admin — Org Links
- Admin — Invitations
- Admin — Pricing
- Admin — Revenue
- Admin — Facility Orgs
- Admin v1 — API Keys
- Admin v1 — Analytics
- Admin v1 — Audit
- Admin v1 — Provider Approval
- Error Handling
- Pagination
- Rate Limiting
- 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:
| Dependency | Version |
|---|---|
| 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
| Parameter | Type | Required | Description |
|---|---|---|---|
sessionToken | string | One of | Clerk short-lived JWT |
apiKey | string | One of | Long-lived platform API key |
baseUrl | string | No | API base URL (default: https://app.currently.health) |
organizationId | string | No | Clerk org ID forwarded as x-org-id |
timeout | number | No | Request timeout in milliseconds |
retries | number | No | Retry attempts for transient failures |
retryDelay | number | No | Base 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
| Code | Description |
|---|---|
401 | Missing 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
| Parameter | Type | Required | Description |
|---|---|---|---|
clerkId | string | Yes | Clerk user ID (user_*) |
email | string | Yes | User's primary email |
name | string | No | Display name |
imageUrl | string | No | Avatar URL from Clerk |
organizationId | UUID | No | Currently org UUID to assign on sync |
clerkRole | string | No | Role 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
| Code | Description |
|---|---|
400 | Validation failure — missing clerkId or email |
401 | Unauthenticated request |
409 | Clerk 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
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | No | Page number (default: 1) |
limit | number | No | Results 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
| Parameter | Type | Required | Description |
|---|---|---|---|
slug | string | Yes | Organization 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
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Organization UUID |
Example
const hie = await client.hies.get('3e4f5a6b-7c8d-9e0f-1a2b-3c4d5e6f7a8b');
Errors
| Code | Description |
|---|---|
404 | HIE 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
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Facility UUID |
Example
const facility = await client.facilities.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
Errors
| Code | Description |
|---|---|
403 | Authenticated user lacks access to this facility |
404 | Facility 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
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Facility 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
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Facility UUID |
status | FileStatus | No | Filter by processing status |
fileType | FileType | No | Filter by file type (hl7, cda, fhir) |
page | number | No | Page number |
limit | number | No | Results 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
| Parameter | Type | Required | Description |
|---|---|---|---|
facilityOrganizationId | UUID | Yes | UUID of the facility's organization |
hieOrganizationId | UUID | Yes | UUID 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
| Parameter | Type | Required | Description |
|---|---|---|---|
facilityOrgId | UUID | Yes | Facility 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
| Parameter | Type | Required | Description |
|---|---|---|---|
organizationName | string | Yes | Full legal name of the HIE |
slug | string | Yes | URL-safe identifier (lowercase, hyphens) |
primaryContactName | string | Yes | Full name of primary contact |
primaryContactEmail | string | Yes | Contact email address |
primaryContactPhone | string | No | Contact 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
| Code | Description |
|---|---|
400 | Validation error — invalid slug format or missing required fields |
409 | Slug 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
| Parameter | Type | Required | Description |
|---|---|---|---|
facilityName | string | Yes | Facility name |
type | HospitalType | Yes | Facility type |
npi | string | No | 10-digit NPI number |
contactName | string | Yes | Primary contact name |
contactEmail | string | Yes | Primary contact email |
contactPhone | string | No | Contact phone |
addressLine1 | string | No | Street address |
city | string | No | City |
state | string | No | State (2-letter abbreviation) |
zipCode | string | No | ZIP 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',
});