verification
use it
# add to stunt.yaml
services:
persona:
adapter: embedded:persona-style
# then
$ stunt upThe embedded: source extracts this adapter from the binary — no git clone, fully offline.
how to mock the Persona Inquiry API locally
Install stunt, paste the service block above into stunt.yaml, run stunt up — then point your client at localhost instead of Persona Inquiry API. It works offline, keeps state across requests and restarts, and every response is synthetic: the route shapes, status codes, pagination, and webhook delivery follow the real Persona Inquiry API 2023-01-05 surface — the data is fake, the behavior is real.
backing stores
inquiriesverificationswebhook_events
api surface (5)
generated from the adapter manifest — exactly what boots, nothing more · covers 1% of the real API's 213 routes (derived from spec Persona API reference @ 1.0.0)
5 routes
POST/api/inquiry/v1/inquiries
GET/api/inquiry/v1/inquiries/{inquiry_id}
POST/api/inquiry/v1/inquiries/{inquiry_id}/resume
GET/api/inquiry/v1/inquiries/{inquiry_id}/verifications
POST/api/inquiry/v1/webhooks
VM-verified behaviors (18)
- ✓a missing, bare or wrong-scheme token is a 401 in the JSON:API error envelope
- ✓a create mints a zero-padded inq_ id in the JSON:API envelope
- ✓sequential creates advance the id sequence
- ✓any Bearer is accepted: the gate checks presence, not a store (as-is)
- ✓a create missing template_id or reference_id is a 400 invalid_request
- ✓the status derives from the clock created to pending to completed
- ✓resume restarts the clock at pending without duplicating verifications
- ✓simulate_fail declines at the terminal transition and seeds nothing
- ✓unknown inquiries are JSON:API 404s on every parameterized route
- ✓verifications are empty until the terminal transition fires
- ✓completion seeds the government-id and selfie verifications
- ✓a fresh correctly-signed webhook is accepted
- ✓a tampered body or wrong MAC is a 401 invalid_signature
- ✓a stale or far-future t is a 401 invalid_timestamp
- ✓a missing header or unparseable signature is a 401
- ✓polling through pending still emits exactly one inquiry.completed
- ✓re-reads and post-resume re-completions do not re-emit
- ✓a declined inquiry emits inquiry.declined signed the same way
Not implemented (5)
- No inquiries list endpoint (GET /api/inquiry/v1/inquiries)
- No inquiry templates or reports endpoints
- No document or selfie upload endpoints (verifications auto-seeded)
- No Transactions API (bank account linking and verification)
- No inquiry cancel, expire, redact, or mark-under-review actions
Differs from the real API (6)
- Fixed clock lifecycle: created (0-1s), pending (1-3s), completed or declined (+3s)
- simulate_fail create flag yields declined instead of completed (stunt-only)
- Webhook HMAC secret is the public constant stunt_persona_mock_signing_key
- POST /api/inquiry/v1/webhooks is a local stand-in receiver with 5-minute replay window
- JSON:API attributes are snake_case; real Persona serializes kebab-case
- Create takes a flat body; real API expects the JSON:API data/attributes wrapper
want more of the Persona Inquiry API surface? adapters are YAML + Starlark — the authoring guide covers adding routes, fixtures, and state machines. Open an issue for anything big first, or just file a PR — merged routes ship in the next release.