Authentication
Authentication Flow
-
To authenticate with the Heidi API and use the widget, you will need to generate a JSON Web Token (JWT) using your API key.
-
The API key provided is unique to your EHR system.
-
Heidi will use your API key in combination with your EHR User UID and email address to generate a unique "Heidi API User" account for the EHR User making the request.
Authenticate with the API
Method: GET
Path: /jwt
Description: Get a JWT token for authenticating with the API.
Request
GET /jwt?email=test@heidihealth.com&third_party_internal_id=123
Heidi-Api-Key: <heidi_api_key>Response
{
"token": "JWT_TOKEN",
"expiration_time": "2024-08-01T00:00:00.000Z"
}Linking a user
Authenticating with the API creates a "Heidi API User" account, but that account is not usable until the EHR user links it to a Heidi account. Linking is a browser flow, not an API call: open the link URL in a new tab or window and Heidi handles the entire sign in, sign up and subscription flow.
URL: https://scribe.heidihealth.com/integration/widget/auth
The link URL must match the environment that issued the token. If you are testing against a non-production API, ask your Heidi contact for the matching link URL.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
t | string | Yes | The JWT returned by /jwt. Must be URL-encoded. |
region | string | Yes | The Heidi region the token was issued for: AU, US, UK, EU or CA. See the region mapping. |
reset | boolean | No | Set to true to clear any existing session in the browser before linking. Recommended, so the user always starts from a clean state. |
productName | string | No | Your product or EHR name. Displayed to the user during the linking flow. |
Example
const linkUrl =
`https://scribe.heidihealth.com/integration/widget/auth` +
`?reset=true` +
`®ion=${encodeURIComponent(region)}` +
`&t=${encodeURIComponent(token)}`;
const authWindow = window.open(linkUrl, '_blank');The user signs in to their existing Heidi account or creates a new one, and Heidi associates it with the API user account behind the token. Once linked, future authentications for that user log them in automatically.
Poll Checking link status while the window is open to detect when linking completes, then
close or ignore the window once is_linked is true.
Checking link status
Method: GET
Path: /users/linked-account/access
Description: Check if an API user is linked to a Heidi account.
Request
GET /users/linked-account/access
Authorization: Bearer <your_token>Response
{
"is_valid": true,
"is_linked": true,
"account": {
"user_id": "Heidi User ID",
"ehr_provider": "Your EHR Provider",
"ehr_email": "The email provided with the API key",
"ehr_user_id": "The user ID provided with the API key"
},
"heidi_email": "The users' email",
"linked_account_plan": "The users' Heidi plan"
}In the response above, if is_linked is false, the user is not linked to a Heidi account. If is_linked is true, the user is linked to a Heidi account.
Team Management
The Team Management APIs allow you to retrieve information about teams and organization members.
List Joined Teams
Method: GET
Path: /team
Description: List all teams that the authenticated user has joined.
Request
GET /team
Authorization: Bearer <your_token>Response
{
"joined_teams": [
{
"team_id": "5eb7cf5a86d9755df3a6c593",
"team_name": "My Team",
"user_role": "ADMIN",
"free_trial_end_date": "2024-12-31T00:00:00.000Z",
"joined_at": "2024-01-01T00:00:00.000Z",
"member_count": 10
}
]
}Response Fields
| Field | Type | Description |
|---|---|---|
team_id | string | Unique identifier for the team |
team_name | string | Display name of the team |
user_role | string | User's role in the team (ADMIN or MEMBER) |
free_trial_end_date | string | ISO 8601 timestamp of when free trial ends (nullable) |
joined_at | string | ISO 8601 timestamp of when user joined (nullable) |
member_count | integer | Number of members in the team (nullable) |
Get Team Details
Method: GET
Path: /team/{team_id}
Description: Get detailed information about a specific team.
Request
GET /team/5eb7cf5a86d9755df3a6c593
Authorization: Bearer <your_token>Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
team_id | string | Yes | The unique identifier of the team |
Response
{
"team": {
"id": "5eb7cf5a86d9755df3a6c593",
"name": "My Team",
"country": "AU",
"is_subscribed": true,
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-06-01T00:00:00.000Z",
"is_stripe_managed": true,
"charge_future_members": true,
"allow_to_add_team_members": true,
"admin_session_review_toggle": false,
"subscribed_plan": "PRO",
"tier": "PRO",
"plan_cycle": "MONTHLY",
"plan_start_date": "2024-01-01T00:00:00.000Z",
"plan_end_date": "2025-01-01T00:00:00.000Z",
"require_patient_consent": false,
"org_id": "5eb7cf5a86d9755df3a6c594",
"org_name": "My Organization"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the team |
name | string | Team display name |
country | string | Country code for the team |
is_subscribed | boolean | Whether the team has an active subscription |
created_at | string | ISO 8601 timestamp of team creation |
updated_at | string | ISO 8601 timestamp of last update |
is_stripe_managed | boolean | Whether billing is managed through Stripe |
charge_future_members | boolean | Whether new members are automatically charged |
allow_to_add_team_members | boolean | Whether adding new members is allowed |
admin_session_review_toggle | boolean | Whether admin session review is enabled |
subscribed_plan | string | Current subscription plan tier |
tier | string | Current tier level |
plan_cycle | string | Billing cycle (MONTHLY or YEARLY) |
plan_start_date | string | ISO 8601 timestamp of plan start |
plan_end_date | string | ISO 8601 timestamp of plan end |
require_patient_consent | boolean | Whether patient consent is required |
org_id | string | Organization ID (if part of an organization) |
org_name | string | Organization name (if part of an organization) |
List Organization Members
Method: GET
Path: /organization/{organization_id}/members
Description: List members of an organization with pagination and filtering options.
Request
GET /organization/5eb7cf5a86d9755df3a6c593/members?page=1&page_size=10
Authorization: Bearer <your_token>Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The unique identifier of the organization |
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page | integer | No | 1 | Page number (minimum: 1) |
page_size | integer | No | 10 | Number of results per page (1-200) |
order_by | string | No | name | Field to sort by: name, email, specialty, role, or team |
is_descending | boolean | No | false | Sort in descending order |
search | string | No | - | Search term to filter members |
role_ids | array | No | - | Filter by role IDs |
team_ids | array | No | - | Filter by team IDs |
specialty_ids | array | No | - | Filter by specialty IDs |
show_pending_invitations_only | boolean | No | false | Show only pending invitations |
Response
{
"members": [
{
"id": "5eb7cf5a86d9755df3a6c593",
"team_id": "5eb7cf5a86d9755df3a6c594",
"team_name": "My Team",
"user_role": "MEMBER",
"kinde_user_id": "kp_xxx",
"name": "John Doe",
"email": "john.doe@example.com",
"specialty": "General Practice",
"specialty_id": "5eb7cf5a86d9755df3a6c596",
"country": "AU",
"invitation_accepted": true,
"is_team_owner": false,
"invitation_expire_at": null
}
],
"total": 50,
"page": 1,
"page_size": 10
}Response Fields
| Field | Type | Description |
|---|---|---|
members | array | List of organization members |
total | integer | Total number of members |
page | integer | Current page number |
page_size | integer | Number of members per page |
Member Object Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the team relation/invitation |
team_id | string | Team ID the member belongs to |
team_name | string | Name of the team |
user_role | string | User's role (ADMIN or MEMBER) |
kinde_user_id | string | User's Kinde ID |
name | string | Member's display name |
email | string | Member's email address |
specialty | string | Member's medical specialty |
specialty_id | string | Specialty ID (nullable) |
country | string | Member's country code (nullable) |
invitation_accepted | boolean | Whether the invitation has been accepted |
is_team_owner | boolean | Whether the member is the team owner |
invitation_expire_at | string | ISO 8601 timestamp of invitation expiry (nullable) |