Webhooks

Webhooks is available from version 2.27.


A client can subscribe to webhooks in order for the client to be notified when different events occur inside BFS. An example of an event in BFS could be that a transaction is created or an account is updated. A webhook is sent over HTTP making it possible for every client that can receive an HTTP request to get notified when an event occurs. The client can for example use webhooks to synchronize data and update a cache on their side or maybe use it to build a living user interface for their end customers where events are pushed to the user interface.

Getting started

The first step for setting up webhooks is to create a webhook subscription through the BFS API and endpoint https://bricknode.atlassian.net/wiki/spaces/API/pages/1711472815/CreateWebhookSubscriptions. When creating webhook subscriptions the client needs to provide the name of the event and the destination address where the client wants to be notified when the event occurs. Available events with their respective payload and structure can be found here https://bricknode.atlassian.net/wiki/spaces/API/pages/1721106535/Events and the client can also fetch available events to subscribe on by calling the endpoint https://bricknode.atlassian.net/wiki/spaces/API/pages/1711472878/GetAvailableWebhookEvents. BFS will now notify the provided destination address when the event occurs.

Note: Webhook subscriptions can be cached for up to ten minutes. When making changes to the webhook subscription, it may take up to ten minutes to see your changes go into effect.

Note: A client can add up to five webhook subscriptions for each event. When this quota is reached the CreateWebhookSubscriptions endpoint will return an error message telling that the quota has been exceeded.

Receive webhooks

To receive a webhook request the destination address must be able to process HTTP POST requests. The body in the HTTP request is formatted as JSON. Below is an example of an HTTP webhook request:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST /webhooksreceiver HTTP/1.1 Host: localhost content-type: application/json; charset=utf-8 x-bricknode-key : 6a05058546fe40c84f02fb51b4609fe34263639d09ddec271702592551e58061 { "Id": "b2ffad4a-c6ba-4a4b-bc8e-c44cf566c8a1", "EventName": "AccountCreated", "Data": [ { "AccountId": "2e13efb7-cef2-4722-9bbc-21a1e45f93ee", "CreatedAtDateTime": "2021-02-23T12:38:34.4939141Z" } ] }

The Data field in the JSON payload can contain multiple events if the event is part of a batch. For simplicity, the Data field will always be an array, even if the webhook only contains a single event. A batched webhook can contain a maximum of 100 items in the Data field. For example, if 1 000 AccountCreated events occur in the same batch the destination will receive 10 webhooks where each webhook request contains 100 items. Each webhook also contains a BatchId, making it possible for the receiver to see if the webhook is a part of a batch. Below is an example of a batched webhook request:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 POST /webhooksreceiver HTTP/1.1 Host: localhost content-type: application/json; charset=utf-8 x-bricknode-key : 6a05058546fe40c84f02fb51b4609fe34263639d09ddec271702592551e58061 { "Id": "b2ffad4a-c6ba-4a4b-bc8e-c44cf566c8a1", "EventName": "AccountCreated", "BatchId": "14ec77ef-f23d-4acf-8512-fd8454bbba99", "Data": [ { "AccountId": "46c2f193-d5d9-49a5-9974-32788ffae9eb", "CreatedAtDateTime": "2021-02-23T12:38:34.4939141Z" }, { "AccountId": "d3575f56-4c76-4a90-a1f9-28868459c7e2", "CreatedAtDateTime": "2021-02-23T12:38:34.4939141Z" }, { "AccountId": "22066fad-958e-4e8b-9d4c-446853ca8f2d", "CreatedAtDateTime": "2021-02-23T12:38:34.4939141Z" } ] }

The request timeouts after 5 seconds so the client should send a response directly and process the request asynchronously at their side. The client should send HTTP-status code 200 (OK) in the response if the webhook was processed successfully. If Bricknode receives an error in the response Bricknode will try to recover and send the same webhook request again. Bricknode will only retry the request if the error is considered a transient error that could be recovered by a retry. For example, if Bricknode receives HTTP-status code 404 (Not found) the destination address is not found and the Webhook would not be delivered if we retry. A retry will be made for the following errors:

  • HTTPS-status code 500 (Internal server error).

  • HTTPS-status code 408 (Request timeout).

  • Network errors, for example, if a webhook request failed due to an external reason that cannot be specifically determined.

The retry logic uses an exponential backoff which will retry the request a maximum of five times. The first retry will be made after two seconds, the next after four seconds and the next one after eight seconds, and so on until the backoff is reached or the webhook request succeeds. If the webhook request fails it will be set in state Failed and the client will be able to fetch all failed events by calling the https://bricknode.atlassian.net/wiki/spaces/API/pages/1711833274/GetFailedWebhooks endpoint in the BFS API. Failed webhooks are purged after seven days.

Bricknode does not guarantee that a webhook is only sent once, meaning that the client must be able to handle duplicates. Every webhook request contains a unique Id (GUID) which the client can use to detect duplicates and make their receiving endpoints idempotent.

It can take up to two minutes for the webhook request to be sent to the client's destination address after the event occurs in BFS. In most cases, the webhook is delivered within 1-4 seconds to the destination.

Security

In order for the client to be able to verify that the requests come from Bricknode and the data in the request has not tampered with a hash is sent as an HTTP-header in the webhook request that can be used to verify this. The name of the header is “x-bricknode-key” and the value is an HMAC SHA-256 hash and is encoded as a hexadecimal string. The client should calculate the HMAC SHA-256 hash by using a secret key and the JSON-body that is sent in the webhook request and then compare the calculated hash with the value in “x-bricknode-key“. If the client's calculated string equals the value in “x-bricknode-key” the webhook request is from Bricknode and the data sent in the body has not been tampered with. The secret key must only be known by Bricknode and the client, so the client should handle this key as a secret.

The secret key is provided by Bricknode at the moment but in the future, the client will be able to generate/update their secret in BFS Admin.