Skip to main content

API Key Types

Where keys come from​

Key issuance depends on mode:

  • Test keys (vp_sk_test_*, vp_pk_test_*) come from your business's sandbox. Activate it from Developers and create them there. Asking for test keys on the live business is refused with 403 test_keys_are_sandbox_only.
  • Live keys (vp_sk_live_*, vp_pk_live_*) are created on the live business, never on a sandbox (403 live_keys_not_on_sandbox). They are issued once your merchant application is approved and a payment processor is connected to your account. Both are required, and they are checked in that order:
    • Not approved yet: 403 merchant_not_onboarded (Error Codes).
    • Approved, but nothing connected: 403 live_keys_need_processor (Error Codes).
    • We could not confirm your payment setup: 503 processor_check_unavailable (Error Codes). This one is temporary and is not a problem with your request; retry shortly.

These refusals gate creating a new key. Keys you already hold keep working, and rotating one is never gated, so a leaked key can always be replaced.

Key types at a glance​

KeyPrefixWhere to use itRotation
Test secret keyvp_sk_test_Server-side code, test mode onlyGrace window (default 24h)
Live secret keyvp_sk_live_Server-side code, production onlyGrace window (default 24h)
Test publishable keyvp_pk_test_Browser-exposed client code, test mode onlyGrace window (default 24h)
Live publishable keyvp_pk_live_Browser-exposed client code, production onlyGrace window (default 24h)
Legacy secret keyvp_key_⚠ Older accounts only. Still accepted, and treated as a full secret key — server-side only, never in a browserRotate to a vp_sk_ key
Legacy session secret

Older accounts may hold an ss_test_ / ss_live_ session secret. It is no longer issued and verifies nothing — in particular it is not how you confirm a payment when the buyer is redirected back. Read the outcome from sessions.get and fulfil on the charge.succeeded webhook instead; see Handle the return.

Webhook signing secrets (whsec_*) are separate — see Webhook Signing Secrets.

Secret vs publishable — when to use which​

  • Secret keys (vp_sk_*) can create sessions, retrieve session status, and do everything through the API. Never expose them to a browser or mobile app.

  • Publishable keys (vp_pk_*) are safe to embed in client code. They can initialize the drop-in vora-hosted.js widget and create sessions — POST /v1/sessions is the only merchant-facing endpoint a publishable key can write through, and even there five fields are secret-key only (gateway, storedCredentialUse, captureMethod, setupForFutureUse and the buyer fields): a publishable-key request carrying one is refused with auth_key_type_forbidden. One read-only route also accepts either key type: GET /v1/capabilities. Every other /v1/ merchant route rejects a publishable key with auth_key_type_forbidden (HTTP 403), including retrieving the full session details a secret key sees.

    Session creation is not the only thing a publishable key does. Ten browser-facing /v1/public/* handlers require a publishable key and reject a secret one — so the reach of a publishable key is wider than the merchant surface suggests:

    RouteMethodWhat it does
    /v1/public/sessions/{id}GETRedacted public session view (id, expiry, amount, currency, routing — no PII, no merchant-internal metadata, no provider session id)
    /v1/public/sessions/{id}/embed-tokenGETShort-lived token for the embedded-fields frame
    /v1/public/sessions/{id}/mirror-orderGETMirrored store-order status for this session
    /v1/public/sessions/{id}/chargePOSTCharges the buyer — Embedded Fields charge at submit. 422 merchant_not_configured where your gateway does not support it; 501 endpoint_not_implemented while it is switched off platform-wide or not yet live-enabled for your gateway
    /v1/public/sessions/{id}/completePOSTCompletes the session after payment — the SDK calls it for you
    /v1/public/binder-loadPOSTPer-processor element capability map
    /v1/public/tokensPOSTMints a vp_pmt_* payment-method token from the browser — and on a wallet request (instrument: "wallet") charges the buyer directly
    /v1/public/telemetry/browserPOSTBrowser telemetry ingest
    /v1/public/wallets/apple-sessionPOSTApple Pay merchant validation for standalone wallets, enabled per account
    /v1/public/wallets/google-sessionPOSTGoogle Pay session for standalone wallets, enabled per account

    The session routes are session-bound — each is scoped to one checkout session, and a cross-merchant, mode-mismatched, or unknown session collapses to an opaque 404. That scoping, not the key type, is what limits them. (/v1/public/telemetry/browser takes no session and is rate-limited per IP instead.)

Key type is derived authoritatively from the prefix: vp_pk_ ⇒ publishable, vp_sk_ ⇒ secret. The checkout API enforces key-type restrictions server-side. For example, calling sessions.get() (GET /v1/sessions/:id, the full secret-key view) with a publishable key returns auth_key_type_forbidden (HTTP 403). The SDK surfaces that 403; it does not reject the key at construction time — constructing a client with a publishable key is allowed.

Rotation grace​

When you rotate a secret or publishable key, the old key stays valid for a grace window so you can deploy the new key without downtime. The grace period is caller-configurable — 1h, 24h, or 7d — and defaults to 24h when you don't specify one. The old key keeps working until grace_ends_at, after which it rejects with auth_key_expired.

Rotation timeline (default 24h grace)​

t =State
t0Click Rotate in /dashboard/developers/api-keys. New key is created; old key enters grace.
t0UI shows the raw value of the new key once. Copy it to your secret manager immediately.
t0 → t0+24hBoth keys accepted. Deploy the new key across all your services during this window.
t0+24hOld key rejects with auth_key_expired (HTTP 401). Grace ends.

If you rotate with a 1h or 7d grace, the t0+24h row shifts to t0+1h or t0+7d accordingly.

You cannot re-rotate a key that is already in its grace window — that returns 404 ("not eligible for rotation"); rotate the current primary key instead. A predecessor already in grace stays active until its own grace_ends_at passes; rotating again does not deactivate it early. There is no per-window rotation rate limit (24h is the default grace period, not a cooldown), though each mode has a cap on the number of simultaneously-active keys (fresh + in-grace) — exceeding it returns 409.

Compromise — skip the grace​

If a key is exposed (leaked to a public repo, screenshot, shoulder-surf, etc.), do not initiate a normal rotation. Grace would keep the compromised key working for the duration of the grace window.

Instead, from /dashboard/developers/api-keys:

  1. Click Revoke on the compromised key (not Rotate). It is refused with no grace window.
  2. Create a fresh key.
  3. Move your deployed services to the fresh key.

A revoked key (one with no rotation metadata) rejects with auth_invalid_key. A key that simply ran out its rotation grace rejects with auth_key_expired.

Rotation-badge states (dashboard)​

Each key in /dashboard/developers/api-keys carries a badge: Active (the current primary), Grace: ends in <N>h (previous primary, accepted until grace_ends_at), Revoked (auth_invalid_key from now on) or Expired (grace passed — auth_key_expired). When a service starts failing authentication after a rotation, the badge on the key it holds says which.

Expiry behavior​

API keys do not have a baked-in TTL — they stay Active until rotated or revoked. The only paths to expiry are:

  • Normal rotation → previous key enters its grace window → rejects with auth_key_expired once grace_ends_at passes.
  • Revoke → immediate rejection with auth_invalid_key.
  • Merchant account suspension → all keys for that merchant immediately reject with auth_merchant_inactive (HTTP 401). This is an account-level state (the merchant account is suspended or no longer approved for the mode), separate from per-key rotation/revocation.
  • Revocation by Von Payments — e.g. in response to a breach report. Shows the same Revoked badge.

A freshly-rotated key needs no further activation step.