Configurable KYC and identity verification platform with templated inquiry flows, embedded React/JS SDKs, and a JSON:API-styled REST + webhook surface. Strong in US/CA consumer fintech and supports global ID document coverage.
- 01consumer KYC
- 02templated identity flows
- 03embedded inquiry UI
- 04government ID + selfie verification
- 05fraud + watchlist screening
- pnpm add persona-react
| Variable | Scope | Description |
|---|---|---|
| NEXT_PUBLIC_PERSONA_TEMPLATE_ID | Client | Persona inquiry template ID (e.g. `itmpl_...`) from Dashboard > Inquiries > Templates. |
| NEXT_PUBLIC_PERSONA_ENVIRONMENT_ID | Client | Persona environment ID (`env_...`) — sandbox or production. |
| PERSONA_API_KEY | Server | Server-side API key for the Persona REST API (used to fetch inquiries, verifications, accounts). |
| PERSONA_WEBHOOK_SECRET | Server | Shared secret for verifying the `Persona-Signature` header (HMAC-SHA256 of the raw body). |
Use Persona for KYC. Render `<PersonaReact templateId={NEXT_PUBLIC_PERSONA_TEMPLATE_ID} environmentId={NEXT_PUBLIC_PERSONA_ENVIRONMENT_ID} referenceId={userId} onComplete={({ inquiryId, status }) => ...} onCancel={...} />` from `persona-react`. Server-side, fetch the canonical result with `GET https://api.withpersona.com/api/v1/inquiries/{inquiryId}` (Bearer `PERSONA_API_KEY`, `Persona-Version: 2025-12-08`) — never trust the client's `status`. Webhook handler at `/api/persona/webhook` verifies `Persona-Signature` (HMAC-SHA256 of raw body, format `t=...,v1=...`) using `PERSONA_WEBHOOK_SECRET`, then handles `inquiry.completed`, `inquiry.approved`, `inquiry.declined`, `verification.passed`, and `verification.failed` events.
- ⚑Persona signs webhooks as `t=<timestamp>,v1=<hmac>` — you must concat `${t}.${rawBody}` before HMAC-SHA256, then constant-time compare. Naive `body`-only HMAC will always fail.
- ⚑Persona retries failed webhooks up to 7 times with exponential backoff after a 5-second timeout; idempotency keys on your handler are required to avoid double-processing.
- ⚑The client `onComplete` payload is NOT a trusted source of truth — always re-fetch the inquiry server-side before granting access; the client can be tampered with.
- ⚑Inquiry templates pin an API version — bumping `Persona-Version` in API calls without updating the template can return fields your code doesn't expect.
- ⚑Coverage is strongest in US/CA/UK/EU; some APAC and African document types fall back to manual review with multi-day SLAs.
- ⚑PII (selfies, ID images) is stored on Persona — your privacy policy and DPA must disclose Persona as a sub-processor, and EU residency must be explicitly requested.