Errors
Every failed /api/v1 request returns the same JSON envelope. Branch on the machine-readable code
rather than parsing message text — the code is stable across API versions, the message is not.
{ "error": { "type": "invalid_request", "code": "invalid_ttl", "message": "ttl must be one of 1h, 24h, 3d, 7d", "request_id": "req_9tKf2mVxWyN4rLbJfHd3", "doc_url": "https://www.personablocks.io/docs/api/errors#invalid_ttl" }}| Field | What it’s for |
|---|---|
type | A coarse category (see the table below) — dispatch broad handling on this. |
code | The specific, stable error identifier — branch your logic on this. |
message | A human-readable explanation. For logs and support, not for parsing. |
request_id | The req_... id of this request. Quote it in support tickets. |
doc_url | A deep link to this code’s entry on this page. |
Types and status codes
Section titled “Types and status codes”The type maps to the HTTP status by default:
| Status | type | Meaning |
|---|---|---|
| 400 | invalid_request | The request was malformed or failed validation. |
| 401 | authentication | The API key was missing or invalid. |
| 402 | billing | Payment is required — the account is past due. |
| 403 | permission | Authenticated, but not allowed to do this. |
| 404 | not_found | No such route or resource. |
| 409 | conflict | The resource’s current state forbids the operation. |
| 429 | rate_limited | Too many requests — back off and retry. |
| 5xx | internal | Something failed on our side. |
Error catalog
Section titled “Error catalog”Every code the API can return, grouped by category.
Authentication (401)
Section titled “Authentication (401)”missing_api_key
Section titled “missing_api_key”401. No Authorization: Bearer token was supplied. Send your key as
Authorization: Bearer pb_sk_....
invalid_api_key
Section titled “invalid_api_key”401. A key was supplied but doesn’t match an active key, or isn’t a pb_sk_test_/pb_sk_live_
secret key. The key may be revoked or mistyped — mint a fresh one from the Developers tab.
invalid_console_token
Section titled “invalid_console_token”401. A short-lived pb_ct_ console token (used by the in-browser API console) is invalid or has
expired. Mint a new one from the Developers tab.
Permission (403)
Section titled “Permission (403)”missing_scope
Section titled “missing_scope”403. Your key lacks the scope this route requires. Re-mint the key with the needed scope — see Authentication.
live_key_required
Section titled “live_key_required”403. A sandbox (pb_sk_test_) key tried to write live customer data (suspend/unsuspend, notes,
review resolution, or a reverification mint). These routes touch real records regardless of key mode,
so they require a pb_sk_live_ key.
not_your_note
Section titled “not_your_note”403. You tried to edit a customer note authored by someone else. A key can only edit notes it created.
Rate limiting (429)
Section titled “Rate limiting (429)”rate_limit_exceeded
Section titled “rate_limit_exceeded”429. You exceeded the per-key limit for this endpoint class. The response carries Retry-After
(seconds) plus X-RateLimit-Limit and X-RateLimit-Remaining. Back off and retry — see
Rate limits.
Billing (402 / 403)
Section titled “Billing (402 / 403)”account_past_due
Section titled “account_past_due”402 · type: billing. The merchant account is past due (frozen). Live API writes are paused until
the balance is settled in the billing portal.
subscription_canceled
Section titled “subscription_canceled”403 · type: billing. The subscription has been canceled. Live API access requires an active
subscription — reactivate it to resume.
billing_not_active
Section titled “billing_not_active”403 · type: billing. There is no active subscription (never activated, or still pending
approval). Complete billing setup to enable live API writes.
Conflict (409)
Section titled “Conflict (409)”invalid_transition
Section titled “invalid_transition”409. A verification session was asked to move to a status that isn’t a legal forward step from its current one (the status machine is forward-only, and terminal states are final). Re-read the session to see its actual status.
not_cancelable
Section titled “not_cancelable”409. You tried to cancel a verification session that is already processing or in a terminal state.
Only created or opened sessions can be canceled.
already_resolved
Section titled “already_resolved”409. This review has already been resolved. Re-read it to see the resulting tier.
not_resolvable
Section titled “not_resolvable”409. This review’s tier isn’t in a resolvable state — only REVIEW/FAIL tiers can be resolved.
Not found (404)
Section titled “Not found (404)”route_not_found
Section titled “route_not_found”404. No route matches the method and path. Check the path against the interactive reference.
session_not_found
Section titled “session_not_found”404. No verification session with that id exists for this key. This also masks a session that belongs to another merchant, or to the other key mode — a test key can never confirm a live session exists, or vice versa.
customer_not_found
Section titled “customer_not_found”404. No customer with that address is associated with your merchant account. Sandbox keys also get this on every customer read, since the sandbox has no live roster.
note_not_found
Section titled “note_not_found”404. No customer note with that id exists.
review_not_found
Section titled “review_not_found”404. No review with that id exists for your merchant wallet (this also covers a malformed
rev_... id, or one that belongs to someone else).
no_ruleset
Section titled “no_ruleset”404. No decision ruleset is available for your merchant (neither a custom ruleset nor the platform fallback resolved).
reverification_not_found
Section titled “reverification_not_found”404. No reverification request with that id exists for your merchant wallet (also covers a
malformed rvr_... id, or a test key polling — reverification requests are created live-only).
endpoint_not_found
Section titled “endpoint_not_found”404. No webhook endpoint with that id exists for this key’s mode, or it has been disabled (a disabled endpoint can’t be test-pinged). Deletion, rotation, and test are only valid on an active endpoint.
event_not_found
Section titled “event_not_found”404. No event with that id exists for this key’s mode.
Invalid request (400 / 405)
Section titled “Invalid request (400 / 405)”method_not_allowed
Section titled “method_not_allowed”405. The path exists but not for this HTTP method.
validation_failed
Section titled “validation_failed”400. The request body or parameters failed the OpenAPI schema (a bad enum value, an over-long
field, a missing required field). The message names the first offending field and what was wrong.
invalid_request
Section titled “invalid_request”400. A required field is missing or malformed on a route without a more specific code — for
example, suspend needs vic_id and reason; a reverification mint needs customer_address and
vic_id. The message says which.
invalid_limit
Section titled “invalid_limit”400. The limit query parameter isn’t an integer between 1 and 100.
theme_id_not_supported
Section titled “theme_id_not_supported”400. theme_id was sent when minting a session. It is reserved and not yet supported — remove it
and use appearance instead.
invalid_created_gte
Section titled “invalid_created_gte”400. The created[gte] filter isn’t a unix timestamp in seconds.
invalid_created_lte
Section titled “invalid_created_lte”400. The created[lte] filter isn’t a unix timestamp in seconds.
invalid_flows
Section titled “invalid_flows”400. flows isn’t a non-empty subset of ["wallet", "phone"].
invalid_ttl
Section titled “invalid_ttl”400. ttl isn’t one of 1h, 24h, 3d, 7d.
invalid_customer_fields
Section titled “invalid_customer_fields”400. The customer object contains keys outside { emailAddress, phoneNumber }.
metadata_too_large
Section titled “metadata_too_large”400. metadata serializes to more than 4096 bytes. Trim it or store the bulk on your side keyed by
the session id.
appearance_too_large
Section titled “appearance_too_large”400. The appearance object exceeds its size cap. Trim it — see the SDK
theming reference.
invalid_appearance
Section titled “invalid_appearance”400. appearance contains a key that isn’t in the allowed set. The message names the offending
key.
invalid_return_url
Section titled “invalid_return_url”400. return_url isn’t a valid http(s) URL.
return_url_not_registered
Section titled “return_url_not_registered”400. In live mode, the return_url’s origin isn’t a registered origin for your merchant. Register
the origin (via your Store Key connection or a webhook endpoint) before using it.
test_field_on_live_mode
Section titled “test_field_on_live_mode”400. test_outcome or test_delay_seconds was sent with a live key. Those fields exist only in
the sandbox — drop them, or use a pb_sk_test_ key.
invalid_test_outcome
Section titled “invalid_test_outcome”400. test_outcome isn’t one of approved, review, failed.
invalid_test_delay_seconds
Section titled “invalid_test_delay_seconds”400. test_delay_seconds isn’t an integer between 0 and 120.
invalid_status
Section titled “invalid_status”400. An internal status-machine guard: a verification session was asked to transition to a value
that isn’t a known session status. You should not see this from normal API use — quote the
request_id if you do.
invalid_updated_since
Section titled “invalid_updated_since”400. The updated_since filter isn’t an ISO 8601 timestamp or unix seconds.
invalid_content
Section titled “invalid_content”400. A customer note’s content isn’t a string between 1 and 5000 characters.
merchant_wallet_required
Section titled “merchant_wallet_required”400. This resource (decisioning or reverification) is keyed by a merchant wallet address, but your key belongs to an email-based merchant with no wallet. These endpoints are unavailable to wallet-less accounts.
invalid_outcome
Section titled “invalid_outcome”400. A review-resolution outcome isn’t pass or fail.
invalid_addons
Section titled “invalid_addons”400. A reverification addons array contains a value outside { bank, phone }.
invalid_url
Section titled “invalid_url”400. A webhook endpoint url isn’t a valid http(s) URL.
invalid_events
Section titled “invalid_events”400. A webhook endpoint’s events isn’t a non-empty subset of the
event catalog.
Server & infrastructure (5xx)
Section titled “Server & infrastructure (5xx)”internal_error
Section titled “internal_error”5xx · type: internal. Something failed on our side. The message is deliberately generic; the
detail is in our logs against this request_id. Retry idempotent reads; quote the request_id in
support.
entitlement_unavailable
Section titled “entitlement_unavailable”503 · type: internal. A billing-entitlement check couldn’t complete, so the request was blocked
rather than allowed (this gate fails closed on live writes). Retry shortly.
vic_client_unavailable
Section titled “vic_client_unavailable”503 · type: internal. The on-chain VIC client needed for a suspend/unsuspend write is momentarily
unavailable. Note: this condition currently surfaces on the wire as
internal_error — 500-class responses are sanitized before they leave the API —
so you won’t see this code in a response today. It is documented here because it identifies the
condition server-side and may surface directly in a future release. Treat any 5xx as retryable with
backoff.
Related
Section titled “Related”- Authentication — the auth and scope errors.
- Rate limits — handling
rate_limit_exceeded. - Pagination —
invalid_limitand cursor handling. - Interactive reference — the per-endpoint request contracts these validate against.