🚧
The Messaging Service is currently in beta.

Conversations

Conversations allows you to build multi-channel bi-directional messaging workflows. For example, you might create a Conversation where a provider messages with a patient through a web app, and the patient receives and responds to messages via SMS on their phone. Conversations can have several participants on either channel (SMS or chat). Learn more about use cases for Conversations.

ZapEHR Conversations is built on top of Twilio Conversations (opens in a new tab). Chat-channel participants join the Conversation using the Twilio Conversations Client SDKs (opens in a new tab) for web, iOS, and Android. SMS-channel participants send and receive messages to a Twilio Phone number which proxies messages to and from the Conversation.

Conversations on FHIR

Conversations are integrated directly with the FHIR Service. When you create a Conversation, a FHIR Encounter (opens in a new tab) resource is created to document it. Use this encounter to store and retrieve any details that are relevant to your use case. For example you might want to store:

Encounter virtualService

Conversation Encounter resources are just like any other FHIR Encounter you might create except in one thing. Your Create Conversation request creates the FHIR Encounter, its Encounter.virtualService (opens in a new tab) value is automatically set to store the ID of the Twilio Conversation that is created.

If your Project is using FHIR R4, an extension is used to backport the virtualService model into the Encounter because the R4 Encounter (opens in a new tab) resource does not support it:

{
  "encounter": {
    "resourceType": "Encounter",
    "id": "032b5cef-0cb7-42b5-af8f-b4813581c14a",
    "status": "in-progress",
    "subject": {
      "reference": "Patient/11bf5b37-e0b8-42e0-8dcf-dc8c4aefc000"
    },
    "participant": [
      {
        "individual": {
          "reference": "Practitioner/f1d01874-0631-4903-8b32-73b3299b3363",
          "display": "Dr Adam Careful"
        }
      }
    ],
    "extension": [
      {
        "url": "https://extensions.fhir.zapehr.com/encounter-virtual-service-pre-release",
        "extension": [
          {
            "url": "channelType",
            "valueCoding": {
              "system": "https://fhir.zapehr.com/virtual-service-type",
              "code": "twilio-conversations",
              "display": "Twilio Conversations"
            }
          },
          {
            "url": "addressString",
            "valueString": "CH4b95706dd9f344d38bec278d98ec0d58"
          }
        ]
      }
    ]
  }
}

The valueString in the extension's addressString is the Twilio Conversation ID.

Using Conversations

There are four steps to using Conversations:

You can also send messages into a Conversation with an API call using the Send Message endpoint.

Create a Conversation

Create Conversation API Reference (opens in a new tab)

Create a Conversation with the SDK
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: yourAccessToken,
});
 
const response = await zapehr.project.conversation.create({
  encounter: {
    resourceType: 'Encounter',
    id: 'home',
    text: {
      status: 'generated',
      div: '<div xmlns="http://www.w3.org/1999/xhtml">Encounter with patient @example who is at home</div>',
    },
    status: 'finished',
    class: {
      system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode',
      code: 'HH',
      display: 'home health',
    },
    period: {
      start: '2015-01-17T16:00:00+10:00',
      end: '2015-01-17T16:30:00+10:00',
    },
    location: [
      {
        location: {
          reference: '#home',
          display: "Client's home",
        },
        status: 'completed',
        period: {
          start: '2015-01-17T16:00:00+10:00',
          end: '2015-01-17T16:30:00+10:00',
        },
      },
    ],
  },
});

Create Conversation takes just one value in the request body, a FHIR Encounter resource JSON. The endpoint does a few things:

  • Creates the FHIR Encounter
  • Creates a Twilio Conversation
  • Updates the FHIR Encounter to put the Twilio Conversation SID into virtualService as described here.

The created Twilio Conversation has no participants in it at this point.

Update FHIR Encounter

Now that the conversation is created, we will add participants to the FHIR Encounter. This example is for FHIR R4, so the patient is placed into an extension and the provider is listed in the participant array. Adding the participants to the FHIR Encounter is required for the next step, where we will add both paricipants to the twilio conversation.

Add a Participant to a Conversation with the SDK
const fhirClient = new FhirClient({
  accessToken: yourAccessToken,
});
 
const putResult: Encounter = await fhirClient.putResource({
  resourceType: "Encounter",
  id: "cf39e0ec-067a-4808-a46b-5014299e9906",
  text: {
    status: "generated",
    div: "<div xmlns=\"http://www.w3.org/1999/xhtml\">Encounter with patient @example who is at home</div>"
  },
  subject: {
    reference: "Patient/11bf4b17-e0b8-42e0-8dcf-dc8c4aefc000"
  },
  participant: [
    {
      individual: {
        reference: "Practitioner/471ba2a1-a6a1-4cfa-b01e-c558c6863949",
      }
    }
  ],
  status: "finished",
  class: {
    system: "http://terminology.hl7.org/CodeSystem/v3-ActCode",
    code: "HH",
    display: "home health"
  },
  period: {
    start: "2015-01-17T16:00:00+10:00",
    end: "2015-01-17T16:30:00+10:00"
  },
  location: [
    {
      location: {
        reference: "#home",
        display: "Client's home"
      },
      status: "completed",
      period: {
        start: "2015-01-17T16:00:00+10:00",
        end: "2015-01-17T16:30:00+10:00"
      }
    }
  ],
  extension: [
    {
      url: "https://extensions.fhir.zapehr.com/encounter-virtual-service-pre-release",
      extension: [
        {
          url: "channelType",
          valueCoding: {
            system: "https://fhir.zapehr.com/virtual-service-type",
            code: "twilio-conversations",
            display: "Twilio Conversations"
          }
        },
        {
          url: "addressString",
          valueString: "CH4b95706dd9f344d38bec278d98ec0d58"
        }
      ]
    },
    {
      url: "https://extensions.fhir.zapehr.com/encounter-other-participants",
      extension: [
        {
          url: "https://extensions.fhir.zapehr.com/encounter-other-participant",
          extension: [
            {
              url: "reference",
              valueReference: {
                reference: "Patient/11bf4b17-e0b8-42e0-8dcf-dc8c4aefc000"
              }
            }
          ]
        }
      ]
    }
  ]
});

