Skip to main content

Choose your integration

Von Payments has two front-end integration paths — Hosted Checkout and Embedded Fields (which itself renders in two modes: embed and elements). Both paths vault the same vp_pmt_* token and settle through the same server-side Payment Intents engine; they differ only in how much of the checkout UI you build. Pick by how much control you need over the UI and how much PCI handling you want to avoid.

Hosted CheckoutEmbedded Fields
Browser SDKvora-hosted.js (js.vonpay.com/v1/vora-hosted.js) — redirectsvora.js (js.vonpay.com/v1/vora.js) — no redirect
Server SDK@vonpay/checkout-node@vonpay/checkout-node + browser vora.js
You buildA redirect + return handlerA page that hosts our iframe-vault fields — one combined card box (embed), or each element placed individually (elements)
Buyer seescheckout.vonpay.comYour page, our card field(s)
PCI scopeNone (SAQ-A)None (SAQ-A; iframe vault)
Control over UILowHigh → Highest (in elements mode)
Time to integrate~30 min~half a day (embed) to ~1–2 days (elements)
3DSAutomaticYou send the buyer to the bank's page
Submit behaviorBuyer pays on hosted pageTokenize-only or charge-and-save (charges on submit; also vaults a token when a buyer is on the session)
Saved cards (buyer present)Yes (via buyerId)Token reuse; charge-and-save vaults the token on submit
MIT (no buyer)Not applicableToken reuse in Payment Intents
When to pick itSimplest path; brand on checkout page acceptableBrand control matters; your-brand one-page (embed) or fully custom field layout (elements)

elements is not a third path — it's a render mode of Embedded Fields. The composable, place-each-field-yourself option is the elements mode (integrationMode: "elements"), covered under Embedded Fields below. See Render modes: embed vs elements for the full model.

Payment Intents is the engine, not a third path. Both front-end paths produce a vp_pmt_* and charge through POST /v1/payment_intents. You also call it directly — with no buyer-facing redirect — for delayed capture, voids, refunds, MIT, and recurring charges. See The Payment Intents engine below.

vora-hosted.js and vora.js are different scripts

The names are similar enough to mix up. vora-hosted.js is the redirect browser snippet used by the Checkout path. vora.js is the Embedded Fields SDK used by the Embedded Fields path. Both load from the js.vonpay.com/v1/ CDN family and take a publishable key, but they produce different buyer experiences. vora.js always loads from https://js.vonpay.com/v1/vora.js. In a bundler, the @vonpay/vora package loads that script for you and adds TypeScript types; it does not contain the SDK, and @vonpay/vora-js is not on npm.

Vonpay handles processor selection server-side via VORA. Your integration code never imports any processor SDK — the card iframe is mounted by vora.js, which picks the underlying processor adapter (its binder) at session-load time. See the Embedded Fields quickstart for the supported flow.

Sandbox vs. live behavior at a glance​

Both paths work with a sandbox account's test keys, webhooks fire, and no money moves. What a test key reaches is on Test mode.

Checkout (vora-hosted.js)Embedded Fields (vora.js)
Test keys✅ Works end-to-end on a sandbox account. A test key with no test environment behind it (a live merchant account, or a sandbox with no processor) is refused with HTTP 422 sandbox_account_required.✅ Works on a sandbox account whose processor has a supported card-field binder. Refused with sandbox_account_required in the same cases as Checkout.
Live (live keys)✅ Works end-to-end on every gateway.✅ Works on gateways with a supported card-field binder. GET /v1/public/sessions/:id returns the binder details when supported, or HTTP 422 merchant_not_configured when not.
Production strategyUse as-is.Surface merchant_not_configured as a "fall back to hosted" code path, so an integrator can ship without waiting on every merchant's gateway readiness.

When the embedded path returns merchant_not_configured, the 422 response body links directly to Embedded Fields quickstart and Sandbox & Test Mode.

Hosted Checkout​

The fastest path. Your server creates a session, the buyer pays on checkout.vonpay.com, and we redirect them back with a signed status. You write a redirect + a return handler — that's it.

Pick this if:

  • You want the simplest integration that exists
  • A Von-Payments-hosted checkout page is acceptable
  • You don't need delayed capture or auth-only flows

Go to Checkout →

Embedded Fields​

Drop our iframe-vault fields into your own checkout page. The card form stays inside the iframe (PCI-isolated), but you control the page around it — branding, layout, copy.

Submit behavior. Embedded Fields has two submit behaviors (a property of the session you create, not an account setting):

  • Tokenize-only. Submit returns a vp_pmt_* token and moves no money. You charge it later via Payment Intents, or use it in a Session.
  • Charge-and-save. Submit charges the card immediately and, when the session carries a buyer, also vaults a reusable vp_pmt_* in the same step — no separate charge call. A guest/no-buyer session charges once and saves nothing. Because submit already charges, do not also charge the resulting token via Payment Intents — that double-charges the buyer.

