Webhooks
How to add a Webhook
Your system can register to events on Corsa platform you want to be notified and/or act uppon.
-
From the Settings -> Developers Menu you can choose the Webhooks tab and press + Add webhook.
-
You are required to specify of your server URL and a secret for validation on your server.
-
Choose the events you want to get webhook for (choose at least one):
Webhook Handling
Headers
When receiving webhooks, inspect the following HTTP headers:
x-hub-signature-256
: The HMAC SHA256 signature of the request payload. Used for verifying the webhook's authenticity. (See Verifying Signatures below).x-tweed-event
: The type of event that triggered the webhook (e.g., individual_client.created).x-tweed-hook-id
: The unique identifier of the webhook configuration that sent this request.x-tweed-delivery
: A unique identifier for this specific delivery attempt.
Verifying Signatures
Verifying Signatures
It's crucial to verify the signature of incoming webhooks to ensure they originated from the Compliance API and were not tampered with. Use the verifyWebhookSignature function exported from the SDK.
import { verifyWebhookSignature } from '@paytweed/compliance-sdk';
async function verifyWebhookRequest(request: Request) { // Assuming a standard Request object
const signature = request.headers.get('x-hub-signature-256');
const payload = await request.text(); // Raw request body
const secret = process.env.WEBHOOK_SECRET; // Your webhook secret
if (!signature || !secret) {
console.error("Missing signature or secret");
// Return an error response (e.g., HTTP 400 Bad Request)
return false;
}
const isValid = await verifyWebhookSignature(secret, payload, signature);
if (!isValid) {
console.error('Invalid webhook signature');
// Return an error response (e.g., HTTP 401 Unauthorized)
return false;
}
console.log("Webhook signature verified successfully!");
// Signature is valid, proceed with processing the webhook payload
// const webhookEvent = JSON.parse(payload);
// console.log('Received valid webhook:', webhookEvent.type);
// ... process event ...
return true;
}
Event Types
The following webhook event types are available (defined in WebhookEventType):
individual_client.created
: Triggered when an individual client is created.individual_client.updated
: Triggered when an individual client is updated.corporate_client.created
: Triggered when a corporate client is created.corporate_client.updated
: Triggered when a corporate client is updated.alert.created
: Triggered when an alert is created.alert.updated
: Triggered when an alert is updated.case.created
: Triggered when a case is created.case.updated
: Triggered when a case is updated.
The payload structure for each event type (WebhookEvent, EntityCreatedPayload, EntityUpdatedPayload) and the WebhookEventType enum can be imported from @corsa-labs/sdk
.
For a practical example of how to set up a webhook handler, see the Webhook Example.
Signing Secret
The signing secret is a shared string used to verify that incoming webhook requests are authentic and have not been tampered with or spoofed. This ensures that the request is genuinely coming from our server. Make sure the signing secret you provide is stored securely and encrypted in your platform (for example, using AWS secret manager).
We use HMAC-based shared-key authentication for this purpose. The signing process involves generating a signature using the shared key and comparing it with the one included in the webhook request.
// TypeScript
const signingSecret: string = '<the secret>';
const algorithm = 'sha256';
const result = `${algorithm}=${createHmac(algorithm, signingSecret)
.update(payload)
.digest('hex')}`
// >>> console.log(result)
// sha256=4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865
We then attach the result in the request headers under the X-Hub-Signature-256 header:
Example header:
X-Hub-Signature-256: sha256=4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865
Later on your end, you may validate by using the same implementation (hashing the HTTP request body) and compare the result with the header.
For increased security use a cryptographically-secure string comparison function like: crypto.timingSafeEqual
Updated 13 days ago