Authentication
The Partner API uses two levels of credentials:
- Partner credentials authenticate your backend to Blueprint. Server-to-server only.
- Clinician tokens let the embedded widget act on behalf of one clinician. Minted by your
backend, used by your frontend.
If you are building an API-only integration you only need the first.
Credentials you receive
Blueprint provisions these when your partner organization is onboarded:
| Credential | Purpose |
|---|---|
clientId | Identifies your partner application |
clientSecret | Secret for your partner application |
apiKey | API key for your partner organization |
All three are secrets. Store them in your backend's secret manager. Never expose them to frontend
code — the clientSecret also signs your webhooks, so leaking it lets anyone forge events.
You receive a separate set for sandbox and production. See
Environments & Base URLs.
Step 1 — Get a partner access token
curl -X POST https://api.blueprint.ai/v2/partners/authenticate \
-H 'Content-Type: application/json' \
-H 'X-API-Key: YOUR_API_KEY' \
-d '{
"clientId": "YOUR_CLIENT_ID",
"clientSecret": "YOUR_CLIENT_SECRET"
}'Response:
{
"accessToken": "very-long-alphanumeric-string",
"expiresIn": 3600,
"tokenType": "Bearer"
}The token is valid for 1 hour. Cache it and refresh shortly before expiry rather than
authenticating on every request.
Despite
tokenType: "Bearer", this token is not sent as anAuthorization: Bearerheader.
Use theAccess-Tokenheader, as shown below.
Step 2 — Call the API
Every other endpoint requires both headers:
curl https://api.blueprint.ai/v2/partners \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'X-API-Key: YOUR_API_KEY'| Header | Value |
|---|---|
Access-Token | The accessToken from step 1 |
X-API-Key | Your API key |
Both are required on every call, including the ones that create tokens for clinicians.
Recognizing auth failures
These two responses look similar and mean different things:
| Response | Meaning |
|---|---|
403 {"message":"Forbidden"} | X-API-Key is missing or invalid |
403 {"message":"Missing Authentication Token"} | The route does not exist — usually a missing /v2 in your base URL |
401 with a PartnerApiError body | Access-Token has expired — re-authenticate |
403 with a PartnerApiError body | Access-Token is missing, malformed, or not recognized |
404 with a PartnerApiError body | The resource in the path does not exist, or your partner organization does not own it |
The first two come from our API gateway and use a different body shape than application errors. See
Errors.
Step 3 — Get a clinician token (widget integrations only)
To let the embedded widget record on a clinician's behalf, mint a token pair for that clinician. No
clinician password is involved.
curl -X POST https://api.blueprint.ai/v2/clinicians/{clinicianId}/authenticate \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'X-API-Key: YOUR_API_KEY'This endpoint takes no request body.
Response:
{
"AccessToken": "very-long-alphanumeric-string",
"IdToken": "very-long-alphanumeric-string",
"RefreshToken": "very-long-alphanumeric-string",
"ExpiresIn": 600
}These field names are PascalCase, and that matters. Pass this object through to
Blueprint.authenticate()unchanged — the widget readsAccessTokenandRefreshTokenexactly as
spelled. If you rebuild the object with camelCase keys, the widget will not authenticate.The API Reference page for this endpoint currently shows camelCase field names and a
tokenType
field. That reference is wrong; this page is correct.IdTokenis currently identical to
AccessTokenand is reserved — do not depend on it.
| Field | Meaning |
|---|---|
AccessToken | Clinician access token. Valid for 600 seconds (10 minutes). |
RefreshToken | Used to mint new access tokens. Valid for about 7 days. |
ExpiresIn | Access token lifetime in seconds (600). |
IdToken | Reserved. Currently a copy of AccessToken. |
Return the whole object to your frontend and hand it to the widget:
Blueprint.authenticate(clinicianTokens)The widget refreshes itself
You do not need to run a refresh loop. Once the widget has the token pair it renews its own
access token in the background for the life of the refresh token.
That means the refresh token has to reach the browser. Scope it accordingly: it authorizes exactly
one clinician, and it is the same trust boundary as the clinician's own session in your app. If a
clinician logs out of your application, call Blueprint.logout() and stop passing their tokens.
Refresh tokens are single-use and rotate. If a refresh token is replayed after being consumed, all
refresh tokens for that clinician are revoked as a reuse-detection measure and the clinician must
be re-authenticated by your backend. Do not mint one token pair and reuse it across browser sessions
or tabs — call authenticate per session.
What to do next
- Quickstart — a full working sequence from credentials to a generated note
- Errors — the error envelope and every status code you can receive
- Controlling the UI — handing tokens to the embedded widget
Updated 28 days ago
