As a value- and/or risk-based care delivery provider, you strive to manage a patient’s continuum of care, within and outside of your organization. This involves timely interventions to events of interest, such as:

  • When a patient is admitted, discharged, or transferred (ADT) from an inpatient encounter
  • When the patient is prescribed a medication or picks up a medication
  • When a patient has a new lab result

Rather than requiring you to make API calls against the Zus FHIR Store to discover whether a data-generating event occurred, Zus can securely send a message to your URL.

What is a webhook?

A webhook is a user-defined HTTPS callback. When you build your application using Zus APIs, you may want to receive inbound HTTPS requests from Zus. These request payloads contain information about data creation and update activity in the Zus FHIR Store - for instance, when a patient picks up a prescription for a new medication.

👍

If you would like to configure a ZusHook for your account, please submit a support ticket to us here.

Getting Started with ZusHooks

To begin setting up your ZusHook, you will need to specify a webhook URL, filter criteria, and authentication method.

Webhook URL

To react to data and develop your own trigger-action workflow automations, you will need to tell Zus what URL to securely send these requests to and acknowledge that the request was received by your application with a standard HTTP 200 OK response.

Filter

ZusHooks will send an outbound HTTP request to your webhook URL when a FHIR resource is created or updated that matches the specified filter criteria. Filters are constructed as JQ queries and can be used to alert for resources that, for example:

  • Contain / do not contain a particular value such as a patient identifier system
  • Pertain to a set of Zus Universal Patient IDs
  • Have been updated to a completed status (e.g. Appointments, Encounters)
  • Come from a given data type such as ADT or Medication Alerts

It's also recommended that the customer implement a queue on their endpoint.

Authentication

Basic (username/password) and OAuth client credentials authentication (https) methods are supported.

OAuth values

  • webhookUrl
  • clientId
  • clientSecret
  • tokenUrl
  • audience

When secured with OAuth, Zus will send the entire FHIR resource in the response body:

{
    “message_id”: “123”,
    “source”: “com.zushealth.zushooks”,
    “time”: “2023-07-17T13:48:32Z”,
    “resourceId”: “Encounter/c020d8eb-ea59-492b-862f-c27f9556f628”,
    “ownerId”: “builder/abc",
    “resourceIncluded”: true,
    “resource”: {
      "meta": {
        "extension": [
            {
                "url": "https://zusapi.com/created-at",
                "valueInstant": "2023-07-17T13:48:29.991+00:00"
            }
        ],
        "versionId": "1",
        "lastUpdated": "2023-07-17T13:48:53.526+00:00",
        "tag": [
            {
                "system": "https://zusapi.com/accesscontrol/owner",
                "code": "builder/844ad945-13d1-4c18-9f03-8753df1579b3"
            },
            {
                "system": "https://zusapi.com/thirdparty/source",
                "code": "Sample ADT Network"
            }
        ]
    },
    "extension": [
        {
            "url": "https://zusapi.com/fhir/identifier/universal-id",
            "valueString": "75bf769f-d309-4243-a98d-0d12e339b468"
        }
    ],
    "identifier": [
        {
            "use": "official",
            "type": {
                "coding": [
                    {
                        "system": "http://terminology.hl7.org/CodeSystem/v2-0203",
                        "code": "VN",
                        "display": "visit number"
                    }
                ],
                "text": "visit number"
            },
            "value": "185423165"
        }
    ],
    "status": "finished",
    "class": {
        "system": "http://terminology.hl7.org/CodeSystem/class-coding",
        "code": "E",
        "display": "Emergency"
    },
    "subject": {
        "reference": "Patient/f61b4027-d758-4686-ab96-e0e1d1bedc71",
        "type": "Patient",
        "display": "Grace Martin"
    },
    "participant": [
        {
            "individual": {
                "reference": "Practitioner/7927e01e-c251-45c5-8d1b-fb135afba689",
                "type": "Practitioner",
                "display": "VICTOR HOBBS"
            }
        }
    ],
    "period": {
        "start": "2023-07-11T01:09:00Z",
        "end": "2023-07-12T04:30:00Z"
    },
    "hospitalization": {
        "admitSource": {
            "text": "Home"
        },
        "dischargeDisposition": {
            "text": "Against Medical Advice"
        }
    },
    "location": [
        {
            "location": {
                "reference": "Location/9433cbaf-4cea-46d0-a45c-afc2c9f9503f",
                "type": "Location",
                "display": "Sample Medical Center"
            }
        }
    ],
    "serviceProvider": {
        "reference": "Organization/87984080-e35f-4a00-8295-bdfacfc368a8",
        "type": "Organization",
        "display": "Sample Medical Center"
    }
}

📘

Zus sends the full FHIR resource as part of the message for FHIR resources smaller than 1 MB.

For resources larger than 1MB, Builders can query the Zus FHIR store with the delivered resourceID.

For basic authentication schemes, Zus will send the FHIR resource ID and associated Universal Patient ID. You will need to query the Zus FHIR store to retrieve the full details of the resource:

{
  "message_id":"456",
  "source":"com.zushealth.zushooks",
  "time":"2023-07-17T13:48:32Z",
  "resourceId":"Encounter/c020d8eb-ea59-492b-862f-c27f9556f628",
  "ownerId":"builder/abc",
  "resourceIncluded":true,
  "resource":{"UPID":"75bf769f-d309-4243-a98d-0d12e339b468"}
}

The message payload also includes:

  • Message ID. There is no guarantee that a message will only be sent once.
  • Source. Supported sources are "com.zushealth.zushooks"
  • Time of message creation.
  • Resource ID.
  • Owner ID of the resource.
  • resourceIncluded. This will be set to false if using basic authentication or the resource size is greater than 1 MB.

Retry Behavior

Presently, if a customer's webserver returns a 500 response, Zushooks will wait 3 seconds and try to fire the webhook one more time. Messages which fail again are put on a dead-letter queue and can be manually redriven by Zus engineers within the 14 day message retention period.

Upcoming enhancements will introduce a more robust automatic redrive, such that failed messages do not require Zus intervention. Specific timing and backoff schedule are still to be determined.

Testing ZusHooks on your local development environment

ZusHooks require a publicly accessible URL. To approach this, you can deploy your application to a development or test server that is reachable from the public internet or use an HTTP tunneling tool like ngrok to set up a public URL for your application that maps to an application server running locally on your computer.

For convenience to quickly demonstrate proof of life, we will test with no authentication using webhook.site, which instantly provides a unique, random URL that allows us to receive webhooks without needing an internet-facing web server.

❗️

This testing should only be conducted on synthetic data.