Webhooks

How do I use Webhooks?

Why use Webhooks?

When building Cybrid integrations, you might want your applications to receive events as they occur in your Cybrid organization, so that your back-end systems can execute actions accordingly.

To enable Webhook events, you need to register a Webhook endpoint(s). After you register, Cybrid can push real-time event data to your application’s Webhook endpoint when events happen in your Cybrid organization. Cybrid uses HTTPS to send Webhook events to your app as a JSON payload that includes a Subscription event object.

Receiving Webhook events is particularly useful for listening to asynchronous events such as when a customer’s trade is completed, a transfer is settled, or when an identity verification completes.

Event Overview

Cybrid generates event data that we can send you to inform you of activity in your account.

When an event occurs, Cybrid generates a new Subscription event object. A single API request might result in the creation of multiple events. For example, if you create a new transfer for a customer, you receive transfer.storing, transfer.reviewing and transfer.completed events.

By registering Webhook endpoints in your Cybrid organization, you enable Cybrid to automatically send Subscription event`` objects as part of POST requests to the registered Webhook endpoint hosted by your organization. After your Webhook endpoint receives the Subscription event, your app can run back-end actions (for example, informing the customer a trade has been settled).

SubscriptionEvent Object

The following is an example of a SubscriptionEvent:

 {  
    "guid": "cf16b78e233464229c7eda5e979b25a8",  
    "organization_guid": "ad9007e80f35ac6d343d43496cad2744",  
    "event_type": "transfer.storing",  
    "object_guid": "8f5ee194e5aa254feef3054bd9543939",  
    "environment": "sandbox"  
}
  • guid - Identifier for the event. It can also be used as an idempotency key
  • organization_guid - Identifier for the organization owning the object (allows the same Webhook endpoint to be registered with multiple organizations)
  • event_type - A tuple separated by '.' containing the type of the object (ie: trade, transfer or identity_verification) and the type of event generated by the Cybrid platform
  • object_guid - Identifier for the object generating the event
  • sandbox - Flag to indicate if the event is a sandbox or production event. You might receive both sandbox and production mode event delivery requests to your endpoints

Event List

A full list of event types that we send to your Webhook endpoint(s):

trade.storing
trade.pending
trade.cancelled
trade.completed
trade.settling
trade.failed
transfer.storing
transfer.pending
transfer.reviewing
transfer.completed
transfer.failed
identity_verification.storing
identity_verification.pending
identity_verification.reviewing
identity_verification.waiting
identity_verification.expired
identity_verification.completed

For example, if your goal is to capture the potential error events, you can listen for trade.failed, transfer.failedand/or identity_verification.expired.

Get Started

Setup the Webhook Endpoint

To start receiving Webhook events in your app, create a Webhook endpoint handler to receive event data POST requests.

Set up an HTTPS endpoint function that can accept Webhook requests with a POST method. For a sandbox setup you can use an HTTP endpoint.

🚧

Production Webhook endpoints must use HTTPS

Set up your endpoint function so that it handles POST requests with a JSON payload consisting of a SubscriptionEvent object.

Make sure your endpoint quickly returns a successful status code (2xx) prior to any complex logic that could cause a timeout. For example, you must return a 200 response before updating a transfer in your system.

🚧

Endpoints must return a (2xx) prior to any complex logic

📘

Registered Webhook endpoints must be publicly accessible URLs

📘

You can register up to 5 Webhook endpoints per organization

Register the Webhook Endpoint

After testing your Webhook endpoint function, register the Webhook endpoint’s accessible URL using the Subscription API so Cybrid knows where to deliver events. See the POST call and response below:

curl --location --globoff '<https://cybrid.app/api/subscriptions/'>  
--header 'Content-Type: application/json'  
--header 'Accept: application/json'  
--header 'Authorization: ••••••'  
--data '{  
  "name": “My first webhook”,  
  "type": "webhook",  
  "url": "<https://example.com/cybrid_webhook">,  
  "environment": "sandbox"  
}'
{  
    "created_at": "2024-08-06T20:11:35.191626Z",  
    "updated_at": "2024-08-06T20:11:35.191626Z",  
    "guid": "129c6afa730ea41af79d14605edd6691",  
    "organization_guid": "eb882e9420de9e2f73b5fc9b6ea2b085",  
    "type": "webhook",  
    "name": "My first webhook",  
    "url": "<https://example.com/cybrid_webhook">,  
    "state": "storing",  
    "failure_code": null,  
    "environment": "sandbox",  
    "deliveries_failing_since": null,  
    "signing_key": "c3ac436b171923eb688a6bf364f89effd90427f4d58018e25558af3ecd506bc5"  
}

