Send a Patient's Visit Summary

A patient has asked that a document you hold reach their referring provider: a visit summary, a lab result, a discharge note. Send that data via Direct Secure Message.

Three steps:

StepWhat you doEndpoint
1Contribute the patient and the documentPOST /4_0_0/Bundle/$merge
2Instruct b.well to transmit it over DirectPOST /v1/Task
3Confirm it arrivedGET /v1/Task/{id}
❗️

Step 1 is not optional

The Task in step 2 references documents by the ids $merge returns, and b.well rejects a Task whose documents it cannot find.



Before you begin

b.well issues these to your organization during onboarding:

  • OAuth client id and client secret, per environment
  • Your organization slug, used in meta.security on every resource you contribute
  • Your Direct address, registered administratively with b.well

Your credentials arrive pre-scoped. You do not request or send OAuth scopes.

📘

Direct addresses are provisioned, not self-service

b.well verifies your sender-direct-address belongs to a domain registered to your client before it will send; an unregistered address fails with sender-address-not-authorized. This happens during onboarding — not at integration time, and not as a FHIR resource you create.

EnvironmentBase URL
Sandboxhttps://api.client-sandbox.icanbwell.com
Productionhttps://api.icanbwell.com
👍

Begin in Sandbox

Examples below use the Sandbox base URL. Substitute your own values for your-org-slug, https://your-org.example.com, and the placeholder credentials — all example data is fictional.


Authenticate

curl --request POST \
  --url https://api.descope.com/oauth2/v1/apps/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data client_id=<your_client_id> \
  --data client_secret=<your_client_secret> \
  --data grant_type=client_credentials

Use the returned access_token as your Bearer token. Tokens last 600 seconds, so re-authenticate on a 401 rather than caching one for the life of a batch job.

Every request below also sends Content-Type: application/fhir+json, Accept: application/fhir+json, and an X-Request-Id UUID you generate per attempt.

Log that id. It is how b.well locates your request when you raise a support issue.


Step 1 — Contribute the patient and document

curl -X POST https://api.client-sandbox.icanbwell.com/4_0_0/Bundle/$merge \
  -H "Content-Type: application/fhir+json" \
  -H "Accept: application/fhir+json" \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Request-Id: $(uuidgen)" \
  -d '@bundle.json'

One submission carries four resources: a Patient, a Person linked to it, a DocumentReference, and the Binary holding the file.

Rules that matter:

  • Bundle.type is collection.
  • Every resource carries meta.source and a meta.security block with owner, access, and sourceAssigningAuthority, all set to your org slug.
  • The Binary holds the file inline as base64. The DocumentReference points at it by URL rather than embedding the bytes twice, and that URL uses the resolved environment base URL, with a Binary id matching the Binary in the same bundle.
  • Keep a submission under 20 MB total, including the base64. Split larger document sets.

Example request payload

{
  "resourceType": "Bundle",
  "type": "collection",
  "entry": [
    {
      "resource": {
        "resourceType": "Patient",
        "id": "9f1c1c8e-3a4b-4c2f-9d3e-6a7b8c9d0e1f",
        "meta": {
          "source": "https://your-org.example.com",
          "security": [
            { "system": "https://www.icanbwell.com/owner",                    "code": "your-org-slug" },
            { "system": "https://www.icanbwell.com/access",                   "code": "your-org-slug" },
            { "system": "https://www.icanbwell.com/sourceAssigningAuthority", "code": "your-org-slug" }
          ]
        },
        "identifier": [
          {
            "use": "usual",
            "type": {
              "coding": [
                { "system": "http://terminology.hl7.org/CodeSystem/v2-0203", "code": "MR", "display": "Medical record number" }
              ]
            },
            "system": "https://your-org.example.com/mrn",
            "value": "MRN-0001842"
          }
        ],
        "active": true,
        "name": [ { "use": "official", "family": "Doe", "given": ["Jane", "M"] } ],
        "gender": "female",
        "birthDate": "1964-01-01",
        "address": [
          { "use": "home", "line": ["1200 Congress Ave"], "city": "Austin", "state": "TX", "postalCode": "78701", "country": "US" }
        ]
      }
    },
    {
      "resource": {
        "resourceType": "Person",
        "id": "2b7de4a1-5f60-4d18-8b0c-1e2f3a4b5c6d",
        "meta": {
          "source": "https://your-org.example.com",
          "security": [
            { "system": "https://www.icanbwell.com/owner",                    "code": "your-org-slug" },
            { "system": "https://www.icanbwell.com/access",                   "code": "your-org-slug" },
            { "system": "https://www.icanbwell.com/sourceAssigningAuthority", "code": "your-org-slug" }
          ]
        },
        "identifier": [
          { "system": "https://your-org.example.com/person", "value": "PSN-77213" }
        ],
        "active": true,
        "name": [ { "use": "official", "family": "Doe", "given": ["Jane", "M"] } ],
        "gender": "female",
        "birthDate": "1964-01-01",
        "link": [
          { "target": { "reference": "Patient/9f1c1c8e-3a4b-4c2f-9d3e-6a7b8c9d0e1f" } }
        ]
      }
    },
    {
      "resource": {
        "resourceType": "DocumentReference",
        "id": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
        "meta": {
          "source": "https://your-org.example.com",
          "security": [
            { "system": "https://www.icanbwell.com/owner",                    "code": "your-org-slug" },
            { "system": "https://www.icanbwell.com/access",                   "code": "your-org-slug" },
            { "system": "https://www.icanbwell.com/sourceAssigningAuthority", "code": "your-org-slug" }
          ]
        },
        "status": "current",
        "docStatus": "final",
        "type": {
          "coding": [
            { "system": "http://loinc.org", "code": "34133-9", "display": "Summary of episode note" }
          ],
          "text": "Visit summary"
        },
        "subject": { "reference": "Patient/9f1c1c8e-3a4b-4c2f-9d3e-6a7b8c9d0e1f" },
        "date": "2026-08-10T18:04:00-04:00",
        "content": [
          {
            "attachment": {
              "contentType": "application/pdf",
              "url": "https://api.client-sandbox.icanbwell.com/v1/Binary/d7df09d0-4538-4839-868f-20c6997cab38",
              "title": "Visit summary 2026-08-10.pdf",
              "creation": "2026-08-10T18:04:00-04:00"
            }
          }
        ]
      }
    },
    {
      "resource": {
        "resourceType": "Binary",
        "id": "d7df09d0-4538-4839-868f-20c6997cab38",
        "meta": {
          "source": "https://your-org.example.com",
          "security": [
            { "system": "https://www.icanbwell.com/owner",                    "code": "your-org-slug" },
            { "system": "https://www.icanbwell.com/access",                   "code": "your-org-slug" },
            { "system": "https://www.icanbwell.com/sourceAssigningAuthority", "code": "your-org-slug" }
          ]
        },
        "contentType": "application/pdf",
        "data": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2c+PgplbmRvYmoK"
      }
    }
  ]
}

