Quickstart
Get a working checkout integration in 5 minutes.
Step 0: Get your test keys
Start at vonpay.com/developers — the developer-first landing page. The Get sandbox keys button deep-links into the developer dashboard, where one click on Activate Vora Sandbox mints all three test credentials in seconds:
vp_sk_test_*— secret API key (server-only)vp_pk_test_*— publishable keyss_test_*— session signing secret (verifies return URL signatures)
OTP sign-in (any email), no merchant application, no ops approval, no shared demo credentials.
Already signed in? Skip the landing page and go straight to app.vonpay.com/dashboard/developers.
The same path works whether you're a merchant going live with Von Payments or a developer/platform integrator evaluating Vora — the Activate Vora Sandbox flow short-circuits business-details collection so you can build without going through KYC. The merchant record is real, but the UX never asks you to be a business. See Platform Integrator Sandbox if you're building a connector, or Going Live for the path to live keys (vp_sk_live_*) after KYC + contract review.
Other prerequisites
- Node.js 20+ (or Python 3.9+ for the Python SDK)
Step 1: Install the SDK
Node.js
npm install @vonpay/checkout-node@0.4.1
Python
pip install vonpay-checkout==0.4.1
CLI
npm install -g @vonpay/checkout-cli@0.3.2
vonpay checkout login
Pinning to an exact version is recommended during the pre-1.0 window.
Step 2: Create a checkout session
Node.js
import { VonPayCheckout } from "@vonpay/checkout-node";
const vonpay = new VonPayCheckout(process.env.VON_PAY_SECRET_KEY);
const session = await vonpay.sessions.create({
amount: 1499, // $14.99 in cents
currency: "USD",
successUrl: "https://mystore.com/order/123/confirm",
cancelUrl: "https://mystore.com/cart",
lineItems: [
{ name: "Premium Widget", quantity: 1, unitAmount: 1499 },
],
buyerName: "Jane Doe",
buyerEmail: "jane@example.com",
});
Python
from vonpay.checkout import VonPayCheckout
vonpay = VonPayCheckout(os.environ["VON_PAY_SECRET_KEY"])
session = vonpay.sessions.create(
amount=1499,
currency="USD",
success_url="https://mystore.com/order/123/confirm",
cancel_url="https://mystore.com/cart",
line_items=[
{"name": "Premium Widget", "quantity": 1, "unit_amount": 1499},
],
buyer_name="Jane Doe",
buyer_email="jane@example.com",
)
CLI
vonpay checkout sessions create --amount 1499 --currency USD
cURL
curl -X POST https://checkout.vonpay.com/v1/sessions \
-H "Authorization: Bearer vp_sk_test_xxx" \
-H "Content-Type: application/json" \
-H "Von-Pay-Version: 2026-04-14" \
-H "Idempotency-Key: order_123_attempt_1" \
-d '{
"amount": 1499,
"currency": "USD",
"successUrl": "https://mystore.com/order/123/confirm",
"lineItems": [{"name": "Premium Widget", "quantity": 1, "unitAmount": 1499}]
}'
Response:
{
"id": "vp_cs_test_k7x9m2n4p3",
"checkoutUrl": "https://checkout.vonpay.com/checkout?session=vp_cs_test_k7x9m2n4p3",
"expiresAt": "2026-03-31T15:30:00.000Z"
}
Step 3: Redirect the buyer
Send the buyer to the checkout URL returned in the session response.
Node.js (Express)
res.redirect(session.checkoutUrl);
Python (Flask)
return redirect(session.checkout_url)
The buyer sees the Von Payments hosted checkout page with billing address, payment methods (cards, Apple Pay, Google Pay, Klarna, etc.), and your order summary. You don't need to handle anything on this page.
Step 4: Handle the webhook
When a payment completes, Von Payments sends a POST to your configured webhook URL. The webhook secret is your merchant API key (vp_sk_*), not a separate secret.
Node.js (Express)
import { VonPayCheckout } from "@vonpay/checkout-node";
const vonpay = new VonPayCheckout(process.env.VON_PAY_SECRET_KEY);
app.post("/webhooks/vonpay", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-vonpay-signature"];
const timestamp = req.headers["x-vonpay-timestamp"];
try {
const event = vonpay.webhooks.constructEvent(
req.body, // raw body
signature, // X-VonPay-Signature header
process.env.VON_PAY_SECRET_KEY, // your API key IS the webhook secret
timestamp // X-VonPay-Timestamp header
);
switch (event.event) {
case "session.succeeded":
console.log(`Payment succeeded: ${event.transactionId}`);
// fulfill the order
break;
case "session.failed":
console.log(`Payment failed: ${event.error}`);
break;
}
res.status(200).json({ received: true });
} catch (err) {
console.error("Webhook verification failed:", err.message);
res.status(400).json({ error: "Invalid signature" });
}
});
Python (Flask)
from vonpay.checkout import VonPayCheckout
vonpay = VonPayCheckout(os.environ["VON_PAY_SECRET_KEY"])
@app.route("/webhooks/vonpay", methods=["POST"])
def webhook():
signature = request.headers.get("X-VonPay-Signature")
timestamp = request.headers.get("X-VonPay-Timestamp")
try:
event = vonpay.webhooks.construct_event(
request.data,
signature,
os.environ["VON_PAY_SECRET_KEY"],
timestamp,
)
if event.event == "session.succeeded":
print(f"Payment succeeded: {event.transaction_id}")
return {"received": True}, 200
except Exception as e:
return {"error": str(e)}, 400
Key details:
- The webhook secret is your API key (
vp_sk_*). There is no separate webhook secret. - The
X-VonPay-Signatureheader contains the HMAC-SHA256 signature. - The
X-VonPay-Timestampheader (ISO 8601) is used for replay protection with a +/-5 minute tolerance.
Step 5: Verify the return redirect
After payment, the buyer is redirected to your successUrl with signed query parameters:
https://mystore.com/order/123/confirm
?session=vp_cs_test_k7x9m2n4p3
&status=succeeded
&amount=1499
¤cy=USD
&transaction_id=abc123
&sig=v2.eyJzaWQiOi...
Always verify the signature server-side. The secret for return signatures is your session secret (VON_PAY_SESSION_SECRET, prefixed ss_test_* or ss_live_*), not your API key.
import { VonPayCheckout } from "@vonpay/checkout-node";
const url = new URL(req.url, `https://${req.headers.host}`);
const isValid = VonPayCheckout.verifyReturnSignature(
{
session: url.searchParams.get("session"),
status: url.searchParams.get("status"),
amount: url.searchParams.get("amount"),
currency: url.searchParams.get("currency"),
transaction_id: url.searchParams.get("transaction_id"),
sig: url.searchParams.get("sig"),
},
process.env.VON_PAY_SESSION_SECRET, // ss_test_* or ss_live_*
{
expectedSuccessUrl: "https://mystore.com/order/123/confirm",
expectedKeyMode: "test", // "live" in production
},
);
if (!isValid) {
throw new Error("Invalid return signature");
}
// Safe to show order confirmation
The SDK auto-detects v1 (legacy) vs v2 (current) signature format. expectedSuccessUrl and expectedKeyMode are required for v2 — see Handle the Return for details.
Step 6: Go live
Replace your test keys with live keys. That's it.
- Swap
vp_sk_test_xxxforvp_sk_live_xxx - Update your session secret from
ss_test_*toss_live_* - Ensure
successUrluses HTTPS - Test with a small real payment
Next steps
If you're integrating for your own checkout
- Webhooks Guide — Event types, payloads, and retry behavior
- Error Handling — Structured errors and retry logic
- Node SDK Reference — Full API surface
- CLI Reference — Command-line tools
- Python SDK — Python integration
- Sample Apps — Clone-and-run reference integrations: Next.js, Express, Flask, pay-by-link
If you're building a platform/CRM connector
- Platforms — Integrate Vora as a payment gateway — full spec for connector authors: API surface, webhook format, idempotency, error catalog, sandbox matrix
- Platform Integrator Sandbox — how the sandbox flow maps to your connector's dev loop
- Webhook Verification — reference HMAC verifier code in Node, Python, Go, Ruby, PHP