Algorithm
The signature is calculated as: MD5(base64(JSON.stringify(payload)) + webhookSecret)
TypeScript Example
import crypto from 'crypto';
function generateSign(payload: object, webhookSecret: string): string {
const payloadString = JSON.stringify(payload);
const base64Payload = Buffer.from(payloadString).toString('base64');
const hash = crypto
.createHash('md5')
.update(base64Payload + webhookSecret)
.digest('hex');
return hash;
}
function isValidWebhookSign(payload: object, receivedSign: string, webhookSecret: string): boolean {
// remove sign from payload before verification
const { sign, ...payloadWithoutSign } = payload as any;
const expectedSign = generateSign(payloadWithoutSign, webhookSecret);
return receivedSign === expectedSign;
}
// example usage
app.post('/webhook', (req, res) => {
const payload = req.body;
const receivedSign = payload.sign;
const webhookSecret = process.env.WEBHOOK_SECRET; // your webhook secret from dashboard
if (!isValidWebhookSign(payload, receivedSign, webhookSecret)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// process webhook...
res.json({ success: true });
});
JavaScript Example
const crypto = require('crypto');
function generateSign(payload, webhookSecret) {
const payloadString = JSON.stringify(payload);
const base64Payload = Buffer.from(payloadString).toString('base64');
const hash = crypto
.createHash('md5')
.update(base64Payload + webhookSecret)
.digest('hex');
return hash;
}
function isValidWebhookSign(payload, receivedSign, webhookSecret) {
// remove sign from payload before verification
const { sign, ...payloadWithoutSign } = payload;
const expectedSign = generateSign(payloadWithoutSign, webhookSecret);
return receivedSign === expectedSign;
}
// example usage
app.post('/webhook', (req, res) => {
const payload = req.body;
const receivedSign = payload.sign;
const webhookSecret = process.env.WEBHOOK_SECRET; // your webhook secret from dashboard
if (!isValidWebhookSign(payload, receivedSign, webhookSecret)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// process webhook...
res.json({ success: true });
});
Python Example
import hashlib
import base64
import json
def generate_sign(payload, webhook_secret):
payload_string = json.dumps(payload, separators=(',', ':'))
base64_payload = base64.b64encode(payload_string.encode()).decode()
hash_input = base64_payload + webhook_secret
return hashlib.md5(hash_input.encode()).hexdigest()
def is_valid_webhook_sign(payload, received_sign, webhook_secret):
# Remove sign from payload before verification
payload_without_sign = {k: v for k, v in payload.items() if k != 'sign'}
expected_sign = generate_sign(payload_without_sign, webhook_secret)
return received_sign == expected_sign
# Example usage
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.json
received_sign = payload.get('sign')
webhook_secret = os.environ.get('WEBHOOK_SECRET') # Your webhook secret from dashboard
if not is_valid_webhook_sign(payload, received_sign, webhook_secret):
return jsonify({'error': 'Invalid signature'}), 401
# Process webhook...
return jsonify({'success': True})
Important: Always verify webhook signatures before processing. The webhook secret is available in your API project settings in the dashboard. Never expose your webhook secret in client-side code.