Capture the ids, and check every entry

200 OK returns one result per submitted resource.


Example $merge response

[
  { "resourceType": "Patient",           "id": "9f1c1c8e-3a4b-4c2f-9d3e-6a7b8c9d0e1f", "uuid": "9f1c1c8e-3a4b-4c2f-9d3e-6a7b8c9d0e1f", "created": true, "updated": false, "sourceAssigningAuthority": "your-org-slug" },
  { "resourceType": "Person",            "id": "2b7de4a1-5f60-4d18-8b0c-1e2f3a4b5c6d", "uuid": "2b7de4a1-5f60-4d18-8b0c-1e2f3a4b5c6d", "created": true, "updated": false, "sourceAssigningAuthority": "your-org-slug" },
  { "resourceType": "DocumentReference", "id": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f", "uuid": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f", "created": true, "updated": false, "sourceAssigningAuthority": "your-org-slug" },
  { "resourceType": "Binary",            "id": "d7df09d0-4538-4839-868f-20c6997cab38", "uuid": "d7df09d0-4538-4839-868f-20c6997cab38", "created": true, "updated": false, "sourceAssigningAuthority": "your-org-slug" }
]

Persist the Patient id and each DocumentReference id. Step 2 needs both.


❗️

A 200 does not mean every resource persisted

A validation error on one entry does not fail the request; that entry comes back as an OperationOutcome instead of a merge result. Iterate the array and treat any OperationOutcome as a failure for that resource. A DocumentReference that silently failed here resurfaces in step 2 as document-not-found, which is much harder to trace back.

Retrying is safe

b.well matches on resource.id plus your org slug and returns the same uuid. created: false, updated: false means the resource already existed and your payload was identical — so re-sending an unchanged bundle is a no-op.


Step 2 — Submit the Direct send Task

A Task with code send-direct-message asks b.well to transmit the documents to a named provider.

Prerequisites: the Patient and every DocumentReference exist and persisted; your sender-direct-address is registered; and you have Organization and Practitioner references for sender and recipient.

Addressing the recipient

Every Task uses one of two modes:

ModeYou supplyTo address
Directoryrecipient-practitioner and recipient-organizationResolved from the practitioner's role at that organization
Explicitrecipient-direct-addressUsed exactly as given

Addresses are bare strings with no mailto: prefix and no wrapping Endpoint resource. One recipient per Task; to reach several providers, submit several Tasks sharing a groupIdentifier.

🚧

Prefer Directory mode

b.well confirms an explicit address is well-formed and that a trust path exists, but not that it belongs to the clinician you meant. One transposed character that resolves to a different real Direct address delivers the patient's records to the wrong provider, and Direct reports that as success. Treat operator-typed addresses as the highest-risk path in this workflow.

curl -X POST https://api.client-sandbox.icanbwell.com/v1/Task \
  -H "Content-Type: application/fhir+json" \
  -H "Accept: application/fhir+json" \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Request-Id: $(uuidgen)" \
  -d '@task.json'

Example request payload

