Request

What does the webhook send me?

The webhook sends an event via HTTP POST request with Content-Type: application/json with the following parameters:

  • An X-Caf-Signature header used to verify that the request came from Caf

Signature
  • The request body is a JSON that follows the CloudEvents standard

Events

Request structure

Each webhook request includes:

Headers

Header
Description

Content-Type

Always application/json

User-Agent

Identifies as Caf-Webhook/Connect

X-Caf-Signature

Contains the HMAC SHA-256 signature of the request body

Request body

The request body follows the CloudEvents format, although the specific CloudEvents HTTP headers are not included:

{
  "specversion": "1.0",
  "type": "COMMUNICATIONCREATEDEVENT",
  "source": "COMMUNICATION",
  "id": "01JZNK5ZQBNF623MB5KE64GNQB",
  "time": "2025-07-08T18:01:19.622Z",
  "datacontenttype": "application/json",
  "data": {
    "tenantId": "016e8f79-2399-4d35-90f9-c6f91b73189d",
    "channel": "sms",
    "externalId": "external-id",
    "notificationId": "01JZNK51YCZXT55TKF8M366QHJ",
    "system": "onboarding",
    "occurredOn": "2025-07-08T18:00:46.797Z"
  }
}

Examples

Curl

Example curl command assuming SECRET: "dummysecret":

curl --location 'http://localhost:8080/webhook' \
--header 'X-Caf-Signature: 6f9ed23a7b505a3b6907c5f6eb2ad1b056fbf35a643d365a9a072ed7aabca153' \
--header 'Content-Type: application/json' \
--data '{
  "specversion": "1.0",
  "type": "COMMUNICATIONCREATEDEVENT",
  "source": "COMMUNICATION",
  "id": "01JZNK5ZQBNF623MB5KE64GNQB",
  "time": "2025-07-08T18:01:19.622Z",
  "datacontenttype": "application/json",
  "data": {
    "tenantId": "016e8f79-2399-4d35-90f9-c6f91b73189d",
    "channel": "sms",
    "externalId": "external-id",
    "notificationId": "01JZNK51YCZXT55TKF8M366QHJ",
    "system": "onboarding",
    "occurredOn": "2025-07-08T18:00:46.797Z"
  }
}'

Example of a request with an equivalent payload, just with some extra spaces that affect the signature, but equally valid:

curl --location 'http://localhost:8080/webhook' \
--header 'X-Caf-Signature: cf7e092c9148a48f5ee5f12b947f46b331eac6bf0745e1e1d0f3df722e219df3' \
--header 'Content-Type: application/json' \
--data '{ "specversion": "1.0", "type": "COMMUNICATIONCREATEDEVENT", "source": "COMMUNICATION", "id": "01JZNK5ZQBNF623MB5KE64GNQB", "time": "2025-07-08T18:01:19.622Z", "datacontenttype": "application/json", "data": { "tenantId": "016e8f79-2399-4d35-90f9-c6f91b73189d", "channel": "sms", "externalId": "external-id", "notificationId": "01JZNK51YCZXT55TKF8M366QHJ", "system": "onboarding", "occurredOn": "2025-07-08T18:00:46.797Z" } }'

What should I respond to the webhook?

Our webhook considers responses with a 2xx code (preferably 202 ACCEPTED) within 2 seconds to mean that the integration has successfully received the event, and therefore no more calls will be made for that event. The response body is ignored by the system, except for internal audit purposes in case of delivery failures.

Error cases

The webhook request has the purpose of successfully integrating the event and nothing more than that. With this purpose in mind, error responses should only be used to indicate failure in the event integration (by integrated event, it means the event was successfully received by the webhook server).

The webhook delivery mechanism accepts and recognizes errors within the HTTP 5xx error series, which can indicate errors in receiving or processing the request by the server. Delivery retries will happen only for this class of errors.

Error responses can follow the payload specified below to detail and make clear the reason for the error in our internal audit. Any other fields and/or formats will be ignored.

{
  "error": "error message"
}

Handling webhook requests

Idempotency

Webhook requests may be delivered more than once in rare cases. To handle this, implement idempotency by:

  1. Using the id field in the event payload to detect duplicates

  2. Storing processed event IDs to avoid processing the same event twice

  3. Making your event handling logic idempotent (safe to run multiple times)

Example webhook handler

Here's a simple example of a webhook handler in Node.js Express:

const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');

const app = express();
app.use(bodyParser.json());

app.post('/webhook', (req, res) => {
  const sigHeader = req.headers['x-caf-signature'];
  const payload = req.body;
  
  // Verify the signature
  if (!verifySignature(payload, sigHeader, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process the CloudEvent based on its type
  const eventType = payload.type;
  const eventSource = payload.source;
  const eventId = payload.id;
  
  console.log(`Processing CloudEvent: ${eventId} from ${eventSource} of type ${eventType}`);
  
  switch (eventType) {
    case 'COMMUNICATIONCREATEDEVENT':
      handleCommunicationCreated(payload.data);
      break;
    case 'TRANSACTIONUPDATEDEVENT':
      handleTransactionUpdated(payload.data);
      break;
    case 'PROFILECREATEDEVENT':
      handleProfileCreated(payload.data);
      break;
    // Handle other event types...
    default:
      console.log(`Unhandled event type: ${eventType}`);
  }
  
  // Respond with success
  res.status(200).send('Event received');
});

// Start the server
app.listen(3000, () => {
  console.log('Webhook server listening on port 3000');
});

Troubleshooting

Common issues

Logs and debugging

You can use webhook logs in Trust, the platform that manages configurations, to view the delivery status of recent events and any error messages. The logs maintain a history of:

  • Successful and failed delivery attempts

  • HTTP response codes received

  • Delivery timestamps

  • Specific errors encountered during deliveries

Last updated