Unfortunately, the Heidi API and Widget are no longer available for future integrations in Australia and New Zealand. If you are a current Heidi customer looking to integrate, reach out to your Customer Success representative. Otherwise, contact our team to find out what this means for you.
Usage API (Beta)
Overview

Usage API

🚧 Beta. The Heidi Usage API is currently in beta. Endpoints, request/response shapes, and the set of available queries may change ahead of general availability. Handle unknown error_code values gracefully and pin to a specific query name. Breaking changes will be announced before GA.

Overview

The Heidi Usage API exposes partner-facing usage analytics over your Heidi data as named, pre-defined queries returned as paginated rows. It is separate from the Heidi API (clinical scribe) — different base URL and its own query surface, but the same credentials.

Base URL

There is no cross-region routing layer — pick the endpoint for the region whose data you're querying. All endpoints sit under the /api/v1/usage path.

RegionBase URL
Australiahttps://au.api.heidihealth.com
United Stateshttps://us.api.heidihealth.com
United Kingdom / EU Westhttps://uk.api.heidihealth.com
EU Centralhttps://eu.api.heidihealth.com
Canadahttps://ca.api.heidihealth.com

Specification

Find the Swagger definition here and download a Postman collection here.

Authentication

Send either credential as a header on every request (same as the Heidi API):

  • Heidi-Api-Key: <your api key> — your partner API key (recommended).
  • Authorization: Bearer <jwt> — a Heidi open-api JWT.

A request with neither returns 401 MISSING_CREDENTIAL.

Request lifecycle

The Usage API uses a POST-to-start / GET-to-page model:

  1. POST /api/v1/usage with a query name starts the query and returns the first page (200). If the query is still running it returns 202 — poll the GET with the returned statement_id.
  2. Each response carries a fully-formed next_page_url. Follow it with a GET (same auth header) until next_page_url is null and has_more is false.
POST /api/v1/usage
Heidi-Api-Key: <your api key>
Content-Type: application/json
 
{
  "name": "user_daily_report",
  "limit": 500,
  "params": { "since": "2026-06-01" }
}
{
  "statement_id": "01f1848c-d205-1886-83c9-f61e2aad23bb",
  "data": [ { "report_date": "2026-06-01", "…": "…" } ],
  "has_more": true,
  "next_page_url": "https://au.api.heidihealth.com/api/v1/usage/01f1848c-d205-1886-83c9-f61e2aad23bb?name=user_daily_report&offset=500&limit=500"
}
GET /api/v1/usage/01f1848c-d205-1886-83c9-f61e2aad23bb?name=user_daily_report&offset=500&limit=500
Heidi-Api-Key: <your api key>

Paging with GET is cheap — it reads cached result chunks and does not re-run the warehouse query. A running statement expires after ~10 minutes; following a next_page_url too late returns 410 STATEMENT_EXPIRED (re-POST to start again).

Idempotency

Pass an Idempotency-Key header (a UUID) on the POST to make retries safe — useful from cron jobs. Same key + same body within 10 minutes replays the cached response; same key + a different body returns 422 IDEMPOTENCY_KEY_MISMATCH.

Cancelling

DELETE /api/v1/usage/{statement_id} requests cancellation of a running statement (204 No Content).

Errors

Every non-2xx response uses a typed body so you can switch on error_code rather than parsing strings:

{
  "error_code": "MISSING_CREDENTIAL",
  "detail": "provide either `Heidi-Api-Key` header or `Authorization: Bearer <jwt>`",
  "recovery_hint": "Provide either `Heidi-Api-Key: <key>` or `Authorization: Bearer <jwt>`."
}
error_codeHTTPWhen
MISSING_CREDENTIAL401No Heidi-Api-Key / Authorization header
INVALID_CREDENTIAL401Wrong or expired credential
UNKNOWN_QUERY404Unrecognised query name
STATEMENT_EXPIRED410next_page_url followed too late (~10 min)
INVALID_PARAMS422Request failed validation
INVALID_DATE_RANGE422until < since or a malformed date
INVALID_WINDOW422offset / limit out of range
IDEMPOTENCY_KEY_MISMATCH422Reused an Idempotency-Key with a different body
RATE_LIMITED429Per-organization rate limit exceeded
QUERY_FAILED500The warehouse query itself failed
WAREHOUSE_DEGRADED503The analytics warehouse is failing health checks — retry after ~30s

Rate limits

Requests are rate-limited per organization. Exceeding the limit returns 429 RATE_LIMITED — back off and retry.

Available queries

See Queries for the current query catalogue and column shapes.