🚧

Make a note of the signing_key as it is only returned once and it is needed in securing your Webhook endpoint

📘

A subscription will become active only after the endpoint is available and responds to requests

Secure the Webhook Endpoint

When Cybrid sends data to registered Webhook endpoints, the payload will be authenticated with a hash-based message authentication code (HMAC). The key used to create the HMAC is the signing_key provided on subscription registration (see section above), and you verify it by running the algorithm yourself with the payload and the key to re-create the HMAC. The HMAC is created with the HMAC_SHA256 algorithm, then encoded in base 64. The HMAC is attached to the request in the X-Cybrid-Signature header. You can find an example on how to secure your endpoint below:

const express = require('express');  
const crypto = require('crypto');  
const bodyParser = require('body-parser');  
const PORT = 3333;  
const SIGNING_KEY = "c3ac436b171923eb688a6bf364f89effd90427f4d58018e25558af3ecd506bc5"  
const ALGORITHM = 'sha256'  
const SIGNATURE_HEADER = 'X-Cybrid-Signature'  
const app = express();  
app.use(bodyParser.json({  
    verify: (req, res, buf) => {  
      req.rawBody = buf;  
    }  
  }));  
app.use(express.json());  
app.post('/webhook', async (req, res) => {  
    try {  
        const requestSignature = req.get(SIGNATURE_HEADER);  
        const expectedSignature = crypto.createHmac(ALGORITHM, SIGNING_KEY)  
          .update(req.rawBody)  
          .digest('hex');  
        let valid_request = requestSignature === expectedSignature  
        // respond with 200  
        if (valid_request) {  
            res.status(200).send("OK"); 
            console.log(`received payload ${req.body}`)  
            // perform actions related to the event  
        } else {  
            res.status(403).send("INVALID SIGNATURE");  
        }  
    } catch (err) {  
        res.status(500).send(err.toString());  
    }  
})  
app.listen(PORT, () => {  
    console.log(`Server running on ${PORT}`);  
});

Event Delivery Behaviour and Best Practices

Retry behaviour

Cybrid attempts to deliver a given event to your Webhook endpoint for up to 3 days with an exponential back off and a maximum wait of 1 hour. Using the SubscriptionDelivery API you can view failing deliveries and when the next attempt will occur. If your endpoint subscription has been disabled or deleted when Cybrid attempts a retry, future retries of that event are prevented. If a delivery has failed, you can trigger a new retry cycle by creating a new delivery using SubscriptionDelivery API.

Disable behaviour

If your endpoint has not returned a successful response for multiple days Cybrid will automatically mark the endpoint as failed and it will skip future deliveries. To re-enable the endpoint, a new registration will need to be created using the Subscription API

Event ordering

Cybrid doesn’t guarantee delivery of events in the order in which they’re generated. For example, creating a transfer might generate the following events:

transfer.storing
transfer.reviewing
transfer.completed

Your endpoint shouldn’t expect delivery of these events in this order, and needs to handle delivery accordingly. You can also use the API to fetch the updated object and react according to the latest state of the object.

Handle duplicate events

Webhook endpoints might occasionally receive the same event more than once. You can guard against duplicated event receipts by logging the event GUID you’ve processed, and then not processing already-logged events.

Handle events asynchronously

Configure your handler to process incoming events with an asynchronous queue. You might encounter scalability issues if you choose to process events synchronously. Any large spike in Webhook deliveries might overwhelm your endpoint hosts. Asynchronous queues allow you to process the concurrent events at a rate your system can support.

Quickly return a 2xx response

Your endpoint must quickly return a successful status code (2xx) prior to any complex logic that could cause a timeout. For example, you must return a 200 response before updating information in your system.

Roll endpoint signing secrets periodically

To keep your Webhook handler safe, we recommend that you roll secrets periodically, or when you suspect a compromised secret. The process of rolling a Webhook signing secret consists of creating a new registration (with a new signing key), updating your Webhook handler and deleting the previous registration. This process may lead to the same event being delivered multiple times but your Webhook handler should handle duplicate events.