The signature covers the full webhook payload: id, delivered_at, event. Two signature algorithms are supported depending on the keyType:
ED25519 (Recommended)
- Create a payload object:
id, delivered_at, event
- JSON.stringify(payload)
- Encode the JSON string to Base64
- Sign using ED25519 (ed25519.signAsync)
- Encode the signature to Base64
Legacy (Deprecated)
- Create a payload object:
id, delivered_at, event
- JSON.stringify(payload)
- Encode the JSON string to Base64
- SHA256 hash (privateKey + data)
- Encode the hash to Base64
Security Details:
- The signature covers all fields, including id and delivered_at
- A unique id prevents replay attacks
- Timestamp validation prevents accepting outdated webhooks (16-minute window)
- The 16-minute window accounts for retries (immediate + 5 min + 10 min) + network buffer
- ED25519 provides cryptographic authenticity
Retry Logic
- First attempt: Immediately
- Second attempt: delay of 300 seconds (5 minutes)
- Third attempt: delay of 600 seconds (10 minutes)
- Error: task is removed from the queue and logged
IMPORTANT: Always verify webhooks to prevent forgery and replay attacks.
Full Verification Algorithm
ED25519 Verification Steps
- Replay protection - check
webhook.id that it has not been seen before
- Timestamp validation - validate delivery_at within 16 minutes (maximum delivery time + buffer)
- Payload reconstruction -
id, delivery_at, event
- Signature verification - ed25519.verifyAsync (signature, payload, publicKey)
- Store the webhook ID - store it to prevent replay in the future”