Skip to main content

Embedded Fields — embedded payment fields

Drop Embedded Fields into your checkout and your buyer's card information flows directly to the gateway — never touching your server, never landing in your DOM. The card iframe sits inside your form: you have full branding control of your page — everything outside the iframe — and theme-level control inside it (font + color) to match your look. The card data reflects straight through to the processor; we keep you out of PCI scope. In the default embed mode the card is one combined box — number, expiry, and CVC together, with font + color theming only inside; in elements mode you can keep that combined box or split it into the three discrete card-number / card-expiry / card-cvc fields. For control over where the card and the other input fields (email, cardholder, billing address) sit on your page, mount them as discrete Elements.

Two render modes: embed vs elements

Embedded Fields renders in one of two modes, set per session via integrationMode (default embed, no account-wide setting):

  • embed (default) — one combined card box renders the whole payment surface (card + cardholder, billing address, eligible Apple Pay / Google Pay, and a returning buyer's saved cards). You place only email and save-for-future-use.
  • elements — you place the card, email, cardholder, address, and other pieces as discrete elements, where your account supports it; the card can stay the combined box or split into the three discrete card-number / card-expiry / card-cvc fields. Unsupported elements sessions fall back to embed silently (never an error).

Render modes: embed vs elements is the full model — capability matrix, fallback, what each mode means. Build a custom checkout covers setting integrationMode and branching on the echoed value.

This is the embedded path (either mode); the alternative is hosted checkout, where the buyer redirects to checkout.vonpay.com. Hosted is fastest to integrate; Embedded Fields keeps buyers on your domain with full control over the page.

Pages in this section

  • Quickstart — end-to-end card-only integration in ~10 minutes
  • Build a custom checkout — opt a session into discrete elements rendering with integrationMode, plus the fallback-to-embed behavior
  • Customize the look & feel — interactive playground, three reference themes, the style allowlist, and what's stylable vs not
  • Render modes: embed vs elements — the one canonical explainer for the two render modes (embed monolith vs composable elements), the per-binder capability matrix, and the silent fallback
  • Element reference — Card, Email, Save-for-future-use, discrete card fields; Apple Pay & Google Pay render automatically inside the card mount when the buyer's device and your domain are eligible. Returning buyers' saved cards already appear inside the embed when you set a buyer on the session; the discrete saved-methods element (elements mode) is not usable yet.
  • Using React<VoraProvider>, <CardField>, useVora() patterns + the imperative elements API
  • Tokenization & charge-and-save — the two submit flows: tokenize-only (charge later via Payment Intents) and charge-and-save (charges on submit, optionally vaults a reusable method); the { charged: true } result, buyer-vs-guest split, and confirm-via-webhook rule
  • Error handlingVoraMirrorError codes and recovery
  • 3D Secure — modal harmonization, disable3dsModal opt-out, confirmPaymentIntent + handleAction flows, test cards

Working sample

samples/frame-react in the SDK repo is the canonical end-to-end reference — Express server stub for /api/create-session plus a React app using @vonpay/vora-react. Clone, fill in .env, pnpm dev.

Server-side reference

The server-side payment lifecycle (/v1/payment_intents, capture, refund, void, MIT, webhooks) is shared with the hosted-checkout flow.

The same submit() either tokenizes or charges — that's a property of the session you created, not an account setting, and you choose it per session.

  • Tokenize-only: create a no-charge (setup) session. submit() returns a vp_pmt_* token and charges nothing. You charge it server-side later with Payment Intents.
  • Charge-and-save: create a payment session (with an amount). submit() charges the card on submit and, when a buyer is attached to the session, also vaults a reusable vp_pmt_* in the same step. Do not call /v1/payment_intents for that session — it would double-charge. See Charge-and-save.

⚠️ Read the result, not your account config. The submit result is a discriminated union — branch errortokencharged:

  • { token: "vp_pmt_..." } on a tokenize-only session is an uncharged token to charge later; on a charge-and-save session it's already charged and reusable.
  • { charged: true } (no token) is a guest charge-and-save — charged once, saved nothing.
  • { error } means nothing was charged.

Because the same token shape means "charge later" on a setup session and "already charged" on a payment session, branch on which session you created — but that's your own per-session choice, not an account mode. Either way the client result is only a UX signal — confirm settlement via the webhook before fulfilling (never mark the order failed on a client error, and never resubmit blindly — see Reconciliation for the duplicate-safe pattern). See Charge-and-save for the full result contract.