Subscription Extensions | Medplum

On this page

Use the following FHIR extensions to customize the Subscription behavior. The behavior is non-standard, and will not necessarily work in other FHIR systems.

Adding Extensions

Here is an example FHIR Subscription Object:

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "Patient",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  }
}

An subscription extension contains an array of objects that have url and value* in them. To add an extension, use one of medplum's url below that contains the value to be passed.

The extension will look like this:

{
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
      "valueInteger": 3
    }
  ]
}

And your final Subscription object will be:

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "Patient",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
      "valueInteger": 3
    }
  ]
}

Below are explanations of the different extensions Medplum Provides

Interactions

Note

By default, FHIR Subscriptions will execute on all "create", "update", and "delete" operations. To restrict a Subscription to a subset of these interactions, use one or more subscription-supported-interaction extensions as described below.

You can use extensions as follows for more fine-grained control over when Subscriptions execute. To confirm if your Subscriptions are executing, navigate to https://app.medplum.com/Subscription/<id>/event to view related AuditEvents. Note that if you configure the subscription to use log-only destination for AuditEvents (see AuditEvent Destination), these events will not appear in the UI.

A Subscription may declare multiple subscription-supported-interaction extensions. When one or more are present, the Subscription will only execute for the listed interactions. For example, adding one extension with valueCode of create and another with valueCode of update will fire on "create" and "update" but not "delete". When no subscription-supported-interaction extension is present, the Subscription fires on all interactions ("create", "update", and "delete").

Subscriptions for "create"-only or "update"-only events

To restrict the FHIR Subscription to only execute on "create", use the https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction extension with valueCode of create:

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "Patient",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction",
      "valueCode": "create"
    }
  ]
}

You can also restrict the FHIR Subscription to only execute on "update", using the https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction extension with valueCode of update:

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "Patient",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction",
      "valueCode": "update"
    }
  ]
}

To listen for more than one interaction while excluding the others (for example, "create" and "update" but not "delete"), include a separate subscription-supported-interaction extension for each interaction you want:

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "Patient",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction",
      "valueCode": "create"
    },
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction",
      "valueCode": "update"
    }
  ]
}

Subscriptions for "delete" events

Use the https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction extension with valueCode of delete. For example:

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "Patient",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction",
      "valueCode": "delete"
    }
  ]
}

The response for a deleted resource will contain:

{
  "method": "POST",
  "body": "{}",
  "headers": {
    "Content-Type": "application/fhir+json",
    "X-Medplum-Deleted-Resource": "${resource.resourceType}/${resource.id}"
  }
}

Few things to note:

X-Medplum-Deleted-Resource: Will contain the resource type and resource id that was deleted.

body: Will be an empty object in the response {}

Signatures

When a consumer receives a webhook request, you may want to verify that the request came from the expected sender.

Webhooks can optionally use a FHIR extension to enable an HMAC signature. To enable HMAC signatures, use the extension https://www.medplum.com/fhir/StructureDefinition/subscription-secret and valueString of a cryptographically secure secret.

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "DiagnosticReport?status=completed",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "extension": [
    {
      "url": "https://www.medplum.com/fhir/StructureDefinition/subscription-secret",
      "valueString": "abc"
    }
  ]
}

The valueString will be used to generate a signature. The signature is the payload encoded using SHA-256 (otherwise known as an HMAC).

Retry Policy

If your subscription failed or threw an error, you can configure it to attempt to execute the operation multiple times.

To add an attempt number, use the https://medplum.com/fhir/StructureDefinition/subscription-max-attempts extension with the valueInteger set to a number between 1-18.

The default number of attempts is 4.

Note

Subscriptions with Bot endpoints will only execute once and will not retry on failure. The subscription-max-attempts extension only applies to rest-hook subscriptions with external HTTP endpoints.

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "DiagnosticReport?status=completed",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
      "valueInteger": 3
    }
  ]
}

Retry timing and backoff

Retries are not immediate. Medplum spaces them out using exponential backoff with jitter, which is important to understand when planning for downtime in the destination service that receives the webhook.

Custom Status Codes

HTTP status codes can be customized to determine the success of the subscription operation.

To add custom codes, use the https://medplum.com/fhir/StructureDefinition/subscription-success-codes extension with the valueString having a comma separated list of HTTP status codes for success (i.e., "200,201"). We also allow ranges (i.e., "200-399,404")

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "DiagnosticReport?status=completed",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-success-codes",
      "valueString": "200-399,404"
    }
  ]
}

AuditEvent Destination

Rest-hook subscriptions only

The subscription-audit-event-destination extension applies to rest-hook (channel.type = "rest-hook") subscriptions. For bot-channel subscriptions, audit event behavior is controlled by Bot.auditEventDestination on the Bot resource.

Log-only destination

To send AuditEvent resources only to logs (not the database):

{
  "resourceType": "Subscription",
  "reason": "test",
  "status": "active",
  "criteria": "Patient",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-audit-event-destination",
      "valueCode": "log"
    }
  ]
}

Expression based criteria

Medplum offers an extension (fhir-path-criteria-expression) for triggering subscriptions based on more complex conditional logic using a FHIRPath expression. This expression takes in two variables:

Here is an example Subscription resource with a fhir-path-criteria-expression expression that fires when a Task changes its status:

{
  "resourceType": "Subscription",
  "reason": "Task Status Change",
  "status": "active",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.com/webhook"
  },
  "criteria": "Task",
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/fhir-path-criteria-expression",
      "valueString": "%previous.status != %current.status"
    }
  ]
}