Get the key in Console
Sign in to Console → Settings → Webhook security and select Show key, then Copy key. Store it only in your server secret configuration, for example APISTABLE_WEBHOOK_SECRET. It is an account-level signing key, separate from API keys; replacing an API key does not change it. The key is hidden by default and is not included in ordinary settings responses. Open account settingsSignature format
Read X-APIstable-Timestamp (Unix seconds), X-APIstable-Signature and X-APIstable-Event-Id. Compute HMAC-SHA256 using the exact copied key as a UTF-8 string, over timestamp + ”.” followed by the unmodified request body bytes. Encode the digest as lowercase hexadecimal. The header contains v1=<64 hex characters>. Do not hex-decode the key or sign a parsed/re-serialized JSON body. This protocol differs from Kie: the full body is signed, not only the task ID.- Reject missing/malformed signatures and timestamps more than 300 seconds in the past or future. Keep the receiver clock synchronized.
- Use a constant-time comparison. During key rotation, the signature header contains comma-separated v1 values; accept the request if any value matches your configured key.
Node.js verification
With Express, use express.raw({type:“application/json”}) on the callback route before any express.json() middleware. Pass req.body as a Buffer and req.get(…) header values. Call verifyWebhook before parsing JSON.
Python verification
For Flask, pass request.get_data() bytes and request.headers values. Verify before calling request.get_json(). Both examples return false on an invalid signature; reject it with HTTP 401.