The submit result is one flat object. Branch error → chargeStatus → token → charged: requires_action (3-D Secure, nothing charged — redirect the buyer) and pending (await the webhook) come before token (tokenize-only, or charge-and-save with a buyer) and charged: true (charge-and-save guest, no token). The client result is a UX signal — confirm settlement via the webhook before fulfilling. See Tokenization for both flows.

Two render modes: embed and elements​

Embedded Fields renders in one of two modes, set per session via integrationMode (default embed, no account-level lock) — a mode of the same path, not a separate integration:

  • embed (default) — a drop-in monolith: one combined card iframe renders the whole payment surface (card + cardholder + billing address + method picker + saved cards + wallet buttons). You place only email and save-for-future-use.
  • elements — composable: you place card (the combined box or the three discrete card-number / card-expiry / card-cvc fields), email, cardholder, address, payment-method-picker, and standalone wallet buttons individually. Unsupported elements sessions fall back to embed silently — never an error; the echoed integrationMode tells you which surface you got.

See Render modes: embed vs elements for the full model + per-binder capability matrix, and Custom checkout with Elements for the elements-mode walkthrough.

Pick Embedded Fields if:

  • The checkout page brand has to be yours
  • You want a standard your-brand one-page checkout (embed), or place each field individually in your own layout (elements)

Go to Embedded Fields → · Custom layout with elements mode →

The Payment Intents engine​

Both front-end paths above settle through Payment Intents — and you also call it directly, with no buyer-facing redirect, when your server is the source of truth. Drive auth, capture, void, and refund as discrete steps against a vp_pmt_* token.

Call it directly when:

  • You need delayed capture (auth on order, capture on ship)
  • You need a fraud check before capture
  • You're building a platform, subscriptions, or recurring (MIT) flows
  • You need to drive auth, capture, void, and refund as discrete steps

Go to Payment Intents →

Still not sure?​

Need delayed capture, MIT, or recurring? ──────► Payment Intents (engine)
Need to place each field in your own layout? ──► Embedded Fields — elements mode
Need your-brand one-page checkout? ─────────────► Embedded Fields — embed mode
Just want the simplest thing that works? ──────► Hosted Checkout

Two paths often compose: with the tokenize-only Embedded Fields behavior, Embedded Fields tokenizes the card and Payment Intents charges it. That's the standard recipe when you need both full UI control AND server-driven lifecycle (e.g. a SaaS that takes a card today and charges later). This pairing applies only to the tokenize-only behavior — under the charge-and-save behavior the embed already charges on submit, so you must not also charge that token via Payment Intents.

3-D Secure & SCA by path​

3-D Secure is issuer-driven — the bank decides whether to challenge, not your code. What differs is where the challenge renders and how much you handle. Charge at submit runs only in elements mode.

PathWhere the challenge rendersWhat you doControl
Hosted CheckoutOn the hosted checkout.vonpay.com pageNothing — it's automatic.—
Embedded Fields — tokenize-onlyRaised by your server's POST /v1/payment_intents (status: "requires_action"), not by submit()Set return_url on the create call and send the buyer to next_action.redirect_to_url.url; without return_url, a card that needs a challenge is refused.You drive the redirect. See Embedded Fields → 3D Secure.
Embedded Fields — charge at submit
(elements + chargeAtSubmit: true)
The card issuer's hosted challenge page — the buyer leaves your site for itOne branch is required. submit() resolves chargeStatus: "requires_action" + redirectUrl and nothing is charged; send the buyer to redirectUrl. They return to the session's successUrl, the charge settles, and the charge.* webhook is authoritative.Create the session with successUrl. disable3dsModal / challengeTimeout do not apply. See Charge at submit → 3-D Secure.
Payment Intents (called directly)The issuer's hosted page via next_action.redirect_to_urlSend return_url on every buyer-present charge — on a connection that completes the challenge by redirect, a card that needs one is rejected without it (422 provider_request_rejected), not challenged. The payment_intent.* webhook is the outcome.You drive the redirect. See Authentication challenges.

Which cards and amounts produce a 3-D Secure challenge, a decline or a success depends on your account's test path — see Test mode.

Common to both paths​

  • PCI scope. None on your side for either front-end path (Hosted Checkout, Embedded Fields — in embed or elements mode) — card data stays in our iframes (SAQ-A). Calling Payment Intents directly stays PCI-out as long as you don't pass raw card data — use the vp_pmt_* tokens those paths produce.
  • Webhooks. Same signed event surface. ⚠️ Fulfil on charge.* — charge.succeeded for hosted checkout, plus payment_intent.* for intents. session.succeeded / session.failed report a hosted-checkout session's outcome and can be subscribed to, but they carry no saved card or vp_tx_id, so fulfil on charge.succeeded. See Webhook events.
  • AI agents. Both paths are agent-friendly via the same SDKs, CLI, and MCP server. See AI Agents.
  • Test mode. What a test key reaches, and what decides outcomes, is one page: Test mode.