Agent skill
Autosana Webhooks Skill
Receive and verify Autosana webhooks. Use when setting up Autosana webhook handlers, debugging X-Autosana-Signature-256 signature verification, or handling the batch.completed event sent when a batch of AI end-to-end test flow runs finishes.
Install this skill
npx skills add hookdeck/webhook-skills --skill autosana-webhooks
Autosana (AI end-to-end testing for mobile apps and websites) sends an HTTP POST to your HTTPS endpoint when a batch of flow runs completes. If you set a signing secret on the webhook, each payload is signed with HMAC-SHA256.
When to Use This Skill
- How do I receive Autosana webhooks?
- How do I verify the
X-Autosana-Signature-256header? - Why is my Autosana webhook signature verification failing?
- How do I handle the
batch.completedevent and read run group results? - Why do unsigned Autosana deliveries fail verification?
Verification (core)
With a signing secret configured, Autosana sends X-Autosana-Signature-256: sha256=<hex>, where <hex> is the HMAC-SHA256 of the raw request body keyed with the secret as UTF-8. Require and strip the sha256= prefix. Without a signing secret the deliveries are unsigned, so verification fails by design.
Node (check the hex shape first: Buffer.from(x, 'hex') silently truncates invalid input):
const crypto = require('crypto');
function verify(rawBody, signatureHeader, secret) {
if (!signatureHeader || !signatureHeader.startsWith('sha256=')) return false;
const received = signatureHeader.slice('sha256='.length);
if (!/^[0-9a-f]{64}$/i.test(received)) return false;
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest();
return crypto.timingSafeEqual(Buffer.from(received, 'hex'), expected);
}
Python (encode both sides to bytes so a non-ASCII header gives a 400, not a 500):
import hmac, hashlib
def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
if not signature_header or not signature_header.startswith("sha256="):
return False
received = signature_header[len("sha256="):].lower()
computed = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(received.encode("utf-8"), computed.encode("utf-8"))
In Express use express.raw({ type: '*/*' }) so the body stays a raw Buffer whatever the content type.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Common Event Types
The event name is in the JSON body as event; there is no event header. Autosana documents one notification:
| Event | Description |
|---|---|
batch.completed | A batch of flow runs finished (summary has total_groups, passed_groups, failed_groups; run_groups lists each group and its runs) |
See references/overview.md for the full payload.
Important Headers
| Header | Description |
|---|---|
X-Autosana-Signature-256 | sha256=<hex> HMAC-SHA256 of the raw body (only sent when a signing secret is set) |
Header names are case-insensitive.
Setup with Hookdeck
In Autosana go to Settings > Integrations > Webhooks, click Add Webhook, enter the Hookdeck source URL, and set a signing secret. Without one, deliveries are unsigned and fail verification. Use the same secret as the Hookdeck source's signing secret (Autosana source type). See references/setup.md.
Environment Variables
AUTOSANA_WEBHOOK_SECRET=your_signing_secret # Signing secret set on the Autosana webhook
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 autosana --path /webhooks/autosana
Reference Materials
- references/overview.md - Autosana webhook concepts, event and payload
- references/setup.md - Creating the webhook and signing secret
- references/verification.md - Signature verification details