Skip to main content

API Key Types

Self-service vs. gated issuance

Key issuance depends on mode:

  • Test keys (vp_sk_test_*, vp_pk_test_*, ss_test_*) — fully self-service. Start at vonpay.com/developers (or deep-link straight to app.vonpay.com/dashboard/developers if signed in), click Activate VORA Sandbox, and your test keys are issued in seconds — no ops-side approval queue. A sandbox merchant record is seeded automatically and pre-wired for sandbox transactions so you can create and route test sessions immediately.
  • Live keys (vp_sk_live_*, vp_pk_live_*, ss_live_*) — gated behind merchant application approval. You must complete onboarding and have your merchant application approved (KYC + contract) before live-mode keys can be generated. Contact Von Payments to start the merchant onboarding process. Until your merchant account is approved for live payments, requesting live keys returns 403 merchant_not_onboarded with a fix string pointing back to the onboarding flow ("Complete the merchant application and wait for ops approval before creating live keys. Use test keys (mode: 'test') during integration."). A denied account gets a distinct fix message asking you to contact support@vonpay.com. See Error Codes → merchant_not_onboarded.

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)
Session secretss_test_, ss_live_Server-side verification of return redirectsRotated independently

The ss_* prefix is the format Von Payments uses when provisioning the secret. Always use the session secret provided by Von Payments in the dashboard verbatim — do not generate your own. The checkout runtime does not enforce a minimum key length, so a short or predictable secret enables signature forgery. Copy-paste from /dashboard/developers/api-keys and store in a secret manager.

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 accepts publishable keys — this is the only write operation they can perform). They cannot retrieve the full session details that a secret key sees, nor perform any other server-authorized action. They can fetch a redacted public view of a session via GET /v1/public/sessions/:id (id, expiry, amount, currency, routing — no PII, no merchant-internal metadata, no provider session id); that endpoint accepts publishable keys only.

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 (which is set to NOW() plus the requested interval), 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). This soft-deletes the key (is_active = false) so it rejects on the very next request — no grace.
  2. Create a fresh key.
  3. Rotate deployed services to the fresh key.
  4. Von Payments also flags the revoked key internally so downstream audit logs record the revocation.

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)

The /dashboard/developers/api-keys UI shows a badge on each key reflecting its rotation state. Useful when you're debugging why a deploy is still getting authentication errors somewhere:

  • Active — the primary key, created or rotated-into most recently.
  • Grace: ends in <N>h — previous primary, still accepted until grace_ends_at.
  • Revoked — manually revoked via Revoke. Will never accept again (auth_invalid_key).
  • Expired — grace window passed naturally (auth_key_expired).

If a live-mode service suddenly starts failing authentication after a rotation, check the badge on the key that service is configured with. "Expired" means you missed the grace window for at least one deploy.

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.
  • Revokeis_active = false, 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.
  • Manual rotation forced by ops — e.g. response to a breach report. Shows the same Revoked badge.

Key verification reads straight from the database on every request — there is no separate replication cache to wait on. A freshly-rotated key is live as soon as the rotation write commits.