{
  "resourceType": "Task",
  "meta": {
    "source": "https://your-org.example.com",
    "security": [
      { "system": "https://www.icanbwell.com/owner",  "code": "your-org-slug" },
      { "system": "https://www.icanbwell.com/access", "code": "your-org-slug" }
    ]
  },
  "identifier": [
    { "system": "https://your-org.example.com/tasks", "value": "TSK-004417" }
  ],
  "groupIdentifier": {
    "system": "https://your-org.example.com/referrals",
    "value": "REF-2026-0881"
  },
  "status": "requested",
  "intent": "order",
  "code": {
    "coding": [
      {
        "system": "https://fhir.icanbwell.com/CodeSystem/task-code",
        "code": "send-direct-message",
        "display": "Send documents via Direct secure messaging"
      }
    ]
  },
  "for": { "reference": "Patient/9f1c1c8e-3a4b-4c2f-9d3e-6a7b8c9d0e1f" },
  "authoredOn": "2026-08-11T14:35:00-04:00",
  "requester": { "reference": "Organization/5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b" },
  "reasonCode": {
    "coding": [
      { "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason", "code": "PATRQT", "display": "patient requested" }
    ],
    "text": "Patient asked that records be sent to her referring provider."
  },
  "input": [
    {
      "type": { "coding": [ { "system": "https://fhir.icanbwell.com/CodeSystem/task-input-type", "code": "sender-organization" } ] },
      "valueReference": { "reference": "Organization/5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b" }
    },
    {
      "type": { "coding": [ { "system": "https://fhir.icanbwell.com/CodeSystem/task-input-type", "code": "sender-direct-address" } ] },
      "valueString": "[email protected]"
    },
    {
      "type": { "coding": [ { "system": "https://fhir.icanbwell.com/CodeSystem/task-input-type", "code": "recipient-practitioner" } ] },
      "valueReference": { "reference": "Practitioner/4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b" }
    },
    {
      "type": { "coding": [ { "system": "https://fhir.icanbwell.com/CodeSystem/task-input-type", "code": "recipient-organization" } ] },
      "valueReference": { "reference": "Organization/8c1d2e3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f" }
    },
    {
      "type": { "coding": [ { "system": "https://fhir.icanbwell.com/CodeSystem/task-input-type", "code": "document" } ] },
      "valueReference": { "reference": "DocumentReference/c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f" }
    },
    {
      "type": { "coding": [ { "system": "https://fhir.icanbwell.com/CodeSystem/task-input-type", "code": "message-subject" } ] },
      "valueString": "Records for referral REF-2026-0881"
    },
    {
      "type": { "coding": [ { "system": "https://fhir.icanbwell.com/CodeSystem/task-input-type", "code": "message-body" } ] },
      "valueString": "Attached is the visit summary from the 2026-08-10 encounter, sent at the patient's request."
    }
  ]
}

Repeat the document input once per DocumentReference. All documents on one Task go out as a single Direct message.

Optional but worth setting: sender-practitioner populates the message display name, reasonReference points at a Consent where written authorization backs the disclosure, and restriction.period.end sets a delivery deadline after which the Task fails rather than staying in flight.

❗️

No PHI in the subject line

Direct encrypts message content, but subject lines are widely logged by intermediate systems and surfaced in notification emails. Reference the patient by an internal id or referral number, as above, and never by name or date of birth.

🚧

201 Created means the Task was accepted, not that the message was sent

Save the returned id. Validation failures that depend on your inputs like unauthorized sender address, malformed recipient, and missing document, all surface here. Failures that depend on address resolution and trust surface later, in step 3.


Step 3 — Confirm it arrived

curl https://api.client-sandbox.icanbwell.com/v1/Task/3d9f5a71-2c84-4e16-9b03-7a8c9d0e1f2a \
  -H "Accept: application/fhir+json" \
  -H "Authorization: Bearer <access_token>"

Task.status is the FHIR lifecycle; Task.businessStatus is the Direct-specific detail within it. The pair you are waiting for is:

"status": "completed",  "businessStatus": "mdn-dispatched"

That means delivered, and it is terminal. Poll no more often than once per minute, back off exponentially, and stop at any terminal state : completed, failed, rejected, or cancelled.

🚧

mdn-processed is not delivery

It means a HISP accepted custody and verified trust; the records can still bounce before reaching the recipient's system. If your workflow tells a care coordinator "records sent," gate that on mdn-dispatched.

On success, Task.output carries the evidence: most usefully direct-message-id, the RFC 5322 Message-ID. Log it; it is the correlation key for any support request about that send.

On failure, Task.output.failure-reason classifies why, and tells you whether b.well will retry. A Task at in-progress with a rising attempt-count is being worked on. Do not submit a duplicate. Create a new Task only once the existing one is terminal and the failure is something you can fix: a corrected address, a document that now exists, a narrowed recipient. Use a new identifier, reuse the groupIdentifier.

❗️

Every retry puts another copy of the patient's records in flight

Confirm the address before resending after a notification-timeout, which otherwise tends to time out again for the same reason.



Errors

StatusWhat to do
400 / 422Malformed or invalid FHIR. Do not retry without changing the payload.
401Token expired. They last 600 seconds. Re-authenticate and retry.
403Your credentials are not authorized for this operation. Contact b.well; retrying will not help.
200 on $mergeCheck every entry. See Step 1.

Did this page help you?