Skip to main content

Getting started

This guide gets you from zero to a successful API call.

Base URLs

Every route is mounted under the /api prefix. Your base URL must include /api.

EnvironmentBase URLNotes
Local devhttp://localhost:3001/apinpm run dev from repo root (or apps/api).
Dev / Cloud Runhttps://dev.digitshealth.com/apiShared development deployment.
Productionhttps://api.digitshealth.com/apiLive patient data.

The web app does not talk to these origins directly from the browser. It uses a same-origin BFF proxy at /api/proxy/<path> that attaches the Auth0 token server-side. Native and server-to-server integrations call the API origin directly with their own bearer token.

Running locally

From the repo root (Node 22, npm 11):

npm install
npm run dev          # turbo: web on :3002, api on :3001

Or just the API:

cd apps/api
cp .env.example .env # set DATABASE_URL at minimum
npm run dev          # prisma migrate deploy + generate, then tsx watch

When AUTH0_DOMAIN is unset, the API runs in dev mode: it injects a mock user (sub: 'dev|1', roles ['patient', 'care_provider']) so every authenticated route works without a real token. See Authentication.

Confirm it's up:

curl http://localhost:3001/api/health
# {"status":"ok","timestamp":"2026-06-07T...","version":"0.1.0"}

Your first real call

import { DigitsClient } from '@digits/clinical-sdk';

const digits = new DigitsClient({ baseUrl: 'http://localhost:3001/api' });

const result = await digits.assessments.submitRom({
  hand: 'RIGHT',
  overallScore: 82,
  wristScore: 78,
  fingerScore: 86,
  wrist: { max_extension_deg: 58, max_flexion_deg: 64, unsigned_rom_deg: 122 },
  joints: [],
});

console.log(result.formattedCode); // "XHE-7JR"

With curl

curl -X POST http://localhost:3001/api/assessments/rom \
  -H 'Content-Type: application/json' \
  -d '{
        "hand": "RIGHT",
        "overallScore": 82,
        "wristScore": 78,
        "fingerScore": 86,
        "wrist": { "max_extension_deg": 58, "max_flexion_deg": 64, "unsigned_rom_deg": 122 },
        "joints": []
      }'

Response (201 Created):

{ "id": 1, "code": "XHE7JR", "formattedCode": "XHE-7JR", "overallScore": 82, "wristScore": 78, "fingerScore": 86 }

Fetch it back by code (public, no auth):

curl http://localhost:3001/api/assessments/XHE7JR/results

Authenticated call

curl http://localhost:3001/api/patients/me/scores \
  -H "Authorization: Bearer $ACCESS_TOKEN"
const digits = new DigitsClient({
  baseUrl: 'https://api.digitshealth.com/api',
  token: () => getAccessToken(), // refreshed per request
});
const { scores } = await digits.patients.myScores({ hand: 'RIGHT' });

Conventions you should know

  • Content type: send and expect application/json. PDFs and TTS audio are the exceptions (see the API reference).
  • IDs: the database uses BigInt primary keys; responses serialize them as plain JSON numbers.
  • Assessment codes: six characters from the alphabet ABCDEFGHJKMNPQRSTUVWXYZ23456789 (no 0/O/1/I/L). Accepted with or without the middle dash. Anonymous records expire after 90 days; claimed records never expire.
  • Pagination: list endpoints take limit and offset; each documents its cap.
  • CORS: the API allows the configured FRONTEND_URL, localhost (3000/3002), and the Cloud Run web origins. Add new browser origins in apps/api/src/server.ts.

Next steps