Documentation

SDKs & Libraries

Official client libraries for integrating with the Cari platform.

@cari/sdk — TypeScript / JavaScript

Typed client for all Cari API endpoints with built-in auth and error handling.

The official Cari SDK for TypeScript and JavaScript applications. It provides a typed client for all Cari API endpoints with built-in authentication, error handling, and response envelope unwrapping.

Installation

# npm
npm install @cari/sdk

# yarn
yarn add @cari/sdk

# pnpm
pnpm add @cari/sdk

Quick Start

import { CariClient } from "@cari/sdk";

const cari = new CariClient({
  baseUrl: "https://api.cari.care",
  // Option 1: API key (from Developer API Keys)
  apiKey: "your-api-key",
  // Option 2: PASETO token
  token: "v4.public.eyJ...",
});

Authentication

API keys, PASETO tokens, and username/password login.

The SDK supports three authentication methods: API keys (recommended for server-to-server), PASETO tokens, and username/password login.

API Key Authentication

import { CariClient } from "@cari/sdk";

// API keys are created at /api/developer/keys
const cari = new CariClient({
  baseUrl: "https://api.cari.care",
  apiKey: process.env.CARI_API_KEY,
});

Login Authentication

import { CariClient } from "@cari/sdk";

const cari = new CariClient({
  baseUrl: "https://api.cari.care",
});

// Login and store the token
const { user, token } = await cari.auth.login({
  email: "developer@example.com",
  password: "SecureP@ss123",
});

// The token is automatically used for subsequent requests
console.log("Logged in as:", user.email);

Token Refresh

// The SDK handles token refresh automatically when configured
const cari = new CariClient({
  baseUrl: "https://api.cari.care",
  token: "v4.public.eyJ...",
  refreshToken: "v4.public.refresh...",
  onTokenRefresh: (newToken) => {
    // Store the new token (e.g., in a database or env)
    console.log("Token refreshed");
  },
});

Use API key authentication for server-to-server integrations. It eliminates the need for token refresh and simplifies your integration.

Common Operations

Patients, appointments, clinical records, prescriptions, lab results, and more.

Patients

// List patients in an organization
const patients = await cari.patients.list(orgId, {
  page: 1,
  limit: 20,
});
console.log(`Found ${patients.meta.total} patients`);

// Get a specific patient
const patient = await cari.patients.get(patientId);
console.log(patient.first_name, patient.last_name);

// Create a patient
const newPatient = await cari.patients.create({
  first_name: "Amara",
  last_name: "Okafor",
  date_of_birth: "1990-03-15",
  gender: "female",
  phone: "+234801234567",
});

// Search patients by MRN
const results = await cari.patients.search(orgId, {
  mrn: "MRN-001",
});

Appointments

// Check availability
const slots = await cari.appointments.availability({
  resource_id: doctorResourceId,
  date: "2026-04-25",
});

// Book an appointment
const appointment = await cari.appointments.book({
  resource_id: doctorResourceId,
  patient_name: "Amara Okafor",
  patient_email: "amara@example.com",
  patient_phone: "+234801234567",
  start_time: "2026-04-25T09:00:00Z",
  end_time: "2026-04-25T09:30:00Z",
  reason: "Annual checkup",
});

// Cancel an appointment
await cari.appointments.cancel(appointmentId);

// Get kanban board view
const kanban = await cari.appointments.kanban({
  date: "2026-04-25",
});

Clinical Records

// List clinical records for a patient
const records = await cari.clinical.records.list(patientId);

// Create a clinical record
const record = await cari.clinical.records.create({
  patient_id: patientId,
  encounter_type: "consultation",
  chief_complaint: "Persistent headache",
  notes: "Patient reports headache for 3 days...",
});

// Record vitals
const vitals = await cari.vitals.create({
  patient_id: patientId,
  heart_rate: 72,
  blood_pressure_systolic: 120,
  blood_pressure_diastolic: 80,
  temperature: 36.6,
  respiratory_rate: 16,
  oxygen_saturation: 98,
});

Prescriptions

// Create a prescription
const prescription = await cari.prescriptions.create({
  patient_id: patientId,
  medication: "Amoxicillin",
  dosage: "500mg",
  frequency: "3 times daily",
  duration: "7 days",
  instructions: "Take with food",
});

// Sign the prescription
await cari.prescriptions.sign(prescription.id);

// Send to pharmacy via e-prescribing
await cari.eprescriptions.create({
  prescription_id: prescription.id,
  pharmacy_id: pharmacyId,
});

Lab Results

// List lab results for a patient
const labResults = await cari.labs.listResults(patientId);

// Create a lab order
const labOrder = await cari.labs.createOrder({
  patient_id: patientId,
  test_type: "CBC",
  priority: "routine",
  notes: "Annual screening",
});

// AI lab interpretation
const interpretation = await cari.ai.interpretLab({
  patient_id: patientId,
  lab_result_id: labResultId,
});

Drug Interaction Check

