Webhook Event Signing

Optional HMAC-based webhook content validation via a shared secret

📘

New in release v0.2.124

  • Sandbox release date: Aug 13, 2025
  • Prod release date:

It's now possible to validate that the webhook event your app receives from Sila:

  • has actually been sent by Sila
  • has not been tampered with in transit

Starting in mid-August 2025 (when release v0.2.124 is put into production), webhook events sent from Sila will contain three new headers:

  • SILA-WEBHOOK-ID
  • SILA-WEBHOOK-TYPE
  • SILA-SIGNATURE

Sample webhook headers

sila-webhook-id: 978d8989-e0c6-4e55-9901-2c433ef33980
sila-webhook-type: transaction_update
sila-signature: VKF5Hv4zuWW6qAVcMgpGAjxFCtbPrujnc4xvaDNF0aU=

Webhook header values

SILA-WEBHOOK-ID

This header will contain the UUID which uniquely identifies which of your defined webhook endpoints was responsible for generating this particular event. All events emitted from the same webhook endpoint definition will have the same WEBHOOK-ID.

The body of the event will contain a event_uuid which will be unique for every event; no two events will ever have the same event_uuid

SILA-WEBHOOK-TYPE

The descriptive name for the webhook endpoint; transaction_update, account_link, etc.

SILA-SIGNATURE

This will be a 44-character string comprised of seemingly random characters. An example will look like

VKF5Hv4zuWW6qAVcMgpGAjxFCtbPrujnc4xvaDNF0aU=

Webhook Event Validation

Event validation is entirely optional; you may ignore the SILA-* headers and consume the webhook event in the form that it was received.

📘

It's important to note that the webhook event body is not encrypted with the webhook signing key, nor does it need to be decrypted upon receipt. It's sent in cleartext, and encryption is accomplished via TLS over the HTTPs protocol.

In order to validate the webhook event, you compute the signature from several parts of the webhook event and your copy of the shared secret. If both the sender and receiver use the same shared key, they should both compute the the same signature from the same data.

Signature calculation

To calculate the signature, you first build a string composed of three parts, in this exact order, with no spaces between the parts:

import base64
import hashlib
import hmac

string_to_hash: str = ( 
    headers[WebhookHeader.ID.value] +
    headers[WebhookHeader.TYPE.value] +
    json.dumps(request_body, separators=(',', ':'))
)

computed_signature: str = base64.b64encode(
    hmac.digest(
        webhook_signing_key.encode('utf-8'),
        string_to_hash.encode('utf-8'),
        hashlib.sha256
    )   
).decode('utf-8')

Once the string has been built, you generate an HMAC digest by providing:

  • the webhook signing key
  • the string to hash
  • the agreed-upon hashing library (Sila has chosen SHA256).

Then the HMAC digest is base64-encoded, then converted to a string.

It's important to note that the request body (the third part of the string), must have no spaces before or after the JSON item and key separators: json.dumps(...., separators=(',', ':'). If there are spaces, the signature computed will differ.

Once you've computed the signature from the received webhook event, compare it to the SILA-SIGNATURE header value. If the signatures match, the webhook event can be considered validated.

Which Signing Key To Use?

Every webhook endpoint defined for you app in the Endpoints Dashboard will now display a "webhook signing key" expressed as a 64-digit hexadecimal integer. If one has not been defined for a pre-existing webhook endpoint, there will be a "create key" button which should allow you to generate one.

Each webhook endpoint will have a unique signing key, as well as a unique UUID. Since the UUID is also passed in the header as SILA-WEBHOOK-ID, you may want to store the UUID and signing key together, and lookup the signing key by the UUID.