vonpay-checkout
Python SDK for the Von Payments Checkout API. Create hosted checkout sessions, verify webhook signatures, and validate signed return redirects.
Install
pip install vonpay-checkout
Requires: Python 3.9+, httpx 0.27+
Quick start
from vonpay.checkout import VonPayCheckout, VonPayError
client = VonPayCheckout("vp_sk_test_...")
session = client.sessions.create(
amount=1499,
currency="USD",
country="US",
success_url="https://example.com/order/123/confirm",
)
print(session.checkout_url)
# https://checkout.vonpay.com/checkout?session=vp_cs_test_...
Discrete-lifecycle API
The payment_intents, refunds, tokens, and capabilities namespaces give server-side control over payment intents, alongside the existing hosted-checkout sessions flow.
# Create a payment intent (auth + capture)
intent = client.payment_intents.create(
amount=1499,
currency="usd",
capture_method="automatic",
metadata={"order_id": "ord_42"},
idempotency_key="ord_42-charge-1",
)
print(intent.id, intent.status) # "vpi_live_…", "succeeded"
# Auth-only + later capture (fulfillment-on-ship)
auth = client.payment_intents.create(
amount=1499, currency="usd", capture_method="manual", idempotency_key="ord_43-hold-1"
)
client.payment_intents.capture(auth.id, amount_to_capture=1499)
# Refund a captured intent (partial or full)
refund = client.refunds.create(payment_intent=intent.id, amount=500)
# Create a reusable token for save-card / MIT flows
token = client.tokens.create(buyer_id="buyer_42", setup_for_future_use="off_session")
# List a buyer's saved, active cards (newest first; page with next_cursor / has_more)
cards = client.payment_methods.list(buyer_id="buyer_42")
# A signed-in shopper removes their own card — PERMANENT. A repeat returns already_revoked=True.
client.tokens.revoke(cards.data[0].id, buyer_id="buyer_42", initiated_by="buyer")
# Apple Pay on your own checkout domain: register, host the file, verify
domain = client.wallet_domains.create(domain="shop.example.com", wallet_type="apple_pay")
file = client.wallet_domains.retrieve_file(domain.id) # exact bytes, not JSON
# serve file.content at https://shop.example.com/.well-known/apple-developer-merchantid-domain-association
checked = client.wallet_domains.verify(domain.id) # read checked.verification_status
# Read the merchant's processor capability matrix before invoking optional ops
caps = client.capabilities.get()
if caps.supported_operations.partial_refund:
# partial refunds supported — safe to offer partial-refund UI
...
Send idempotency_key on every payment_intents.create. Use one value per charge and send the same value on every retry of that charge. A charge without one still works today, but from 28 October 2026 the API refuses it with 400 idempotency_key_required (nothing is charged), and this SDK emits a one-time FutureWarning until then. 4.0.0 still accepts a charge without one; the key becomes required by this SDK in a later major version.
Migrating from 3.x
4.0.0 changes two behaviours. Nothing in the 3.x API was removed or renamed.
- A live secret key is sent only to Vonpay's API. With a
vp_sk_live_*key,VonPayCheckout(...)raisesValueErrorunlessbase_urlis unset or https oncheckout.vonpay.com/checkout-staging.vonpay.com. Removebase_url, or, for a proxy you run on purpose, passallow_custom_base_url=True(or setVONPAY_ALLOW_CUSTOM_BASE_URL=1). Test and publishable keys are never refused; with an address that is not a Vonpay host or this machine they emit a one-timeCustomBaseUrlWarning, which raises under-W error. - An unknown money outcome says "check first". When a charge, capture, void or refund fails ambiguously and the SDK does not repeat it (
err.retry_withheld is True), the error now hasretryable=Falseandnext_action="reconcile". Read the payment back (payment_intents.retrieve, orrefunds.listfor a refund) and send it again only if it did not happen, with the sameidempotency_key. - Webhook
cardcan be absent fromdataon the charge, refund and saved-card events: read it withevent.data.get("card").
Migrating from 2.x
3.0.0 changes two behaviours. Nothing else in the 2.x API was removed or renamed.
-
payment_intents.void()is retried automatically only when you pass an idempotency key. After a timeout or a500/502/503/504, 2.x retried a void on its own. 3.x does that only when the call carries a key, exactly as it already did forcapture()andrefunds.create(). Without one, the first error is raised withretry_withheld=True. To keep automatic retries:client.payment_intents.void(payment_intent_id, idempotency_key=f"{order_id}-void")
-
A redirect from the API is now its own error,
unexpected_redirect. The API never redirects, and this SDK has never followed one. 3.x raises aVonPayErrorwithcode == "unexpected_redirect",retryable is Falseandnext_action == "check_configuration"(2.x raised a generic error). If you see it, check yourbase_url(the API origin itself,https://checkout.vonpay.com: https, no path), any proxy, and your network. Do not retry it. If you branch exhaustively onerr.next_action, add the new"check_configuration"value.
Features
- Typed session / webhook / error objects — full
CheckoutSession,SessionStatus,WebhookEvent,VonPayErrortypes. - Webhook verification —
webhooks.construct_event(raw_body, signature_header, signing_secret)parses thex-vonpay-signature: t=<unix>,v1=<hex>header, verifies HMAC-SHA256 overf"{t}.{raw_body}"keyed by your per-endpoint signing secret (whsec_…), and enforces the freshness window (≤5 min old / ≤30 sec future). Accepts multiplev1=entries for zero-downtime secret rotation. - Test events — check
event.test_eventFIRST (2.7.0+). It isTrueonly on an event synthesized by "Send test event";livemodedoes not tell you this. Return 2xx and do nothing else — a test event can carry a real session's ids. - Re-read a payment —
payment_intents.retrieve(id)(2.7.0+) returns its stored state. On a 3-D Secure return page use it, with the id you stored at create time, instead of the URL's query params. - Return confirmation —
client.sessions.confirm_return(params, session_secret)verifies the signature and confirms server-side that the payment succeeded, returningReturnOutcome(paid, signature_valid, status, reason). Use this, and branch onpaid. ⛔verify_return_signature()is DEPRECATED and STOPS WORKING on or after 2026-10-13 — the redirect stops carryingsig/status/amount/currency/transaction_idat all, so there will be nothing to verify and it will refuse every return. Migrate before that date. (It was also never usable as merchant-side proof: the signature uses a platform-wide secret no merchant was ever issued.) It proves a message is AUTHENTIC, and a declined payment is signed just as validly, so atruefrom it was never proof of payment either. ⚠️reason == "still_pending"means the charge is in flight (the ordinary 3-D Secure case) — show a neutral "confirming your payment", never a failure. ⚠️paid: truestill does not mean safe to fulfil: record which session IDs you have already fulfilled, and prefer fulfilling from thecharge.succeededwebhook. ⚠️ Notsession.succeeded— that event is emitted internally but is not subscribable: it is absent from the merchant subscription catalog, which accepts an unknown event key, stores nothing and returns success. An endpoint subscribed to it receives nothing, forever, with no error raised at any layer.charge.succeededis the fulfilment event. - Tie the return to YOUR order — any of your paid sessions answers
paid=True, so a buyer could paste the return link of a different, cheaper order they paid for. Pass what your server recorded when it created the session:confirm_return(params, expected_session_id=..., expected_amount=..., expected_currency=...)(the session id, or the amount + currency pair, or both). A mismatch ispaid=Falsewithreason="session_mismatch"or"amount_mismatch", never paid; show a neutral "we couldn't match this payment to your order", not "payment failed". Optional; without it nothing changes. - Where your secret key may go — every request carries your secret key, so
base_urlis checked when the client is created. Leave it unset (https://checkout.vonpay.comserves live and test keys). ⚠️ A live secret key (vp_sk_live_*) is sent only to https oncheckout.vonpay.comorcheckout-staging.vonpay.com; any other address raisesValueErrorat construction, unless you passallow_custom_base_url=Trueor set the environment variableVONPAY_ALLOW_CUSTOM_BASE_URL=1(only for a proxy you run on purpose). A test key may also use this machine (localhost,127.0.0.1,[::1]); any other address is used with a one-timeCustomBaseUrlWarningnaming it (filter it under-W errorwithignore::vonpay.checkout.CustomBaseUrlWarning).key_destination_problem(api_key, base_url, allow_custom=False)gives the same answer without creating a client (None, or the reason). - Auto-retry — exponential backoff on 429 / 5xx with
Retry-Afterheader support. - When a payment's outcome is unknown — if a charge, capture, void or refund gets a
500/502/503/504or a reply that cannot be read, and the SDK does not retry it, the error hasretry_withheld=True,retryable=Falseandnext_action="reconcile", whatever itscode. Money may have moved: read the payment back (payment_intents.retrieve, orrefunds.listfor a refund) before anything else. If it did not happen and you send it again, reuse the sameidempotency_key, never a new one. (RETRY_WITHHELD_HELPholds this advice.) - Plugin identification — building a plugin other merchants install? Pass
app_info={"name": ..., "version": ..., "url": ...}and it is appended to theUser-Agentof every request. - Request ID tracing — every response includes
X-Request-Idfor support tickets.
Documentation
License
MIT
Metadata
Release files for vonpay-checkout 4.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| vonpay_checkout-4.1.0.tar.gz | 236.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| vonpay_checkout-4.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 413.1 kB
Release files / vonpay_checkout-4.1.0.tar.gz
| Download URL | vonpay_checkout-4.1.0.tar.gz |
|---|---|
| Size | 236.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d03e1533f3c8a26ad54a60634e44ac33ca242f39ea86ede1dbbf7819d31918d7
|
|
BLAKE2b-256 checksum How to use checksums |
ec314d42b22d56ded67130cf1b4a84cc196f8f41386ca4e4b895fa89c928cc08
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / vonpay_checkout-4.1.0-py3-none-any.whl
| Download URL | vonpay_checkout-4.1.0-py3-none-any.whl |
|---|---|
| Size | 176.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
31a6f6d140257a782ae8ef7413d127cb5e3a8d1b22af1f83df9e5e94463b613c
|
|
BLAKE2b-256 checksum How to use checksums |
45842567389e65d21309db0f9d0343f354d63561a185edddea07b8cd5baa9b14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency log