Prerequisites
Please acquire Webhook Signature Secret which is needed to compute the signature and compare to the one Xenith sent from webhook. Refer here to check your webhook signature secret in the platform. Feel free to reach out to us at [email protected] if you have any inquiries.
Xenith signs all webhook events by including a signature in the request headers. This allows you to verify that the events were sent by Xenith. Follow these steps to verify the signature:
- Construct the string to be signed by concatenating the following elements separated by \n character:
{HTTP_METHOD}\n{URL_PATH}\n{REQUEST_BODY}\n{TIMESTAMP_RFC3339}- HTTP_METHOD:
POST, all in uppercase - URL_PATH: The full path of the URL
- REQUEST_BODY: The full body of the request
- TIMESTAMP_RFC3339: The timestamp from
X-Xenith-Timestampheader in RFC3339 format (e.g., 2026-07-16T12:34:56.123456789Z)
- HTTP_METHOD:
- Create an HMAC using SHA256 hash from the concatenated string as the message and your Webhook Signature Secret as the secret key
- Encode the resulting hash in Base64
- Verify the generated signature with the
X-Xenith-Signatureheader from the webhook request is the same with computed signature by your system - Ensure the timestamp in the
X-Xenith-Timestampheader is within an acceptable time range to prevent replay attacks
The actual signature will vary based on your specific inputs. The secret used for signature verification should be securely stored on your server and will not be transmitted with the webhook payload.
Request Header Parameters
| Header Key | Example Value |
|---|---|
Content-Type | application/json |
X-Xenith-Timestamp | 2026-07-16T12:34:56.123456789Z |
X-Xenith-Signature | Computed Signature |
Try the Webhook Signature Simulator
Webhook Signature Simulator
Reproduce the signature Xenith sends with a webhook. All calculation happens in this browser.
Signature result
String to sign
POST\n/webhooks/example\n{"data":{"currency":"IDR","paymentChannels":["MDR.VA","BNI.VA"],"paymentMethod":"VIRTUAL_ACCOUNT","status":"INACTIVE"},"eventType":"maintenance.started.payins","schemaVersion":"1.0.1","timestamp":"2026-07-16T12:34:56.123456789Z"}\n2026-07-16T12:34:56.123456789ZBase64 HMAC-SHA256
0x5c 0x6e), not line-feed bytes.Compare a received signature
Example
Reference implementations
<?php
$method = 'POST';
$path = '/webhooks/example'; // Path only: no host or query string
$rawBody = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_XENITH_TIMESTAMP'];
$secret = getenv('XENITH_WEBHOOK_SECRET');
// Single-quoted '\n' is a literal backslash followed by n in PHP.
$stringToSign = $method . '\n' . $path . '\n' . $rawBody . '\n' . $timestamp;
$computed = base64_encode(hash_hmac('sha256', $stringToSign, $secret, true));
if ($computed === $_SERVER['HTTP_X_XENITH_SIGNATURE']) {
echo 'Signature is valid';
}