Add Participants

Add Participants API Reference (opens in a new tab)

Add a Participant to a Conversation with the SDK
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: yourAccessToken,
});
 
await zapehr.project.conversation.participant({
  conversationId: 'CH8277a50cb9cf44809c7da3be1b88723c',
  encounterReference: 'Encounter/cf39e0ec-067a-4808-a46b-5014299e9906',
  participants: [
    {
      participantReference: 'Practitioner/471ba2a1-a6a1-4cfa-b01e-c558c6863949',
      channel: 'chat',
    },
    {
      participantReference: "Patient/11bf4b17-e0b8-42e0-8dcf-dc8c4aefc000",
      channel: "chat"
    }
  ],
});

To add participants to a Conversation you specify two things in the request body:

  • encounterReference — A reference to a FHIR Encounter that was created using Create Conversation.
  • participants — An array of participants to add to the Conversation each containing:

participantReference

There are two key details to understand about the participantReference in order to successfully add your actors to the Conversation.

First, every participantReference must also be in Encounter.participant.actor. This helps to keep the documentation of who participated in the Conversation up to date in the FHIR Encounter.

Second, if the channel is chat, then the participant will be using a token from Get Token to join the Conversation with the Twilio Conversations SDKs. This token has the actor's ID as a claim, and it is their key to connecting to the Conversation with the Twilio SDKs.

When the channel is chat, the Add Participants endpoint updates the Twilio Conversation to allow actors with certain IDs to be able to connect. It looks up the actor ID from the participantReference value. In order for this to work, participantReference must be the FHIR profile of the Developer, User, or M2M Client that is going to use a token from Get Token to connect to the Conversation.

participantReference for FHIR R4B

At a high level, participantReference functions in the same way for R4B as it does for R5. The difference is where the references are expected to be stored. Instead of storing all participants in Encounter.participant.actor, practitioners are stored in Encounter.participant.individual and patients are stored in an extension. See the updating FHIR encounter example for more details.

Get Token

Get Token API Reference (opens in a new tab)

In order to connect to a Conversation as a chat-channel participant, invoke the Get Token endpoint as the Developer, User, or M2M Client (actor) who needs to connect. This returns a Twilio Conversation JWT with the actor's identity.

Decoded token from the Get Token endpoint
{
  "jti": "SKc53238564cd4efaf8fd4098f2fecca9c-1698785068",
  "grants": {
    "identity": "ca02393f-b2bf-4142-bec9-abcdefg01234",
    "chat": {
      "service_sid": "IS5411229312bd4940a4cba4ecade7b1c8"
    }
  },
  "iat": 1698785068,
  "exp": 1698788668,
  "iss": "SKc5323856eee4efaf7fd4098f2cebca9c",
  "sub": "AC3d7e1066c7fb6c701a5d6085f7626f3c"
}

The value in grants.identity is the actor's ID. In order to connect to the Conversation with this token, the actor must be added to the conversation.

Send Message

Besides sending messages as chat-channel and SMS-channel participants, you can also send messages with an API call using the Send Message endpoint (opens in a new tab).

This is useful for sending automated messages into a Conversation. For example, you might use the send message endpoint to introduce participants in a newly made conversation, or to remind patients about upcoming appointments.

While this can also be done with Transactional SMS, the advantage of using Conversations is that you can have a two-way conversation with the patient in the event they respond to the automated message.

Send a message to a Conversation with the SDK
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: yourAccessToken,
});
 
await zapehr.project.conversation.message({
  conversationId,
  message: 'Reminder, your appointment at Dentists R Us is scheduled for Friday 12/29/23 at 2:30 PM.',
});

Compliance

ZapEHR maintains a BAA with Twilio (opens in a new tab) which is offered through its enterprise-tier plans. When building on ZapEHR, your BAA with ZapEHR (opens in a new tab) acts as a chain to Twilio and our other service providers, so what you build on ZapEHR Conversations may be HIPAA compliant.

As stated in ZapEHR's BAA, HIPAA compliance is a shared responsibility and building on ZapEHR does not automatically make what you build HIPAA-compliant. You are responsible for doing your part to safeguard PHI when using ZapEHR. In addition, if you make use of Twilio with tokens or credentials not vended by ZapEHR, your usage is not covered by our BAA. Learn more about HIPAA Compliance and ZapEHR.

🚧

The Messaging Service does not yet support FHIR R5 (opens in a new tab).