Quickstart

This walks the full path from credentials to a generated progress note. It uses the sandbox
environment and curl; every call maps directly onto the API Reference.

You will need the clientId, clientSecret, and apiKey Blueprint provisioned for you. If you do
not have them, contact your Blueprint representative.

Set up your shell:

export BP_BASE='https://api.staging.blueprint.ai/v2'
export BP_API_KEY='your-api-key'
export BP_CLIENT_ID='your-client-id'
export BP_CLIENT_SECRET='your-client-secret'

Note the /v2 in the base URL — it is part of the path, not a header. See
Environments & Base URLs.

1. Authenticate your backend

curl -sS -X POST "$BP_BASE/partners/authenticate" \
  -H 'Content-Type: application/json' \
  -H "X-API-Key: $BP_API_KEY" \
  -d "{\"clientId\":\"$BP_CLIENT_ID\",\"clientSecret\":\"$BP_CLIENT_SECRET\"}"
{
  "accessToken": "very-long-alphanumeric-string",
  "expiresIn": 3600,
  "tokenType": "Bearer"
}

Save it. This token lasts an hour and goes on every subsequent call as Access-Token:

export BP_TOKEN='very-long-alphanumeric-string'

Confirm it works:

curl -sS "$BP_BASE/partners" \
  -H "Access-Token: $BP_TOKEN" -H "X-API-Key: $BP_API_KEY"
{ "id": "00000000-0000-0000-0000-000000000000", "callbackUrl": null }

callbackUrl is where webhooks will be delivered. It is null until you set it in step 6.

2. Create an organization and a clinic

An organization is a customer of yours — a practice or group. A clinic is a location within
it. Every organization needs at least one clinic; if a practice has no locations to model, create
one clinic that mirrors the organization. See Concepts.

curl -sS -X POST "$BP_BASE/organizations" \
  -H 'Content-Type: application/json' \
  -H "Access-Token: $BP_TOKEN" -H "X-API-Key: $BP_API_KEY" \
  -d '{"name":"Evergreen Behavioral Health","externalId":"org-8842"}'

Returns 201:

{
  "id": "11111111-1111-1111-1111-111111111111",
  "name": "Evergreen Behavioral Health",
  "externalId": "org-8842"
}
export BP_ORG='11111111-1111-1111-1111-111111111111'

curl -sS -X POST "$BP_BASE/organizations/$BP_ORG/clinics" \
  -H 'Content-Type: application/json' \
  -H "Access-Token: $BP_TOKEN" -H "X-API-Key: $BP_API_KEY" \
  -d '{"name":"Evergreen — Downtown","externalId":"clinic-1"}'

Returns 201:

{
  "id": "22222222-2222-2222-2222-222222222222",
  "name": "Evergreen — Downtown",
  "externalId": "clinic-1"
}

Set externalId on everything you create. It is your own identifier — a row ID or MRN — and it
is how you reconcile your records with Blueprint's later. Because the API has no idempotency keys,
externalId is also the only reliable way to detect a duplicate after a failed retry. See
Pagination & Limits.

3. Create a clinician

export BP_CLINIC='22222222-2222-2222-2222-222222222222'

curl -sS -X POST "$BP_BASE/clinics/$BP_CLINIC/clinicians" \
  -H 'Content-Type: application/json' \
  -H "Access-Token: $BP_TOKEN" -H "X-API-Key: $BP_API_KEY" \
  -d '{
    "firstName": "Dana",
    "lastName": "Okonkwo",
    "email": "[email protected]",
    "externalId": "user-5501"
  }'

Returns 201:

{
  "id": "33333333-3333-3333-3333-333333333333",
  "firstName": "Dana",
  "lastName": "Okonkwo",
  "email": "[email protected]",
  "externalId": "user-5501",
  "clinicId": "22222222-2222-2222-2222-222222222222"
}

Creating a clinician whose email already exists returns 409. Search first with
GET /clinics/{clinicId}/clinicians?email=... if you are not sure.

4. Create a client

Clients belong to a clinician.

export BP_CLINICIAN='33333333-3333-3333-3333-333333333333'

curl -sS -X POST "$BP_BASE/clinicians/$BP_CLINICIAN/clients" \
  -H 'Content-Type: application/json' \
  -H "Access-Token: $BP_TOKEN" -H "X-API-Key: $BP_API_KEY" \
  -d '{
    "firstName": "Jordan",
    "lastName": "Reyes",
    "dateOfBirth": "1991-04-17",
    "pronouns": "they/them/theirs",
    "email": "[email protected]",
    "phoneNumber": "+15555550123",
    "externalId": "mrn-77120"
  }'

Returns 201 with a ClientDTO.

