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:

CredentialPurpose
clientIdIdentifies your partner application
clientSecretSecret for your partner application
apiKeyAPI 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 an Authorization: Bearer header.
Use the Access-Token header, 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'
HeaderValue
Access-TokenThe accessToken from step 1
X-API-KeyYour 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:

ResponseMeaning
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 bodyAccess-Token has expired — re-authenticate
403 with a PartnerApiError bodyAccess-Token is missing, malformed, or not recognized
404 with a PartnerApiError bodyThe 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 reads AccessToken and RefreshToken exactly 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. IdToken is currently identical to
AccessToken and is reserved — do not depend on it.

FieldMeaning
AccessTokenClinician access token. Valid for 600 seconds (10 minutes).
RefreshTokenUsed to mint new access tokens. Valid for about 7 days.
ExpiresInAccess token lifetime in seconds (600).
IdTokenReserved. 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

Did this page help you?