Skip to main content

Session Object

A checkout session represents a single payment attempt from creation to completion.

Session ID

Format: vp_cs_{env}_{nanoid}

  • vp_cs_test_k7x9m2n4p3q8r1s5 — sandbox session
  • vp_cs_live_k7x9m2n4p3q8r1s5 — production session

The ID ends in a 16-character random string. It cannot be guessed.

Fields

Core fields

FieldTypeAlways PresentDescription
idstringYesSession ID
statusstringYesCurrent status: pending, processing, succeeded, failed, expired
modestringYesPayment mode (payment)
merchantIdstringYesMerchant account that owns this session
amountintegerYesPayment amount in minor units
currencystringYesISO 4217 currency code (a required 3-letter uppercase code)
countrystringNoISO 3166-1 alpha-2 country code (optional)
descriptionstringNoHuman-readable description of the payment (max 500 characters)
successUrlstringNoRedirect URL on success — echoes the value supplied at creation (null if none)
cancelUrlstringNoRedirect URL on cancel — echoes the value supplied at creation (null if none)
shippingstringYesShipping-address collection mode actually appliednone | auto | required. Not necessarily what you sent: omit the field on create and this is your account setting (none out of the box); send it with a publishable key and a value weaker than your account setting is raised to it. See Asking the buyer for more than a card.
shippingAddressobjectNoBuyer's shipping address (only present when status is succeeded)
buyerPhonestring | nullYesThe phone number the buyer typed on the checkout page — null when none was collected. Don't confuse this with the phone collection mode you set at creation: that mode decides whether the field is shown, and it is returned on the create response, not here.
transactionIdstringNoPayment provider's transaction ID (set on completion)
metadataobjectNoMerchant-provided key-value pairs (passed through to webhooks)
createdAtstringYesISO 8601 creation timestamp
updatedAtstringYesISO 8601 last update timestamp
expiresAtstringYesISO 8601 expiry timestamp
Buyer and reusable tokens

Vaulting a reusable card-on-file token through the embedded charge-and-save flow requires a buyer on the session. With a buyer attached, submit() charges the card and returns a reusable vp_pmt_* token in one step. Guest / no-buyer sessions charge once and vault nothing — submit() resolves with a charge-only result (charged: true along with last4 and brand) and no token. Set the buyer when you create the session.

The same buyer identity also drives reuse: when a returning buyer is on the session, the embed lists that buyer's previously-vaulted cards inside the iframe for one-click payment — only cards saved in a prior completed session appear, and a first-time or guest buyer has none. See buyer identification.

Payment routing (VORA)

Processor selection happens server-side inside Von Payments. The merchant API does not expose which processor was used — neither POST /v1/sessions nor GET /v1/sessions/:id returns processor identifiers. Your integration is identical regardless of which processor fires the charge. See VORA — Payment Routing for context.

Status Lifecycle

pending ──> processing ──> succeeded
└──> failed ──> succeeded (retry converges)

pending ──> expired
processing ──> expired
StatusDescriptionTrigger
pendingSession created, waiting for buyerPOST /v1/sessions
processingBuyer has acted; charge in flightBuyer submits payment
succeededPayment completedPayment processor confirms the capture
failedPayment declined or erroredPayment processor rejects
expiredSession reached its expiry without completingCleanup sweep (see Rules)

Rules

  • A succeeded session cannot become failed. The reverse, however, is allowed: a failed session that the buyer retries successfully converges to succeeded.
  • A session can only be used once — no replays.
  • Expired sessions cannot be re-activated — create a new session.
  • Session TTL defaults to 30 minutes, but is configurable per session via expiresIn (from 5 minutes up to 7 days). expiresAt equals the creation time plus that TTL.
  • A session that passes its expiresAt without completing is moved to expired by a periodic cleanup sweep (not at the exact instant the TTL elapses). Only sessions that have not moved money are expired this way.