// Check for drug-drug interactions
const interactions = await cari.cds.checkDrugInteractions({
  medications: [
    { name: "Warfarin", rxcui: "11289" },
    { name: "Aspirin", rxcui: "1191" },
    { name: "Ibuprofen", rxcui: "5640" },
  ],
});

if (interactions.length > 0) {
  for (const interaction of interactions) {
    console.warn(
      `[${interaction.severity}] ${interaction.description}`
    );
  }
}

Organizations

// List my organizations
const myOrgs = await cari.organizations.me();

// Get organization details
const org = await cari.organizations.get(orgId);

// Invite a member
await cari.organizations.invite(orgId, {
  email: "newdoctor@hospital.org",
  role: "ORG:DOCTOR",
});

// List members
const members = await cari.organizations.members(orgId);

Payments

// Initiate a mobile money payment
const payment = await cari.payments.initiateMobileMoney({
  provider: "mpesa",
  phone: "+254712345678",
  amount: 1500.00,
  currency: "KES",
  order_id: orderId,
  description: "Consultation payment",
});

// Check payment status
const status = await cari.payments.getStatus(orderId);
console.log("Payment status:", status.state);

Error Handling

Typed error classes with HTTP status codes and error codes.

import { CariClient, CariApiError } from "@cari/sdk";

const cari = new CariClient({ baseUrl: "https://api.cari.care" });

try {
  const patient = await cari.patients.get("nonexistent-id");
} catch (error) {
  if (error instanceof CariApiError) {
    console.error(`API Error [${error.status}]: ${error.code}`);
    console.error(error.message);

    switch (error.status) {
      case 401:
        // Token expired — refresh or re-login
        break;
      case 403:
        // Insufficient permissions
        break;
      case 404:
        // Resource not found
        break;
      case 429:
        // Rate limited — back off and retry
        break;
    }
  }
}

The SDK throws CariApiError for all non-2xx responses. Always wrap API calls in try/catch blocks for production applications.

Response Types

Automatic envelope unwrapping with TypeScript types for all resources.

The SDK automatically unwraps the standard API response envelope. List endpoints return data with pagination metadata:

// Single resource — returns the data directly
const patient = await cari.patients.get(id);
// patient = { id, first_name, last_name, ... }

// List endpoint — returns data + meta
const result = await cari.patients.list(orgId, { page: 1, limit: 20 });
// result.data = [{ id, first_name, ... }, ...]
// result.meta = { page: 1, limit: 20, total: 42 }

// TypeScript types are provided for all resources
import type {
  Patient,
  Appointment,
  ClinicalRecord,
  Prescription,
  Organization,
  LabResult,
  Vital,
} from "@cari/sdk";

Configuration Options

Full list of CariClient constructor options.

const cari = new CariClient({
  // Required
  baseUrl: "https://api.cari.care",

  // Authentication (one of these)
  apiKey: "your-api-key",        // Recommended for server-to-server
  token: "v4.public.eyJ...",     // PASETO token
  refreshToken: "v4.public...",  // For automatic token refresh

  // Optional
  timeout: 30000,                // Request timeout in ms (default: 30s)
  retries: 3,                    // Number of retries on 5xx errors
  onTokenRefresh: (token) => {}, // Callback when token is refreshed
  userAgent: "my-app/1.0",       // Custom User-Agent header
});

Direct REST API

Call the API directly from any HTTP client without the SDK.

If you prefer not to use the SDK, you can call the REST API directly from any HTTP client. All endpoints accept and return JSON:

// Using fetch (JavaScript)
const response = await fetch("https://api.cari.care/api/patients/" + patientId, {
  headers: {
    "Authorization": "Bearer v4.public.eyJ...",
    "Content-Type": "application/json",
  },
});

const { success, data } = await response.json();
if (success) {
  console.log("Patient:", data.first_name, data.last_name);
}

// Using curl
curl -X GET https://api.cari.care/api/patients/{id} \
  -H "Authorization: Bearer v4.public.eyJ..." \
  -H "Content-Type: application/json"

// Using Python requests
import requests

response = requests.get(
    f"https://api.cari.care/api/patients/{patient_id}",
    headers={"Authorization": f"Bearer {token}"},
)
patient = response.json()["data"]

Developer API Keys

Create, rotate, and revoke API keys for server-to-server integrations.

For server-to-server integrations, create API keys through the Organization service. API keys can be rotated and revoked without affecting user accounts.

// Create an API key
POST /api/developer/keys
Authorization: Bearer v4.public.eyJ...
Content-Type: application/json

{
  "name": "Production Integration",
  "scopes": ["patients:read", "appointments:write"]
}

// List API keys
GET /api/developer/keys

// Rotate a key (generates a new secret, old key remains valid for 24h)
POST /api/developer/keys/:id/rotate

// Revoke a key (immediate)
DELETE /api/developer/keys/:id

Rotate API keys regularly and use scoped keys with minimal permissions. The 24-hour grace period during rotation ensures zero-downtime key rotation.