Skip to main content

Security & Verification

All webhooks include Standard Webhooks security headers for verification:
  • webhook-id: Unique identifier for the webhook event (used as idempotency key)
  • webhook-timestamp: Unix timestamp when the webhook was sent
  • webhook-signature: HMAC signature of the payload using your webhook secret
Signatures are HMAC-SHA256 over id.timestamp.body, following the Standard Webhooks specification.
The HMAC key is the literal UTF-8 bytes of your webhook secret, exactly as returned when the webhook was created — including any prefix. Do not Base64-decode the secret and do not strip a prefix before signing.Some Standard Webhooks libraries Base64-decode the secret in their default constructor. Those constructors derive a different key and reject valid AhaSend deliveries. Use your library’s raw-key mode instead — for example NewWebhookRaw in Go, or new Webhook(secret, { format: "raw" }) in JavaScript.
The easiest path is a verifier that already implements this correctly, such as the official AhaSend SDKs. Whatever you use, verify against the raw request body bytes (before any JSON parsing), and reject deliveries whose webhook-timestamp is outside your tolerance window in either direction to prevent replay.