Skip to main content

Verifying Webhook signatures in Appical

Learn how to set a Webhook signing secret in Appical and how the receiving system can verify requests actually came from Appical.

Overview

The signing secret lets the receiving system check that a request came from Appical and was not changed on the way. It is optional, but recommended for every Webhook, since all events carry personal data.

Setting the secret

  • Appical does not generate the secret. You create one, enter it in the Signing Secret field, and give the same value to whoever builds the receiving side.

  • Use a long random value, for example 32 or more characters from a password generator. The secret is used exactly as typed, including any spaces.

  • After saving, the secret is never shown again, also not to admins. Store it safely, for example in a password manager, before clicking Create.


Changing or removing the secret

Open the Webhook with the pencil icon. A saved secret shows as dots, with two buttons:

  • Replace: enter the new value under New signing secret and click Update.

  • Remove: click Remove, then Update. Requests are then sent without a signature.

📌 Important:

  • A change applies to every request sent after saving, including replays of older deliveries.

  • Update the receiving system at the same moment, or its checks will fail.

  • To change the secret without rejected requests, let the receiver accept both the old and the new secret for a short while.

What Appical sends

Every request has a webhook-id and a webhook-timestamp header. With a secret set, it also has webhook-signature: the text v1, followed by a Base64-encoded HMAC-SHA256 signature. Test events and replays are signed too. A replay gets a new timestamp and a new signature, so it passes the receiver's time check.

Verifying a request

The signature follows the Standard Webhooks spec. The receiver:

  1. Takes the raw request body exactly as received, before parsing or re-formatting the JSON.

  2. Builds the text ...

  3. Computes an HMAC-SHA256 of that text, with the secret as typed in Appical as the key.

  4. Base64-encodes the result and compares it with the part after v1, in webhook-signature, using a constant-time comparison.

  5. Rejects the request if webhook-timestamp is more than 5 minutes away from its own clock.

📌 Important:

  • The official Standard Webhooks libraries, available for most languages, do these steps for you.

  • They expect the secret as whsec_ followed by the Base64 encoding of the secret, not the secret as typed.

  • For a secret mysecret, pass whsec_bXlzZWNyZXQ=. Passing the plain secret makes every check fail.

→ Example values to test a check against

secret:             mysecret
webhook-id:         evt-example
webhook-timestamp:  1780306200
body:               {"event":"user.created","delivered_at":"2026-06-01T09:30:00Z","application_id":123,"data":{"user_id":42}}
webhook-signature:  v1,L3bBkX/a0IVLkzn8uMVxBXQU4K7RxrIRKBbaMmxkOkE=

👉 Let us know if this article answered your question by using the buttons below. If not, get in touch with our Support Channel for more information:

Did this answer your question?