Skip to main content

Security

Authentication​

API requests use Bearer token authentication:

Key Types​

Authorization: Bearer vp_sk_live_xxx

Von Payments issues two kinds of API key you authenticate with and two kinds of signing secret you never send in a request. Older accounts may also hold a fifth, legacy key — see the note below the list:

  • Secret key (vp_sk_test_… / vp_sk_live_…) — server-side only, authenticates every API call. A live key presents your provider's production credentials and moves real money.
  • Publishable key (vp_pk_test_… / vp_pk_live_…) — the browser-side counterpart, safe to ship in a bundle.
  • Session signing secret (ss_…) — older accounts only; it is no longer issued, and nothing in the integration asks you for it. In particular it does not confirm a return redirect — those signatures are produced with a single platform-wide secret, so an ss_* passed to a return verifier fails every time.
  • Webhook signing secret (whsec_…) — verifies the webhooks we send you. Per endpoint, and not your API key. See Webhook signing secrets.

⚠ Older accounts may also hold a vp_key_… key. It predates the current prefixes and is still accepted — as a full secret key. If you find one in a bundle or a config, treat it as live credentials and rotate it to a vp_sk_ key; do not assume it is inert because it is not in the list above.

Prefixes, which key each route accepts, rotation and expiry: API keys. Mode is decided by the key prefix on every request — one account holds both and flips per request; a test key never moves real money (Test mode). The prefix picks the mode, not the host: the same host serves both, and a browser whose apiBaseUrl names a different host than your server gets 401 auth_invalid_key_publishable on every call (troubleshooting). A compromised secret key is revoked, with no grace window, from the dashboard: Compromise — skip the grace.

Key Rotation​

Secret keys can be rotated without downtime. When a key is rotated, the previous key enters a grace window that is caller-configurable — 1h, 24h or 7d, defaulting to 24h — during which both keys authenticate. After the grace window closes, the previous key returns 401 with code: auth_key_expired — distinct from auth_invalid_key so SDKs can detect rotation and refresh instead of failing the payment.

  • A revoked key (no rotation metadata) returns auth_invalid_key; a key deactivated mid-rotation returns auth_key_expired

Rotate keys via /dashboard/developers/api-keys. The UI shows the new plaintext exactly once — store it immediately.

Confirming the return redirect​

The buyer returns to your successUrl with ?session=vp_cs_… whatever the outcome, through their own browser — treat everything on that URL as untrusted, and reaching the page proves nothing. Read the outcome from sessions.get with your secret key and fulfil on the charge.succeeded webhook: Handle the return. Signature checking belongs on webhooks, not on the redirect — a declined payment is signed exactly as validly as an approved one.

PCI Compliance​

Card number, expiry and CVC are entered in a secure iframe hosted by the payment processor and never touch Von Payments' servers or yours, on Hosted Checkout and on Embedded Fields in either mode — your PCI scope stays at SAQ-A.

elements mode puts billing-details fields in YOUR page

The card fields stay in the iframe in both modes, but in elements mode the SDK renders cardholder name, email, the save-card checkbox and (by default) the billing address as ordinary inputs in your own DOM — the cardholder-name input even carries autocomplete="cc-name", so the browser may autofill it from the buyer's saved card. A connection whose capability map declares the address native gets the processor's own address element instead, rendered in its isolated iframe; the capability matrix says which yours declares.

Any other script on that page can read those values. Your SAQ-A eligibility is unchanged, but your page-script hygiene (a tag manager, an analytics vendor, a compromised dependency) is now in scope for buyer identity data. If you cannot vouch for every script on your checkout page, prefer embed mode.

Data Encryption​

DataProtection
Card dataNever stored — entered in processor's iframe
Buyer nameAES-256-GCM encrypted at rest
Buyer emailAES-256-GCM encrypted at rest
API keysSHA-256 hashed in database
Checkout session IDsCryptographically random (vp_cs_<mode>_ + nanoid)

Transport Security​

  • Merchant-supplied URLs (such as successUrl and cancelUrl) must use HTTPS; localhost is exempt at the validation layer so you can test locally
  • Live-mode keys reject localhost/loopback redirect URLs — local redirects are permitted only with test-mode keys
  • HSTS header with 2-year max-age
  • TLS 1.2+ only (per the platform's information security policy)

Security Headers​

The checkout page serves these headers:

HeaderValue
Strict-Transport-Securitymax-age=63072000; includeSubDomains; preload
X-Frame-OptionsDENY
X-Content-Type-Optionsnosniff
Referrer-Policystrict-origin-when-cross-origin
Content-Security-PolicyRestrictive nonce-based policy allowing only required domains

Rate Limiting​

Every endpoint is rate-limited per IP, per API key, or both — buckets, limits and the 429 headers are on Rate Limits.

API Versioning​

The API is versioned by date through the Von-Pay-Version request header — API Versioning.

Webhook Signature Verification​

Webhooks are signed with HMAC-SHA256, keyed with a per-endpoint whsec_* signing secret. The signature ships in the x-vonpay-signature request header with both the timestamp and the HMAC inline:

x-vonpay-signature: t=1714406400,v1=abc123def456...

The exact bytes to sign, the replay window and working verifiers in Node, Python, Go, Ruby and PHP are on Webhook Signature Verification. The platform signs with exactly one secret and sends one v1= entry, so there is no rotation grace window on our side — Rotating a signing secret. Each endpoint's whsec_* is its own secret: not your API key, and not the ss_* session secret.

Reporting Vulnerabilities​

If you discover a security vulnerability, contact security@vonpay.com.