Agent skill
Persona Webhooks Skill
Receive and verify Persona webhooks. Use when setting up Persona webhook handlers, debugging Persona-Signature verification, or handling identity verification events like inquiry.completed, inquiry.approved, verification.passed, account.created, or case.resolved.
Install this skill
npx skills add hookdeck/webhook-skills --skill persona-webhooks
When to Use This Skill
- How do I receive Persona webhooks?
- How do I verify the Persona-Signature header?
- Why is my Persona webhook signature verification failing?
- How do I handle inquiry.completed, inquiry.approved, or verification.passed events?
- How do I parse Persona's JSON:API webhook payloads?
Verification (core)
Persona has no official server-side SDK — verify the Persona-Signature header manually. It is a Stripe-style scheme (NOT Standard Webhooks): the header is t=<unix_seconds>,v1=<hex>, and v1 is an HMAC-SHA256 hex digest over `${t}.${rawBody}` keyed with the per-webhook secret (wbhsec_...). Use the raw request body — never JSON.parse first. During secret rotation the header carries two space-separated t=...,v1=... pairs; accept if any v1 matches.
const crypto = require('crypto');
function verifyPersonaSignature(rawBody, header, secret) {
if (!header) return false;
// Rotation: header may hold two space-separated "t=...,v1=..." pairs.
return header.trim().split(/\s+/).some((pair) => {
const parts = pair.split(',');
const t = parts.find((p) => p.startsWith('t='))?.slice(2);
const v1 = parts.find((p) => p.startsWith('v1='))?.slice(3);
if (!t || !v1) return false;
const expected = crypto.createHmac('sha256', secret)
.update(`${t}.${rawBody}`).digest('hex');
const a = Buffer.from(v1, 'hex');
const b = Buffer.from(expected, 'hex');
return a.length === b.length && crypto.timingSafeEqual(a, b);
});
}
Persona documents no timestamp tolerance — signature validity is the check. Add your own replay window only if you need one. See references/verification.md for the Python version, rotation details, and gotchas.
For complete handlers with route wiring, event dispatch, and tests, see:
Payload Shape
Persona webhook bodies are JSON:API envelopes. The important paths:
| Path | Meaning |
|---|---|
data.attributes.name | Event type, e.g. inquiry.completed |
data.attributes.payload.data | The affected object (same schema as the API response) |
data.attributes.created-at | Use to order events — delivery is not ordered |
data.id | Event ID — use as the idempotency key |
Each webhook is pinned to a configurable API version, which fixes the payload schema.
Common Event Types
| Event | Triggered When |
|---|---|
inquiry.created | A new inquiry is created |
inquiry.completed | An end user finishes all inquiry steps |
inquiry.approved | An inquiry is approved (auto or manual) |
inquiry.declined | An inquiry is declined |
inquiry.marked-for-review | An inquiry needs manual review |
inquiry.failed | An inquiry fails (too many attempts) |
inquiry.expired | An inquiry expires before completion |
verification.passed | A verification passes |
verification.failed | A verification fails |
account.created | An account is created |
account.archived | An account is archived |
case.created | A case is opened |
case.resolved | A case is resolved |
report/watchlist.ready | A watchlist report finishes (report events use the report/<type>.<action> slash form) |
For the full event list, see Persona Events.
Environment Variables
# Persona webhook signing secret (wbhsec_...)
# Dashboard -> Webhooks -> select your webhook -> reveal the secret
PERSONA_WEBHOOK_SECRET=wbhsec_your_webhook_secret_here
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 persona --path /webhooks/persona
Then create a test inquiry in the Persona Dashboard, or use Webhooks → Recent events → Resend to redeliver a past event (events are retained for 30 days).
Reference Materials
- references/overview.md - What Persona webhooks are, event types, payload shape
- references/setup.md - Dashboard configuration, signing secret, IP allowlist
- references/verification.md - Signature verification details and gotchas