diff --git a/docs/_snippets/webhook-signature-validation.mdx b/docs/_snippets/webhook-signature-validation.mdx index ff22138093..f2555e0e91 100644 --- a/docs/_snippets/webhook-signature-validation.mdx +++ b/docs/_snippets/webhook-signature-validation.mdx @@ -1,11 +1,12 @@ ```typescript + const webhookKey = "your_secret_key"; // Webhook key from the Settings page const signature = req.headers["x-metriport-signature"]; const signatureAsString = // codeToValidateAndConvertToString(signature); const metriportApi = new MetriportMedicalApi(apiKey, { baseAddress: apiUrl, }); - if (metriportApi.verifyWebhookSignature(whKey, req.body, signatureAsString)) { + if (metriportApi.verifyWebhookSignature(webhookKey, req.body, signatureAsString)) { console.log(`Signature verified`); } else { console.log(`Signature verification failed`); diff --git a/docs/home/api-info/webhooks.mdx b/docs/home/api-info/webhooks.mdx index 8cea505573..50362b97a1 100644 --- a/docs/home/api-info/webhooks.mdx +++ b/docs/home/api-info/webhooks.mdx @@ -20,37 +20,39 @@ To enable this integration approach with Metriport: 1. Set this endpoint URL on the [Developers page](https://dash.metriport.com/developers) in the developer dashboard, or via the [Update Settings endpoint](/home/api-reference/settings/post-settings); 1. This will generate a webhook key that should be used to authenticate requests on - your app's endpoint (webhook). + your app's endpoint (webhook) - see [authentication](#authentication) and + [generating a new webhook key](#generating-a-new-webhook-key) below. General requirements for the endpoint: 1. Public endpoint accessible from the internet; 1. Does not do an HTTP redirect (redirects will not be followed); 1. Accepts a `POST` HTTP request; -1. Verifies requests by comparing the HTTP header `x-webhook-key` with the webhook key; +1. Verifies requests using the HTTP header `x-metriport-signature` - see [authentication](#authentication) below; +1. Responds `200` in under 4 seconds - we recommend processing the webhook request asynchronously; 1. Accepts and responds to a [`ping` message](#the-ping-message); +1. Be [idempotent](https://en.wikipedia.org/wiki/Idempotence) - it should accept being called more + than once with the same payload, with no changes to the end result. -Additionally, depending on what Metriport APIs you're using, your endpoint will need to accept and process -different messages when they become available - specifically: +Additionally, your endpoint will need to accept and process different messages when they become available - specifically: -1. If using the Devices API - accept and process [user data messages](#devices-api-messages). -1. If using the Medical API - accept and process [patient data messages](#medical-api-messages). +1. [Patient data messages](#medical-api-messages). ## Authentication -When Metriport sends a webhook message, it includes an `x-metriport-signature` header. +When Metriport sends a webhook message, it includes an `x-metriport-signature` header - this is an +[HMAC](https://en.wikipedia.org/wiki/HMAC) SHA-256 hash computed using your webhook key and the body of the webhook message. -- `x-metriport-signature`: This is an [HMAC](https://en.wikipedia.org/wiki/HMAC) SHA-256 hash computed using your webhook key and the body of the webhook message. - -At a high level, an HMAC works by taking a secret key and a message, and performing iterative hashes of the two to create -a signature. That signature is compared against the signature in the header for equality. If the signatures are equal, you can trust the webhook -payload is authentic and has not been tampered with. If they aren't equal, you should throw it away. +At a high level, an HMAC works by taking a secret key (webhook key from the Settings page) and a message, +and performing iterative hashes of the two to create a signature. That signature is compared against the +signature in the header for equality. If the signatures are equal, you can trust the webhook +payload is authentic and has not been tampered with. If they aren't equal, you should throw it away. You can use this header to verify that the webhook messages sent to your endpoint are from Metriport. Here's an example of how you can do this in Node.js: -The important thing is to make sure you use a trusted cryptography library in whatever language you choose to validate the webhook message in. +The important thing is to make sure you use a trusted cryptography library in whatever language you choose to validate the webhook message in. You can also compute an HMAC in python: ```python @@ -63,7 +65,7 @@ def compute_hmac(key, message, signature, digestmod=hashlib.sha256): """ Verify the HMAC signature for a given message and key. - :param key: The secret key (string). + :param key: The webhook key from the Settings page (string). :param message: The message to be authenticated (string in JSON format). :param signature: The provided HMAC signature to verify against (string). :param digestmod: The hash function to use (defaults to hashlib.sha256). @@ -77,9 +79,9 @@ def compute_hmac(key, message, signature, digestmod=hashlib.sha256): return signature == computed_signature # Example usage -key = 'your_secret_key' # Your key +key = 'your_secret_key' # The webhook key from the Settings page message = '{"webhookUrl": "https://api.app.com/webhook"}' # The message from the request in JSON format -signature = 'the-request-signature' # The signature from the header +signature = 'the-request-signature' # The signature from the header is_signature_valid = compute_hmac(key, message, signature) @@ -87,21 +89,15 @@ if is_signature_valid: print("Signature verified") else: print("Signature verification failed") - - ``` - -The previous method of authenticating webhooks, comparing your webhook key with the `x-webhook-key` in each request's HTTP header, is being deprecated on **December 9th, 2023**. -Please update your implementation to use the `x-metriport-signature` header for authentication. - - ### Generating a new webhook key -If using the dashboard: simply delete your webhook URL on the [Developers page](https://dash.metriport.com/developers), save, and enter it again. +If using the dashboard: simply delete your webhook URL on the [Developers page](https://dash.metriport.com/developers), +save, and enter it again. -If using the API: set the webhook URL to an empty string via the [Update Settings endpoint](/home/api-reference/settings/post-settings), and then set it -to your desired URL making another request to the same endpoint. +If using the API: set the webhook URL to an empty string via the [Update Settings endpoint](/home/api-reference/settings/post-settings), +and then set it to your desired URL making another request to the same endpoint. ## Format @@ -110,7 +106,6 @@ Webhook requests contain the relevant information on the body of the HTTP reques There are several types of messages you can expect to receive: - [`ping`](#the-ping-message): validation of the webhook connection between Metriport and your app; -- [Devices API messages](#devices-api-messages); - [Medical API messages](#medical-api-messages). In general, upon successful receiving of these messages, it's expected that your app responds with a `200` HTTP @@ -145,12 +140,6 @@ accept a `POST` request with this body... You can check the [webhook mock server available on our repository](https://github.com/metriport/metriport/blob/master/utils/src/mock-webhook.ts) for a simple implementation of this message. -### Devices API messages - -When using the Devices API, Metriport will send Webhook messages containing [new provider connections](/devices-api/more-info/webhooks#provider-connected-message) for each user, as well as [user data](/devices-api/more-info/webhooks#user-health-data-message) to your app from [our supported Providers](/devices-api/more-info/our-integrations), as soon as the data becomes available. - -You can see Webhook details specific to the Devices API on [this page](/devices-api/more-info/webhooks). - ### Medical API messages When using the Medical API, Metriport will send Webhook messages containing status updates to your app, as soon @@ -170,8 +159,9 @@ Example payload: "meta": { "messageId": "", "when": "", - "type": "devices.health-data" - } + "type": "medical.medical.consolidated-data" + }, + ... } ``` @@ -191,7 +181,8 @@ The format follows: - The type of the webhook message. If coming from the Devices API, this will be formatted `devices.`, and if coming from the Medical API it will be formatted `medical.`. + The type of the webhook message. This can either be `ping` or one of the + [Medical API types](/medical-api/more-info/webhooks#types-of-messages). diff --git a/docs/medical-api/api-reference/document/download-url-bulk.mdx b/docs/medical-api/api-reference/document/download-url-bulk.mdx index 0b2965fc83..782ec3c6eb 100644 --- a/docs/medical-api/api-reference/document/download-url-bulk.mdx +++ b/docs/medical-api/api-reference/document/download-url-bulk.mdx @@ -3,13 +3,19 @@ title: "Start Bulk Get Document URL" description: "Triggers a process to generate a list of download URLs for all of the patient's documents." api: "POST /medical/v1/document/download-url/bulk" --- -When executed, this endpoint triggers a process to generate all download URLs for a patient's documents, which will then be delivered via webhook message. +When executed, this endpoint triggers a process to generate all download URLs for a patient's documents. +This is an asynchronous process, and the status is returned in the response to the original request. -The status of the process is returned in the response. Initially, it will be `processing`, and when the process is finished, the status will be updated to `completed` or `failed`. +Initially, the status will be `processing`, and when the process is finished, the status will be updated to +`completed` or `failed`. - - The result of the process will be delivered via a webhook message - to set this up, and see the message format, check out our [webhooks guide](/medical-api/more-info/webhooks#bulk-downloadable-url-generation). - +Once completed, a webhook request will be sent [your configured URL](/home/api-reference/settings/post-settings) +containing the document download URLs. + +Webhook message type - see [the respective section on the webhooks page](/medical-api/more-info/webhooks#bulk-downloadable-url-generation) +for more details: + +- `medical.document-bulk-download`: list of download urls for a patient's documents. If you trigger this endpoint again while the process is still running, you will get a response that reflects the current progress. Essentially, only a single bulk URL generation process will be running for a patient at any given time. diff --git a/docs/medical-api/api-reference/document/start-document-query.mdx b/docs/medical-api/api-reference/document/start-document-query.mdx index a02377befd..535253b2c3 100644 --- a/docs/medical-api/api-reference/document/start-document-query.mdx +++ b/docs/medical-api/api-reference/document/start-document-query.mdx @@ -15,11 +15,14 @@ incremented. Once all documents have been converted it too will be marked as `co If there's no document to be converted, the total will be set to zero and the status to `completed`. - - To get updates about the document query progress, including download and conversion status, check - out our [webhooks guide](/medical-api/more-info/webhooks). Note that the webhooks will only - contain updates for new data fetched in the current document query. - +Once each process completes, a webhook request will be sent to [your configured URL](/home/api-reference/settings/post-settings) +containing the available data. **Note:** the webhooks will only contain updates for new data fetched in the current document query. + +Webhook message types - see [the respective section on the webhooks page](/medical-api/more-info/webhooks#patient-document-data) +for more details: + +- `medical.document-download`: contains the newly downloaded documents for the patient; +- `medical.document-conversion`: result of converting the newly downloaded C-CDA documents into FHIR. If you were to trigger this endpoint again while the query is still processing, you will get a diff --git a/docs/medical-api/api-reference/fhir/consolidated-data-query-post.mdx b/docs/medical-api/api-reference/fhir/consolidated-data-query-post.mdx index bb0e067113..060c31c4b5 100644 --- a/docs/medical-api/api-reference/fhir/consolidated-data-query-post.mdx +++ b/docs/medical-api/api-reference/fhir/consolidated-data-query-post.mdx @@ -7,10 +7,15 @@ api: "POST /medical/v1/patient/{id}/consolidated/query" When executed, this endpoint triggers an asynchronous query to retrieve a Patient's consolidated data from the FHIR repository. -Once the data is consolidated and ready for consumption, a [Webhook request](/medical-api/more-info/webhooks#patient-consolidated-data) -is sent to [your configured URL](/home/api-reference/settings/post-settings) containing the Patient's +Once the data is consolidated and ready for consumption, webhook requests will be sent to +[your configured URL](/home/api-reference/settings/post-settings) containing the Patient's data in FHIR-compliant format, based on the [parameters](#query-params) used to trigger the query. +Webhook message type - see [the respective section on the webhooks page](/medical-api/more-info/webhooks#patient-consolidated-data) +for more details: + +- `medical.consolidated-data`: contains the patient's data in FHIR format. + You'll be able to query multiple times for the same Patient which will be added to the queue and processed in order. If the parameters are the same as a previous query that is still processing, the new query will be ignored and you'll get the status and request ID of the previous one. diff --git a/docs/medical-api/more-info/webhooks.mdx b/docs/medical-api/more-info/webhooks.mdx index 2fdd390e4a..9ec0d690ec 100644 --- a/docs/medical-api/more-info/webhooks.mdx +++ b/docs/medical-api/more-info/webhooks.mdx @@ -21,6 +21,17 @@ You should expect to get more than one Webhook message per patient per request ( To enable this integration approach with Metriport, and for some prerequesite reading to understand how the Webhook flow works, see [our Webhooks guide](/home/api-info/webhooks). +### Types of Messages + +- `medical.document-download`: result of Document Query, containing the newly downloaded documents + for the patient - see [details](#patient-document-data) below; +- `medical.document-conversion`: result of converting the newly downloaded C-CDA documents into FHIR - + see [details](#patient-document-data) below; +- `medical.document-bulk-download-urls`: list of download urls for a patient's documents, see + [details](#bulk-document-download-urls) below; +- `medical.consolidated-data`: result of a Consolidated Data Query, containing the patient's data in FHIR + format - see [details](#patient-consolidated-data) below. + ### Passing Metadata You can pass metadata to endpoints that support webhooks, and you will receive the `meta.data` field of the webhook request. @@ -36,23 +47,25 @@ Below is an example payload you could send in the request body of one of those e These are messages you can expect to receive in the following scenarios: -1. When [queried documents](/medical-api/api-reference/document/start-document-query) have completed downloading (`type` for a patient in - the message will be `document-download`, and at this point you'll be able to [download the raw files](/medical-api/api-reference/document/get-document)); +1. When [queried documents](/medical-api/api-reference/document/start-document-query) have completed + downloading, the message `type` will be `medical.document-download`, and at this point + you'll be able to [download the raw files](/medical-api/api-reference/document/get-document); +2. Then, if the downloaded documents contained C-CDA/XML files, when the conversion to FHIR has + completed, the message `type` will be `medical.document-conversion`, and at this point + you'll be able to query for [patient consolidated data](/medical-api/api-reference/fhir/consolidated-data-query-post) + in FHIR-compliant format. Note that the webhooks will only contain updates for new data fetched in the current document query. -2. Then, if the downloaded documents contained C-CDA/XML files, when the conversion to FHIR has completed (`type` for a patient in the message - will be `document-conversion`, and at this point you'll be able to query for [patient consolidated data](#patient-consolidated-data) in FHIR-compliant format). - ```json { "meta": { "messageId": "", "when": "", - "type": "medical.document-bulk-download-urls" + "type": "medical.document-download" "data": { youCan: "putAny", stringKeyValue: "pairsHere",