Callback Signature
Every Merchant Callback is digitally signed to verify its authenticity and ensure the payload has not been modified in transit.
Before processing a callback, verify both the callback timestamp and the signature using your Callback Signing Secret.
Never process a callback without first validating its timestamp and verifying its signature.
Headers
| Header | Description |
|---|---|
X-Timestamp
|
Unix timestamp used when generating the callback signature. |
X-Signature
|
HMAC SHA-256 signature. |
Signature Algorithm
The signature is computed using HMAC SHA-256.
| Component | Value |
|---|---|
| Algorithm |
HMAC-SHA256
|
| Secret | Your Callback Signing Secret. |
| Message |
<timestamp>.<raw-request-body>
|
| Encoding | Hexadecimal. |
Verification Flow
Receive Callback │ Read X-Timestamp │ Validate Timestamp │ Read Raw Request Body │ timestamp + "." + body │ Calculate HMAC SHA-256 │ Compare with X-Signature │ Signature Valid? ┌────────────┴────────────┐ Yes No │ │ Process Callback Reject Request
Example (PHP)
$timestamp = $request->headers->get('X-Timestamp');
$signature = $request->headers->get('X-Signature');
$payload = $request->getContent();
$message = $timestamp . '.' . $payload;
$expected = hash_hmac(
'sha256',
$message,
$callbackSigningSecret
);
if (!hash_equals($expected, $signature)) {
throw new Exception(
'Invalid callback signature.'
);
}
Reject callbacks whose
X-Timestamp
falls outside an acceptable time window
(for example, ±5 minutes).
This protects your application against replay attacks.
Always use the raw HTTP request body exactly as received. Parsing and re-encoding the JSON may change the payload and invalidate the signature.
Common Mistakes
- Using the parsed JSON instead of the raw request body.
-
Omitting the
X-Timestampwhen generating the signature. - Using the API Secret instead of the Callback Signing Secret.
-
Comparing signatures using
==instead ofhash_equals().
Next Step
Continue to the Go Live Checklist before moving your integration to production.