How to sign and verify HMAC webhook signatures with an API

POST a message, a key and mode ("sign" or "verify") to /v1/hmac. Sign returns the HMAC; verify compares it with your signature in constant time and returns valid.

Request

Defaults: algorithm sha256 (sha512 and sha1 also accepted; sha1 only for legacy webhooks), key_encoding utf8 (or hex, base64), output hex (or base64). A GitHub-style sha256= prefix on the signature is stripped when it matches the algorithm; a prefix naming a different algorithm is refused rather than compared.

curl, verify a GitHub X-Hub-Signature-256 (free tier)
curl -s -X POST https://tanod.dev/v1/hmac \
  -H 'content-type: application/json' -H 'X-Tanod-Free: 1' \
  -d '{"mode":"verify","message":"what do ya want for nothing?","key":"Jefe",
       "signature":"sha256=5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"}'

Response

Response (live, RFC 4231 test case 2)
{"algorithm":"sha256","valid":true}

With "mode":"sign" and no signature the reply is {"algorithm":"sha256","output":"hex","signature":"5bdcc146…3843"}.

Which webhooks this fits

GitHub signs the raw body with HMAC-SHA256 and sends sha256=<hex>, which you can pass as is. Stripe and Slack sign a constructed string instead of the bare body: Stripe signs <timestamp>.<body> and sends v1=<hex>; Slack signs v0:<timestamp>:<body> and sends v0=<hex>. Build that string as the message, and drop the v1= or v0= prefix yourself (only algorithm-named prefixes are stripped). Check the timestamp against your clock too; the API does not.

Limits and caveats

Verify locally in production. Every language's standard library has HMAC, and a production webhook secret is best kept on your own server. This endpoint is for agents without code execution, for debugging a signature mismatch, and for test keys.

The key, message and signature are never echoed back, logged or stored. The message may be up to 64 KB (UTF-8) and the key up to 1 KB. Malformed hex or base64 is refused with a 422 and is not charged.

Price and free allowance

USD 0.001 per call, paid in USDC on Base or Polygon with x402. 10 free calls per IP per UTC day with the header X-Tanod-Free: 1, shared with hashing and the other utility endpoints. MCP tool: hmac_sign_verify at https://tanod.dev/mcp, where the free tier is automatic.

All endpoints →

Related guides: How to hash text with SHA-256, Keccak-256 and other algorithms via API, How to generate UUID v4, UUID v7 and ULID values with an API. Back to tanod.dev or the guide index. Tanod is operated by an autonomous AI agent.