Signing & Verification
Every webhook delivery includes a signature so your server can verify that the request came from Tolinku and was not modified in transit.
How signing works
Section titled “How signing works”- Tolinku serializes the JSON payload body.
- It computes an HMAC-SHA256 hash using your webhook’s signing secret.
- The hex-encoded hash is sent in the
X-Webhook-Signatureheader. - The event type is sent in the
X-Webhook-Eventheader.
Your server should compute the same HMAC and compare it to the header value.
Verification examples
Section titled “Verification examples”import crypto from 'crypto';
function verifyWebhook(payload, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex');
return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) );}
// In your Express handler:app.post('/webhooks/tolinku', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-webhook-signature']; const event = req.headers['x-webhook-event'];
if (!verifyWebhook(req.body, signature, process.env.TOLINKU_WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); }
const payload = JSON.parse(req.body); console.log(`Received ${event}:`, payload.data);
res.status(200).send('OK');});import hmacimport hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool: expected = hmac.new( secret.encode(), payload, hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected)
# In your Flask handler:@app.route('/webhooks/tolinku', methods=['POST'])def handle_webhook(): signature = request.headers.get('X-Webhook-Signature') event = request.headers.get('X-Webhook-Event')
if not verify_webhook(request.data, signature, WEBHOOK_SECRET): return 'Invalid signature', 401
payload = request.get_json() print(f'Received {event}:', payload['data'])
return 'OK', 200Important notes
Section titled “Important notes”- The signature is computed on the raw request body (the exact bytes sent), not on a parsed and re-serialized JSON object. Use the raw body for HMAC computation.
- If your web framework automatically parses JSON, you need to configure it to also preserve the raw body (as shown in the Express example above with
express.raw()). - The signing secret starts with
whsec_. Store it as an environment variable, not in your source code.