API Reference
The complete Von Payments Checkout API is documented in OpenAPI 3.1 format.
OpenAPI Spec
openapi.yaml — import into Postman, Insomnia, Redocly, or any OpenAPI tool.
Three front-end integration paths
VORA provides three front-end integration paths. All vault a vp_pmt_* payment method and settle through Payment Intents — the server-side engine that handles authorization, capture, refunds, and voids. Pick the path that fits your integration:
- Hosted Checkout (Sessions) —
POST /v1/sessionsreturns a checkout URL. You redirect the buyer to it; Von Payments hosts the card form, handles 3DS, and redirects back to yoursuccessUrl/cancelUrl. Simplest path. - Embedded Fields — browser SDK (
@vonpay/vora-js) that mounts card / email / address / cardholder elements directly on your page. Submit behavior depends on how the session is configured: under tokenize-only behavior, submit returns avp_pmt_*token your server charges via Payment Intents; under charge-and-save behavior, submit charges and (with a buyer on the session) vaults a reusablevp_pmt_*in one step, while guest sessions charge once and return no token. On charge-and-save you must not also callPOST /v1/payment_intentsfor that session — doing so double-charges. Uses the publishable-key/v1/public/*endpoints from the browser. - Elements (custom) — same
@vonpay/vora-jsSDK withintegrationMode:"elements"onPOST /v1/sessions. Discrete card fields you position and style on your page, plus optional standalone Apple Pay / Google Pay buttons. Highest UI control; tokenize tovp_pmt_*and charge via Payment Intents.
Payment Intents (server-side engine) — POST /v1/payment_intents creates an intent your server controls directly for authorization → capture → refund → void. All three front-end paths vault a vp_pmt_* and settle through Payment Intents. Best for delayed-capture flows, fraud-check-before-capture, subscriptions, or direct server-driven transactions where no buyer redirect is needed. See the Payment Intents guide.
See Choose your integration for the side-by-side comparison.
Endpoints Summary
Get session status
GET /v1/sessions/{id} returns the full status of a previously-created session. Requires a secret key (vp_sk_*); publishable keys are rejected with auth_key_type_forbidden. See Session Object for the response shape.
Session statuses
A checkout session has one of five statuses: pending, processing, succeeded, failed, or expired. The normal flow is pending → processing → succeeded (or → failed / → expired); a session may also move directly pending → succeeded/failed/expired. Not all transitions are one-way: a processing session can revert to pending, and a failed session can later converge to succeeded on a successful retry (success takes precedence). Only succeeded and expired are terminal. See Session Object — Status Lifecycle.
Payment intent statuses
Payment intents progress through a discrete lifecycle of six statuses: requires_action → authorized → captured → succeeded (or voided / failed). On the manual-capture path, authorized → captured → succeeded runs as three discrete steps; on the automatic-capture path, an authorized intent can move straight to succeeded when settlement is synchronous. See the Payment Intents guide for the full state machine, transition rules, and error envelope.
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /v1/sessions | Publishable or Secret | Create a checkout session (Hosted Checkout) — the only endpoint publishable keys can call |
POST | /v1/sessions?dry_run=true | Publishable or Secret | Validate params without creating a session |
GET | /v1/sessions/{id} | Secret | Get session status |
POST | /v1/payment_intents | Secret | Create a payment intent (auth or auth+capture) — see guide |
POST | /v1/payment_intents/{id}/capture | Secret | Capture an authorized intent (full or partial via amount_to_capture) |
POST | /v1/payment_intents/{id}/void | Secret | Void an authorized intent (before capture) |
POST | /v1/refunds | Secret | Refund a succeeded payment intent (full or partial via amount) |
POST | /v1/tokens | Secret | Mint a vp_pmt_* payment-method token from a provider vault reference (provider_reference) |
GET | /v1/capabilities | Publishable or Secret | Per-merchant capability matrix (supported_operations, settlement_currencies, rate_limits) |
GET | /v1/public/sessions/{id} | Publishable | Browser-safe session lookup — used by Embedded Fields SDK |
POST | /v1/public/binder-load | Publishable | Per-processor element capability map (Embedded Fields) |
POST | /v1/public/tokens | Publishable | Browser-side vp_pmt_* minting (Embedded Fields) |
GET | /api/health | None | Health check (add ?deep=true for deep variant) |
Endpoints marked "internal" are called by the hosted checkout page, not by merchants. Inbound provider-webhook endpoints exist server-side under /api/webhooks/... for processor-to-platform delivery; they are not part of the merchant API surface and integrators never call them.
Authentication
Merchant-facing endpoints use Bearer token auth:
Authorization: Bearer vp_sk_live_xxx
Test keys use the vp_sk_test_ prefix. Live keys use vp_sk_live_.
Most endpoints require a secret key (vp_sk_*). The exceptions are session creation (POST /v1/sessions, including its dry_run variant) and GET /v1/capabilities, which accept either key type, and the /v1/public/* endpoints, which require a publishable key (vp_pk_*). Publishable keys can only create sessions and call the public browser endpoints; they are rejected on secret-only routes with auth_key_type_forbidden (HTTP 403).
Request Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer API key. The accepted key type depends on the endpoint — secret (vp_sk_*) for most routes, publishable (vp_pk_*) for the /v1/public/* endpoints, and either type for session creation and GET /v1/capabilities. |
Content-Type | Conditional | application/json on the browser/public POST endpoints (/v1/public/sessions/{id}/confirm, /v1/public/tokens), which reject a missing or non-JSON type with HTTP 415 unsupported_media_type. The authenticated REST POST endpoints (/v1/sessions, /v1/payment_intents, /v1/refunds, /v1/tokens) parse the JSON body without a Content-Type check, but sending application/json is recommended for all POST requests. |
Von-Pay-Version | No | API version date string (e.g. 2026-04-14). If omitted, the request uses the current API version. Pin this header to avoid breaking changes when the API evolves. |
Idempotency-Key | No | Unique key to prevent duplicate operations. If you retry a request with the same key, the original response is returned instead of creating a duplicate. Recommended for all POST requests in production. Max 255 printable-ASCII characters. See Idempotency below for retention. |
Response Headers
Every response includes:
| Header | Description |
|---|---|
X-Request-Id | Unique request ID for debugging |
The three rate-limit headers X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset are returned on every rate-limited response — both successful responses and 429 responses. Retry-After is returned only on 429 responses. See Rate Limits.
Idempotency
Idempotency-Key is enforced per-resource: a key is unique to (merchant_id, idempotency_key) on the resource it created (session, payment intent, refund). A replayed key with a matching request body returns the original response. A replayed key with a different request body returns HTTP 422 idempotency_replay_incompatible — the SDK surfaces this loudly so a buggy retry that changed amount, cart, or redirect URLs cannot silently inherit a prior resource.
Retention. Idempotency keys are bound to the row they created, not to a separate cache with a fixed TTL. A replayed key returns the same resource for as long as the row is retained on our side — effectively the lifetime of the resource record. Use unique keys per attempt (e.g. order_123_attempt_1, order_123_attempt_2) rather than reusing a key across attempts that could legitimately differ.
Format. Max 255 characters, printable ASCII only (codepoints 0x20–0x7E). Whitespace-only keys are treated as no key.
Errors
session_already_completed is returned as HTTP 409 Conflict, distinct from session_expired's HTTP 410 Gone. The 409 is not returned by POST /v1/sessions (the create endpoint); it is returned by the public completion and read endpoints — GET /v1/public/sessions/{id}, POST /v1/public/tokens, and POST /v1/public/sessions/{id}/confirm — when a duplicate or late completion lands on a session that has already reached succeeded. Branch on code: never create a new session for a 409 (the buyer already paid — that would re-charge), whereas a 410 means the session TTL elapsed and you may create a fresh one.
Rate Limits
Full bucket list and handling rules: Rate Limits.