🚧
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.

Oystehr 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:

Linking SMS Participants to Conversations

The Conversations service will automatically record every message sent to a Conversation in a FHIR Communication record. In order to connect SMS participants to their FHIR profiles, the participant must have a telecom property with a system of sms and a value that is a valid phone number, with country code. For example:

{
  "resourceType": "Patient",
  "telecom": [
    {
      "system": "sms",
      "value": "+11231231234"
    }
  ]
}

A Patient may also have a valid telecom entry in a contact property. For example:

{
  "resourceType": "Patient",
  "contact": [
    {
      "telecom": [
        {
          "system": "sms",
          "value": "+11231231234"
        }
      ]
    }
  ]
}

Chat participants are linked automatically.

Encounter virtualService

Conversation Encounter resources are just like any other FHIR Encounter you might create except in one thing. When 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 R4B, an extension is used to backport the virtualService model from FHIR R5 into the Encounter because the R4B 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.

Encounter participants

Conversation Encounter resources track references to their subject (a Patient or Group of Patients) and their participants. On its face this should be a good match to telemedicine workflows. However, at the time the FHIR R4B specification was created, telemedicine was not as popular as it is today. In FHIR R4B, a Patient cannot be both the subject of an Encounter and a participant. Oystehr uses an extension to provide a space for additional participants.

Oystehr M2M accounts can also be added as participants to an Encounter by including their FHIR Device resource in the encounter-other-participants extension.

If your Project is using FHIR R4B, use the encounter-other-participants extension to add Patient or Device references to an Encounter:

{
  "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-other-participants",
        "extension": [
          {
            "url": "https://fhir.zapehr.com/encounter-other-participant",
            "extension": [
              {
                "url": "reference",
                "valueReference": "Patient/11bf4b17-e0b8-42e0-8dcf-dc8c4aefc000"
              }
            ]
          }
        ]
      }
    ]
  }
}

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 v2 SDK
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
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

Check out the API Reference (opens in a new tab)

Now that the conversation is created, we will add participants to the FHIR Encounter. This example is for FHIR R4B, 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 participants to the Twilio conversation.

For the sake of example, we are adding the participants to the FHIR Encounter in a separate step from creating it. This isn't a hard requirement; if you know the participants at the time of creating the Encounter, you can include them in the Encounter definition provided to Create Conversation.

Add the Participants to the FHIR Encounter with the v2 SDK
import { Encounter } from 'fhir/r4b'; // npm install @types/fhir
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
const result = await zapehr.fhir.update<Encounter>({
  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://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 v2 SDK
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
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 — A reference to a Patient, Practitioner, RelatedPerson, or Device FHIR resource. More below.
    • channel — Either chat or sms.
    • phoneNumber — A phone number for the participant only if channel = sms.

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 be in the Encounter's participant list or its encounter-other-participants extension.

Second, if the channel is chat, then the participant will join the Conversation using the Twilio Conversations SDK (opens in a new tab) and a token from the Oystehr Get Token endpoint. The participantReference must be the FHIR profile of the Developer, User, or M2M Client that is going to make the request to the Get Token endpoint.

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 who needs to connect. This returns a Twilio Conversation JWT with their 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"
}

In order to connect to the Conversation with this token, the actor must have been added to the conversation.

Additional Conversations features

Send Message

Besides enabling chat-channel and SMS-channel participants to send messages, you can also send messages directly to a Conversation 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, it may fit your use-case better to utilize already-existing Conversations.

Send a message to a Conversation with the v2 SDK
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
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.',
});

Remove Participants

You can remove previously added participants from a Conversation with the Remove Participants endpoint (opens in a new tab).

Remove a Participant from a Conversation with the v2 SDK
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
await zapehr.project.conversation.removeParticipant({
  conversationId: 'CH8277a50cb9cf44809c7da3be1b88723c',
  encounterReference: 'Encounter/cf39e0ec-067a-4808-a46b-5014299e9906',
  participantReference: 'Practitioner/471ba2a1-a6a1-4cfa-b01e-c558c6863949',
});

To remove participants from a Conversation you specify two things in the request body:

Compliance

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

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

🚧

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