phoneNumber must include a + calling code. 5555550123 is rejected with 400
phoneNumber should include calling code. Send +15555550123. Omit the field entirely if you do
not have a normalized number.

Find them again later without storing Blueprint's ID:

curl -sS "$BP_BASE/clinicians/$BP_CLINICIAN/clients?externalId=mrn-77120" \
  -H "Access-Token: $BP_TOKEN" -H "X-API-Key: $BP_API_KEY"

5. Get a note

From here the path depends on who captures the audio.

Option A — Blueprint captures the audio (widget)

Mint a clinician token and hand it to the embedded UI:

curl -sS -X POST "$BP_BASE/clinicians/$BP_CLINICIAN/authenticate" \
  -H "Access-Token: $BP_TOKEN" -H "X-API-Key: $BP_API_KEY"

No request body. Returns:

{
  "AccessToken": "very-long-alphanumeric-string",
  "IdToken": "very-long-alphanumeric-string",
  "RefreshToken": "very-long-alphanumeric-string",
  "ExpiresIn": 600
}

Return that object to your frontend unchanged — the field names are PascalCase and the widget
depends on them. Then:

<script>
  window.blueprintSettings = {
    containerId: 'blueprint-container',
    isMinifiedView: true
  }
</script>
<script src="https://embed.staging.blueprint.ai/index.min.js"></script>
<div id="blueprint-container"></div>

<script>
  Blueprint.authenticate(clinicianTokens)
  Blueprint.selectClient('CLIENT_ID_FROM_STEP_4')

  Blueprint.onNoteGenerated(async ({ sessionId }) => {
    const note = await myBackend.fetchProgressNote(sessionId)
    insertIntoChart(note)
  })
</script>

window.blueprintSettings must be assigned before the script tag. See
Customizing the Experience and
Controlling the UI.

Option B — You capture the audio (API only)

Host the recording at a URL Blueprint can fetch, then create a session:

curl -sS -X POST "$BP_BASE/clients/$BP_CLIENT/sessions" \
  -H 'Content-Type: application/json' \
  -H "Access-Token: $BP_TOKEN" -H "X-API-Key: $BP_API_KEY" \
  -d '{
    "fileUrl": "https://files.example.com/sessions/abc123.mp3",
    "setting": "telehealth",
    "noteType": "soap",
    "sessionExternalId": "appt-99031"
  }'

Returns 201 with the session, including progressNoteIds. Blueprint downloads the audio and
generates the note asynchronously. See API Only Integrations for the
constraints on fileUrl.

6. Receive the note

Register a callback URL once:

curl -sS -X PATCH "$BP_BASE/partners/$BP_PARTNER_ID" \
  -H 'Content-Type: application/json' \
  -H "Access-Token: $BP_TOKEN" -H "X-API-Key: $BP_API_KEY" \
  -d '{"callbackUrl":"https://your-app.example.com/blueprint/webhooks"}'

When the note is ready you receive:

{
  "eventType": "progress_note_generated",
  "timeStamp": "2026-07-29T18:04:11.522Z",
  "payload": {
    "progressNoteId": "44444444-4444-4444-4444-444444444444",
    "sessionId": "55555555-5555-5555-5555-555555555555",
    "sessionExternalId": "appt-99031",
    "clientId": "...",
    "clinicianId": "...",
    "clinicId": "...",
    "organizationId": "...",
    "progressNoteUrl": "https://api.staging.blueprint.ai/v2/sessions/555.../progress-note"
  }
}

Verify the X-Blueprint-Signature header before trusting it, then GET the progressNoteUrl with
your normal headers:

{
  "id": "44444444-4444-4444-4444-444444444444",
  "sessionId": "55555555-5555-5555-5555-555555555555",
  "isLoading": false,
  "note": [
    { "key": "subjective", "title": "Subjective", "content": "Client reported feeling overwhelmed by..." },
    { "key": "objective",  "title": "Objective",  "content": "Therapist guided client through..." },
    { "key": "assessment", "title": "Assessment", "content": "Client is experiencing..." },
    { "key": "plan",       "title": "Plan",       "content": "Client will continue to..." }
  ],
  "template": {
    "noteType": "soap",
    "sessionType": "individual",
    "title": "SOAP",
    "sections": [
      { "key": "subjective", "title": "Subjective" },
      { "key": "objective",  "title": "Objective" },
      { "key": "assessment", "title": "Assessment" },
      { "key": "plan",       "title": "Plan" }
    ]
  }
}

note is an ordered array of sections rather than a keyed object, so you can render an unknown note
type without knowing its sections in advance. Use template.sections for the expected section list
and note[].content for the text.

Signature verification is the one step you must not skip — see
Listening to Webhooks for a correct implementation.

Where to go next


Did this page help you?