Environment:
Skip to main content
This documentation is in BETA version, for any information contact us at api@sibill.it

Webhook

When you create an integration with Sibill, you may be interested in receiving events as they occur on the entities in your Sibill accounts, so that your backend systems can take action accordingly.

How to use it

To start receiving events in your app:

  1. Create a webhook endpoint to receive events via HTTPS POST requests
  2. Request webhook registration with Sibill
  3. Secure the endpoint

A webhook endpoint is a destination on your server that receives requests from Sibill. Add a new endpoint to your server and make sure it is publicly accessible, so we can send unauthenticated POST requests to it. Also make sure there are no redirects from the destination on your server to other destinations. If a redirect occurs at any point, the destination will be identified as invalid.

1 Create an endpoint to respond to the webhook

Create an HTTPS service that can receive requests using the POST method. The service must return a 2xx status code response as quickly as possible and then execute business logic to avoid potential timeouts.

Example

// Set the content type to application/json
header('Content-Type: application/json');

// Get the raw POST data
$json = file_get_contents('php://input');

// Decode the JSON data
$data = json_decode($json, true);

// Prepare the response array
$response = [];

// Check for JSON decoding errors
if (json_last_error() !== JSON_ERROR_NONE) {
// If there's an error, include it in the response
$response['error'] = 'Invalid JSON';
} else {
// If the JSON is valid, include the parsed data
$response['received'] = $data;
}

// Always return a 200 status code
http_response_code(200);
echo json_encode($response);

2 Register your endpoint

At the moment, registration must be requested by sending an email to api@sibill.it. In this request you will need to provide the HTTPS address of the endpoint that will respond to the calls.

3 Secure the endpoint

It is essential to ensure that the integration takes place in complete security, so that you can be certain that the requests received actually originate from Sibill. For this reason it is necessary to verify the signatures of the received requests.

Some examples are provided below.

Manually verify the webhook signature

You can create a custom solution by following this procedure or follow the examples below. The X-Sibill-Signature header included in every signed event contains a timestamp and a signature that you must verify. The timestamp has a t= prefix and each signature has a scheme prefix. Currently, the only valid scheme for signatures is v1.

X-Sibill-Signature: t=1492774577, v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

Sibill generates signatures using a hash-based message authentication code (HMAC) with SHA-256. To prevent downgrade attacks, ignore all schemes other than v1.

To create a manual solution for signature verification, you need to complete the following steps:

Step 1: extract the timestamp and signature from the header

To get a list of elements, split the header using the , character as a separator. Then split each element using the = character as a separator to get a prefix and value pair. The value of the t prefix corresponds to the timestamp and v1 corresponds to the signature. You can ignore all other elements.

Step 2: prepare the signed_payload string

The signed_payload string is created by concatenating:

  • The timestamp (as a string)
  • The . character
  • The actual JSON payload, i.e. the request body

Step 3: determine the expected signature

Compute an HMAC with the SHA256 hash function. Use the endpoint's private signing key as the key and the signed_payload string as the message.

Step 4: compare the signatures

Compare the signature in the header with the expected signature. For an equality match, calculate the difference between the current timestamp and the received one, then decide whether the difference falls within the tolerance. To protect against timing attacks, use a constant-time string comparison to compare the expected signature with each received signature.

Signature validation example

abstract class WebhookSignature
{
public static function verifyHeader($payload, $header, $secret)
{
// Extract timestamp and signatures from header
$timestamp = self::getTimestamp($header);
$signatures = self::getSignatures($header, 'v1');

if (-1 === $timestamp || empty($signatures)) {
return false;
}

// Check if expected signature is found in list of signatures from header
$signedPayload = "{$timestamp}.{$payload}";
$expectedSignature = self::computeSignature($signedPayload, $secret);
$signatureFound = false;

foreach ($signatures as $signature) {
if (\hash_equals($expectedSignature, $signature)) {
$signatureFound = true;
break;
}
}

return $signatureFound;
}

/**
* Extracts from the headers a particular header given a key name.
*
* @param string $headers the headers of the request
* @param string $header the header to be extracted
*
* @return the string value of the header
*/
private static function getHeader($headers, $header)
{
$items = \explode(',', $headers);

$headerValues = [];
foreach ($items as $item) {
$itemParts = \explode('=', $item, 2);
if (\trim($itemParts[0]) === $header) {
$headerValues[] = $itemParts[1];
}
}

return $headerValues;
}


private static function getTimestamp($header)
{
$res = self::getHeader($header, 't');

if (\count($res) != 1) {
return -1;
}

if (!\is_numeric($res[0])) {
return -1;
}

return (int) $res[0];
}

private static function getSignatures($header, $scheme)
{
return self::getHeader($headers, $scheme);
}

private static function computeSignature($payload, $secret)
{
return \hash_hmac('sha256', $payload, $secret);
}
}

Event delivery behaviours

This section helps you understand the various behaviours to expect regarding how Sibill sends events to the webhook endpoint.

Automatic retries

Sibill attempts to deliver events to your destination for a maximum of two days with a three-hour delay between each retry.

Event ordering

Sibill does not guarantee delivery of events in the order in which they were generated in the system. Be prepared to handle delivery appropriately. You can also use the API to retrieve any missing objects or to reconstruct a state that appears inconsistent.

Webhook best practices

This section lists some best practices for protecting webhook endpoints and making sure they work well with your Sibill integration.

Handle duplicate events

Webhook endpoints might occasionally receive the same event more than once. To protect yourself from receiving duplicate events, handle the event and then do not process already-recorded events; you can rely on various fields including updated_at or infer the validity of the event from the entity's state.

Listen only for the event types required by your integration

Configure your webhook endpoints to receive only the event types required by your integration and ignore others. Listening to all events unnecessarily burdens your server and is therefore not recommended.

Handle events asynchronously

Configure your system to process incoming events with an asynchronous queue. If you choose to process events synchronously, scalability issues may arise. A sharp increase in webhook deliveries (for example, at the end of the month, depending on the frequency of your business) can overload endpoint hosts.

Receive events with an HTTPS server

To receive events from the Sibill webhook, your server must be correctly configured to support the HTTPS protocol and must have a valid certificate.

Prevent replay attacks

A replay attack occurs when an attacker intercepts a valid payload and its signature and then retransmits them. To mitigate these attacks, Sibill includes a timestamp in the X-Sibill-Signature header. Since the timestamp is part of the signed payload, it is also verified by the signature: an attacker therefore cannot modify the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can configure your application to reject the payload.

Return a 2xx response quickly

The endpoint must quickly return a successful status code (2xx) before the execution of any complex logic could cause a timeout. For example, you must return a 200 response before the receiving system performs any operation.