Signing Webhook Requests
Each webhook request must be signed using HMAC-SHA256 with your webhook_secret.
Requests must include the following headers:
X-Webhook-Timestamp: <timestamp>
X-Webhook-Signature: sha256=<signature>
Steps to sign a request:
1. Retrieve yourwebhook_secret. 2. Serialize the request body to a raw string. 3. Generate a Unix timestamp in seconds. 4. Concatenate<timestamp>.<body>. 5. Compute HMAC-SHA256 of this string usingwebhook_secret. 6. Add the signature and timestamp headers to the request.
JavaScript (Node.js)
const crypto = require('crypto');
function signWebhookRequest(body, webhookSecret) {
const timestamp = Math.floor(Date.now() / 1000).toString();
const payload = `${timestamp}.${body}`;
const signature = crypto.createHmac('sha256', webhookSecret)
.update(payload)
.digest('hex');
return { timestamp, signature: `sha256=${signature}` };
}
// Usage
const body = JSON.stringify({ foo: 'bar' });
const { timestamp, signature } = signWebhookRequest(body, process.env.WEBHOOK_SECRET);
Python
import hmac, hashlib, time
def sign_webhook_request(body: str, secret: str):
timestamp = str(int(time.time()))
payload = f"{timestamp}.{body}"
signature = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
return timestamp, f"sha256={signature}"
# Usage
body = '{"foo":"bar"}'
timestamp, signature = sign_webhook_request(body, "your_webhook_secret")
PHP
function signWebhookRequest($body, $secret) {
$timestamp = (string) time();
$payload = $timestamp . '.' . $body;
$signature = hash_hmac('sha256', $payload, $secret);
return [
'timestamp' => $timestamp,
'signature' => 'sha256=' . $signature
];
}
// Usage
$body = json_encode(['foo' => 'bar']);
$result = signWebhookRequest($body, getenv('WEBHOOK_SECRET'));
cURL Example
curl -X POST https://your-webhook-url \
-H "Content-Type: application/json" \
-H "X-Webhook-Timestamp: <timestamp>" \
-H "X-Webhook-Signature: sha256=<signature>" \
-d '{"foo":"bar"}'