Payment Intents quickstart
Server-side payment lifecycle in 5 steps. Use this path when you need explicit control over auth, capture, void, and refund — for example delayed capture (auth on order, capture on ship), subscriptions, or platform-integrator flows.
Comparing paths first? See Choose your integration. For the deep reference (every field, error code, capability gate, MIT details), see the Payment Intents reference.
Step 0: Get your test keys
Same path as the Checkout quickstart Step 0 — start at vonpay.com/developers, click Activate VORA Sandbox, and grab vp_sk_test_* (secret) and vp_pk_test_* (publishable). The server-side calls below use the secret key.
Step 1: Tokenize a card
Payment Intents charges a vp_pmt_* token, never raw card data. The standard production path pairs Payment Intents with Embedded Fields — buyer's card enters our iframe, you get back a token.
For this quickstart, sandbox keys can auto-mint a mock token without an iframe:
curl -X POST https://checkout.vonpay.com/v1/tokens \
-H "Authorization: Bearer vp_sk_test_xxx" \
-H "Content-Type: application/json" \
-d '{}'
{
"id": "vp_pmt_test_QAqnXEJF_TCum1jg",
"status": "active",
"card": { "brand": "visa", "last4": "4242", "exp_month": 12, "exp_year": 2030 }
}
In production you'd POST { "provider_reference": "<iframe-minted handle>" } to bind your iframe-vault token to a vp_pmt_*.
Step 2: Create a Payment Intent
Use the vp_pmt_* from Step 1 as the payment method. capture_method: "automatic" does auth + capture in one call:
Node
import { VonPayCheckout } from "@vonpay/checkout-node";
const vonpay = new VonPayCheckout(process.env.VON_PAY_SECRET_KEY);
const intent = await vonpay.paymentIntents.create(
{
amount: 1499,
currency: "USD",
captureMethod: "automatic",
paymentMethod: { id: "vp_pmt_test_QAqnXEJF_TCum1jg" },
metadata: { orderId: "ord_42" },
},
{ idempotencyKey: "ord_42_create_attempt_1" }
);
// intent.status: "succeeded" | "requires_action" | "failed"
Python
intent = vonpay.payment_intents.create(
amount=1499,
currency="USD",
capture_method="automatic",
payment_method={"id": "vp_pmt_test_QAqnXEJF_TCum1jg"},
metadata={"order_id": "ord_42"},
idempotency_key="ord_42_create_attempt_1",
)
cURL
curl -X POST https://checkout.vonpay.com/v1/payment_intents \
-H "Authorization: Bearer vp_sk_test_xxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ord_42_create_attempt_1" \
-d '{
"amount": 1499,
"currency": "USD",
"capture_method": "automatic",
"payment_method": { "id": "vp_pmt_test_QAqnXEJF_TCum1jg" }
}'
Use capture_method: "manual" if you want to authorize now and capture later — the intent will stop at authorized and wait for an explicit /capture call.
Step 3: Handle requires_action (3DS challenge)
If the buyer's bank requires Strong Customer Authentication, the intent returns status: "requires_action" with a next_action block:
if (intent.status === "requires_action" && intent.nextAction?.type === "redirect_to_url") {
// Top-level navigation — NOT inside an iframe (banks block this).
res.redirect(intent.nextAction.redirect_to_url.url);
}
The buyer completes the challenge on their bank's page. You learn the final status via webhook (payment_intent.succeeded / payment_intent.failed) — don't trust the buyer's browser. See the reference for full 3DS handling.
Step 4: Capture, void, or refund
For auth-only intents, capture later (empty body captures the full authorized amount):
curl -X POST https://checkout.vonpay.com/v1/payment_intents/vpi_test_abc123/capture \
-H "Authorization: Bearer vp_sk_test_xxx" \
-H "Idempotency-Key: ord_42_capture_attempt_1" \
-d '{}'
Refund (omit amount for full refund):
curl -X POST https://checkout.vonpay.com/v1/refunds \
-H "Authorization: Bearer vp_sk_test_xxx" \
-H "Content-Type: application/json" \
-d '{ "payment_intent": "vpi_test_abc123", "reason": "customer_requested" }'
Void (only valid before capture):
curl -X POST https://checkout.vonpay.com/v1/payment_intents/vpi_test_abc123/void \
-H "Authorization: Bearer vp_sk_test_xxx" \
-H "Idempotency-Key: ord_42_void_attempt_1" \
-d '{}'
Some processors don't support void-after-capture; the reference covers the capability gate so you can branch up front rather than catch the error mid-flow.
Step 5: Go live
Same swap as the Checkout path: vp_sk_test_* → vp_sk_live_*. Direct-charge with payment_method may need a per-processor activation gate on live keys — if your live calls return endpoint_not_implemented, contact your VORA point of contact to enable it for your merchant.
Next steps
- Payment Intents reference — full lifecycle reference, error envelopes, MIT block (recurring + retries), capabilities matrix
- Embedded Fields quickstart — the standard browser-side tokenization pairing
- Webhooks —
payment_intent.*event handling - Error codes — canonical error catalog