API & webhooks
Verify webhook signatures
Cryptographically prove a webhook came from Qubed.
Every webhook delivery includes an X-Qubed-Signature header in the format t=<timestamp>,v1=<hmac_sha256_hex>. The signed payload is <timestamp>.<raw_body>, signed with your endpoint's signing secret using HMAC-SHA256.
Get the secret from the dashboard when you create the endpoint. Store it as QUBED_WEBHOOK_SECRET (or the equivalent in your secret manager) — it's distinct from your API token and is only used for signature verification.
Verify in Node with the crypto module: crypto.createHmac('sha256', secret).update(${timestamp}.${rawBody}).digest('hex'), then compare with crypto.timingSafeEqual against the v1 field. Never use === — it's vulnerable to timing attacks.
Reject any request where the timestamp is more than 5 minutes old. This prevents replay attacks. If verification fails, return a 401 and Qubed will retry with the same payload, so you have a chance to fix the secret before the 24-hour retry window closes.