Skip to main content
@clinikehr/api is the official TypeScript client for the ClinikEHR API. It is a thin layer over the same HTTPS endpoints this reference documents, and it takes care of the parts that are easy to get wrong: sending your key, retrying safely, never creating a record twice, walking paged lists, typed errors and checking webhook signatures.

Install

The package ships both ES modules and CommonJS, with type definitions for every route. Each version is built from its public source by GitHub Actions and published with a signed provenance statement — check what you installed with:

Your first call

In the developer portal, switch to Test mode, open Keys and select Create key. A test key reaches only your workspace’s sandbox — invented clinics, patients and stock — so you can try everything safely. Put it in your server’s environment, never in source code:
GET /v1/me tells you which key you are using, its environment and its permissions. With a test key, clinic_id is your sandbox clinic — use it in the calls below.

Calling a route

The client has one method per HTTP verb: GET, POST, PATCH and DELETE. The path is the route exactly as this reference writes it, and your editor will autocomplete it. Path and query parameters go in params; a request body goes in body.
These four methods return the response body as unknown, so you state the shape you expect, as above. For full compile-time checking of parameters, bodies and responses against the API description, use client.raw — see Fully typed calls.
A route your key’s permissions do not cover answers 403 with the code scope_missing, and a route for a clinic your key cannot reach answers 404. See Permissions.

Writing safely: idempotency is automatic

Every POST and PATCH the client sends carries a fresh Idempotency-Key, and the same key is reused if the client retries that request. So a timeout after the server has already saved your record can never create a second one — the retry returns the first answer. Some PATCH routes, such as updating an appointment, require the header; the client always sends it, so you never have to. A DELETE carries a key only when you pass one. See Retries and duplicates. If your own job may repeat a logical operation (for example, a queue that redelivers a message), pass your own key so both attempts are recognised as one:

Retries

The client retries a request that failed for a temporary reason, up to 4 attempts in total: Waits grow exponentially from 500 ms up to 8 s, with random jitter, and a Retry-After header from the API always wins. Change the policy when you create the client:
See Rate limits for the limits themselves.

Errors

A refused request throws ClinikEHRApiError, carrying the API’s error fields:
TransportError means the network failed on every attempt; the request may or may not have reached us. For a POST, retrying with the same idempotencyKey is safe.

Paging through a list

List routes return one page at a time with has_more and next_cursor. paginate walks every page for you:
It stops when has_more is false. See Pagination.

FHIR R4

To receive FHIR resources instead of JSON, turn FHIR on for the whole client or for one call:
See FHIR R4 for which routes answer in FHIR and how.

Verifying a webhook

verifyWebhook checks the signature on an event we deliver to your endpoint. Pass the raw request body — not a re-serialised object — and your endpoint’s signing secret:
While you rotate a signing secret, pass both — secrets: [current, previous] — and either one is accepted. An event older than 5 minutes is refused (toleranceSeconds changes that). See Verifying a webhook’s signature and Events.

Fully typed calls

client.raw is the generated client, typed from the API description: parameters, request bodies and responses are checked at compile time. It already sends your key, but it does not retry or add idempotency keys — use it for reads where you want the types, or add your own Idempotency-Key header on writes.

Keep your key on the server

createClient throws BrowserEnvironmentError when it runs in a web browser, whatever the key. An API key in a browser is readable by anyone who opens the page, and a live key reaches real patient information. Call the API from your server and give your front end only what it needs.

From test to live

  1. Build and test against your sandbox with a test key.
  2. To reach a real clinic, the clinic connects your organization and grants the permissions you need — see Connections. Anything about a patient also needs patient-data access.
  3. Create a live key and swap it in. Nothing else in your code changes.

Versions

The client follows semantic versioning. While it is 0.x, a minor version may change its interface; pin a version range you have tested (npm install @clinikehr/[email protected]; use 0.1.3 or later — earlier versions did not send the Idempotency-Key a PATCH route requires). Releases are listed in the changelog and on npm. Found a problem? Open an issue on GitHub.