Skip to main content

Overview

Our webhooks include a signature in the request headers to ensure authenticity and integrity. This document explains the headers sent with every webhook, how the signature is generated and how you can verify it to ensure that the webhook payload was sent by our system. Webhooks are signed with the HMAC-SHA256 signature when your account has a webhook registered with a secret for the payin or payout event through the Webhook Setup API.
⚠️ DEPRECATED: Legacy API key signature. Webhooks delivered to the notification_url of a transaction (no webhook registered for the event), as well as Automatic PIX authorization and schedule webhooks, are still signed with the deprecated API key signature. It is not recommended, will be removed in the future and must not be used in new integrations — register a webhook with a secret and use the HMAC-SHA256 signature instead.If you still need to validate it, see Legacy Webhook Signature (Deprecated).
The registered URL overrides the URL sent in each request. Once a webhook is registered for the payin or payout event, every webhook of that event — status updates, refunds and Data Qualifications — is delivered to the registered URL, and the notification_url / callback_url sent when creating a transaction is ignored.
Registering, updating or removing a webhook may take up to 5 minutes to take effect. Until then, webhooks keep being delivered to the previous destination.

Request Headers

All webhooks are sent using the POST method with a JSON body.
A new x-webhook-wp-timestamp (and therefore a new signature) is generated on every delivery attempt, including retries.

Webhook types

Possible values of the x-webhook-wp-type header:

HMAC-SHA256 Signature

This is the recommended way to verify webhooks.

Enabling it

Register a webhook for the payin and/or payout event with a secret using the Webhook Setup API. The secret is only known to you and WEpayments — store it safely and never expose it on the client side.
If a webhook is registered without a secret, the x-webhook-wp-type and x-webhook-wp-timestamp headers are still sent, but no x-webhook-wp-signature header is included.

How the signature is generated

Where:
  • secret: the secret you registered for the event, used as-is
  • raw_body: the raw HTTP request body, exactly as received
  • timestamp: the value of the x-webhook-wp-timestamp header
  • raw_body and timestamp are concatenated with no separator
  • The result is sent as lowercase hexadecimal in the x-webhook-wp-signature header
Always compute the signature over the raw request body. Do not parse and re-serialize the JSON before verifying — the body may contain escaped characters (for example \/ and \uXXXX) and any change in formatting or key order produces a different signature.

Signature Verification

  1. Read the x-webhook-wp-timestamp and x-webhook-wp-signature headers
  2. Reject the request if the timestamp is too old (we recommend a tolerance of 5 minutes) to protect against replay attacks
  3. Concatenate the raw request body with the timestamp
  4. Compute the HMAC-SHA256 of the concatenated string using your secret, encoded as hexadecimal
  5. Compare the result with the x-webhook-wp-signature header using a constant-time comparison
If the signatures match, the webhook is verified as authentic.

Example

For a webhook with the following data:
  • secret = s3cr3t
  • x-webhook-wp-timestamp = 1790000000
  • Raw body = {"id":123456,"status":{"id":3,"name":"Paid"},"notification_url":"https:\/\/example.com\/hook"}
Signed string: {"id":123456,"status":{"id":3,"name":"Paid"},"notification_url":"https:\/\/example.com\/hook"}1790000000 Expected x-webhook-wp-signature: 7ca0961c467990b1c7f2bc53e7b789441ac1a1b5d4eddc6686d7c63de91bed8e

Rotating the secret

Update the webhook with a new secret using the Webhook Update API. Since changes may take up to 5 minutes to take effect, accept signatures computed with either the old or the new secret during this period.

Webhook Setup

Register a webhook URL and secret

KYC Webhook

Learn about KYC webhooks

Payin Callback

Payin webhook callback

Payout Callback

Payout webhook callback
For any further questions or issues, please reach out to our support team.