Authentication
Every /api/v1 request authenticates with a secret API key, presented as a Bearer token:
curl https://app.personablocks.io/api/v1/verification-sessions \ -H "Authorization: Bearer pb_sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "flows": ["wallet", "phone"], "test_outcome": "approved" }'There is no cookie, session, or query-parameter fallback — the Authorization: Bearer header is the
only way in. A request without a valid key never reaches a resource handler.
Key modes: test vs. live
Section titled “Key modes: test vs. live”Keys come in two modes, distinguished by prefix:
| Prefix | Mode | Behavior |
|---|---|---|
pb_sk_test_ | Test (sandbox) | Never billed, never written on-chain, never sends SMS. Reads the sandbox, not live customer data. |
pb_sk_live_ | Live (production) | Real verifications, real billing, real on-chain writes. |
The mode is a property of the key, never of the request body. You never pass a livemode flag —
the key you present decides the mode, and the response echoes it back as livemode: true|false. This
is deliberate: it makes it impossible to accidentally run test traffic against production, or vice
versa, by fumbling a request field.
How keys are created and stored
Section titled “How keys are created and stored”Keys are minted by the merchant account owner in the portal (Account → Developers). Each key:
- is scoped — it carries a fixed set of permissions chosen at mint time (see below);
- is stored only as a SHA-256 hash — PersonaBlocks never keeps the plaintext;
- is shown exactly once, on the create response. Copy it into your secret store immediately. If you lose it, you cannot retrieve it — revoke it and mint a new one.
Scopes
Section titled “Scopes”A key grants access only to the scopes it was minted with. A request to a route whose required scope is
absent fails with 403 missing_scope. The seven scopes are:
| Scope | Grants |
|---|---|
sessions:write | Create, read, list, and cancel verification sessions. |
customers:read | Read and list customers and their notes. |
customers:write | Suspend/unsuspend customers and write notes. |
decisioning:read | Read reviews and decision rules. |
decisioning:write | Resolve reviews. |
reverification:write | Mint and read reverification requests. |
webhooks:manage | Manage webhook endpoints and read the event log. |
Grant a key the narrowest set it needs. A backend that only mints sessions and consumes webhooks needs
sessions:write and webhooks:manage and nothing more.
Credential boundaries
Section titled “Credential boundaries”The /api/v1 surface accepts secret keys only, and secret keys work only here. Two boundaries
are enforced in both directions:
- Secret keys are rejected by the portal. A
pb_sk_...key sent to a/api/merchant/*portal route is refused — those routes authenticate a browser session, not an API key. - WooCommerce Store Keys are rejected by
/api/v1. Apbk_...Store Key belongs to a different program (it licenses the WooCommerce plugin and authenticates that plugin’s own endpoints). It is not an API key, and/api/v1refuses it.
These are two disjoint credential spaces on purpose — a Store Key licenses the plugin, a secret key calls the public API.
Rotating a key
Section titled “Rotating a key”There is no in-place rotation. To rotate, mint a new key, deploy it, then revoke the old one from the Developers tab. Overlapping the two briefly lets you cut over with zero downtime before you retire the previous key.
Related
Section titled “Related”- Errors —
missing_api_key,invalid_api_key,missing_scope,live_key_required. - Sandbox & testing — what a
pb_sk_test_key can and can’t do. - Go live — the checklist gating your first
pb_sk_live_key. - Web SDK — how the frontend authenticates with a
pbvs_client token, never a secret key.