Skip to main content

Python SDK

Typed Python client for the Von Payments Checkout API, published as vonpay-checkout on PyPI.

Requirements: Python 3.9+, httpx

Install

pip install vonpay-checkout

Pinning to an exact version is recommended during the pre-1.0 window — minor bumps may add options or change defaults.

Initialize

from vonpay.checkout import VonPayCheckout, VonPayError

client = VonPayCheckout("vp_sk_test_...", api_version="2026-04-14")

The api_version parameter pins the API version for all requests made by this client instance. See API Versioning for details.

Sessions

Create a session

session = client.sessions.create(
amount=1499,
currency="USD",
country="US",
)

print(session.id) # "vp_cs_test_abc123"
print(session.checkout_url) # "https://checkout.vonpay.com/checkout?session=..."

Returns a CheckoutSession object.

Get a session

status = client.sessions.get("vp_cs_test_abc123")

print(status.status) # "succeeded"
print(status.amount) # 1499

Returns a SessionStatus object. Requires a secret key.

Validate (dry run)

result = client.sessions.validate(
amount=1499,
currency="USD",
)
# Validates parameters without creating a session

Webhooks

Verify signature

Verify the HMAC-SHA256 signature on an incoming webhook request. The webhook secret is per-endpoint (whsec_*), minted when you register the endpoint at /dashboard/developers/webhooks.

is_valid = client.webhooks.verify_signature(
payload=request_body,
signature_header=request.headers["x-vonpay-signature"],
secret=os.environ["VON_PAY_WEBHOOK_SECRET"], # whsec_*
)

Construct event

Parse and verify a webhook payload into a typed event object. Enforces the asymmetric replay window (5 min past / 30 sec future).

event = client.webhooks.construct_event(
payload=request_body,
signature_header=request.headers["x-vonpay-signature"],
secret=os.environ["VON_PAY_WEBHOOK_SECRET"], # whsec_*
)

print(event.type) # "charge.succeeded"
print(event.data["transaction_id"]) # "vp_txn_9f2nd..."

Webhook management

Read-only access to your registered webhook endpoints and stored event records. These methods all require a secret key (vp_sk_*) — publishable keys are rejected with 403. The wire format is camelCase end-to-end and parsed into typed dataclasses.

List webhook subscriptions

subs = client.webhook_subscriptions.list(
limit=20, # optional
starting_after="wh_sub_abc123", # optional cursor
)

for sub in subs.data:
print(sub.id, sub.url, sub.status)

print(subs.has_more) # True if more pages remain

Results are newest-first. To page, pass the last item's id as starting_after. A cursor that doesn't reference a subscription owned by your merchant raises a 400 validation_error (pagination is not silently restarted from the top).

Returns a WebhookSubscriptionsList object with object, data (a list of WebhookSubscription), has_more, and url. Requires a secret key.

Retrieve a webhook subscription

sub = client.webhook_subscriptions.retrieve("wh_sub_abc123")

print(sub.url) # the registered endpoint URL
print(sub.enabled_events) # ["charge.succeeded", ...]
print(sub.status) # "active" | "paused" | "disabled"

Returns a WebhookSubscription object. A cross-merchant or soft-deleted id returns 404 (opaque — never 403). The signing secret is never present on a read response. Requires a secret key.

Retrieve a stored webhook event

record = client.webhook_events.retrieve("evt_abc123")

print(record.type) # "charge.succeeded"
print(record.processed) # True | False
print(record.retry_count) # int

Returns a WebhookEventRecord — the durable, queryable record of a stored event (distinct from the signed payload that webhooks.construct_event parses). Use it from your own code, e.g. an admin tool, retry trigger, or audit dashboard. Requires a secret key.

Return URL Verification

Verify the HMAC signature on the redirect back from checkout. This is a static method — no client instance needed. Auto-detects v1 (legacy) and v2 (current) signature formats.

params = {
"session": request.args["session"],
"status": request.args["status"],
"amount": request.args["amount"],
"currency": request.args["currency"],
"transaction_id": request.args["transaction_id"],
"sig": request.args["sig"],
}

is_valid = VonPayCheckout.verify_return_signature(
params=params,
secret=os.environ["VON_PAY_SESSION_SECRET"], # ss_test_* or ss_live_*
expected_success_url="https://mystore.com/order/123/confirm",
expected_key_mode="live", # "live" or "test"
max_age_seconds=600, # optional, default 600
)

The secret is the session secret (ss_* prefix), not the API key.

Options (v2 signatures)

expected_success_url and expected_key_mode are required when the sig starts with v2.. For v1 signatures they are ignored.

OptionRequired for v2?DefaultPurpose
expected_success_urlYesThe success_url you passed to sessions.create. Normalised (trailing slash stripped, query sorted, fragment dropped).
expected_key_modeYes"test" or "live". Prevents test-mode sigs from being accepted as live.
max_age_secondsNo600Maximum age of the signature in seconds.

See Handle the Return for a full walkthrough of the v2 format.

Health Check

health = client.health()

print(health.status) # "ok" | "healthy" | "degraded"
print(health.latency_ms) # float — measured dependency latency (ms)
print(health.version) # server build/version string

Returns a HealthStatus dataclass with status, latency_ms, and version.

Error Handling

All API errors raise VonPayError with structured fields for programmatic handling.

from vonpay.checkout import VonPayCheckout, VonPayError

try:
session = client.sessions.create(amount=-1, currency="USD")
except VonPayError as e:
print(e.status) # 400
print(e.code) # "validation_invalid_amount"
print(e.fix) # "Amount must be a positive integer in minor units (cents). 1499 = $14.99"
print(e.docs) # "https://docs.vonpay.com/integration/create-session#required-fields"

Error reporting

The SDK accepts an optional error_reporter callback so integrators can pipe SDK failures into their own observability stack (Sentry, Datadog, custom logger). Your reporter is invoked synchronously, fire-and-forget; if it raises, the SDK swallows it (with a logging.warning on the vonpay.checkout logger) and continues.

When it fires

  • API request failures: non-retryable 4xx, retry-exhaustion on 5xx, network/timeout errors after retry exhaustion
  • webhooks.construct_event / construct_event_v2 verification failures (signature mismatch, stale timestamp, malformed v2 header)

It does not fire on:

  • verify_signature / verify_return_signature — these return bool, never raise
  • The constructor's invalid-key-prefix ValueError — that's a dev-time error before the reporter is wired

Callback shape

from vonpay.checkout import ErrorReporter, ErrorReporterContext, VonPayError

def reporter(err: Exception, ctx: ErrorReporterContext) -> None:
# err is VonPayError or another Exception subclass
# ctx fields:
# method: str — "sessions.create" / "webhooks.construct_event" / etc.
# sdk_version: str
# url: str | None — origin + path, no query string (no PII via params)
# status: int | None — HTTP status if from API response
# request_id: str | None — X-Request-Id for correlation
# code: str | None — server error code
# attempt: int | None — 0-indexed retry attempt
...

Sentry example

import sentry_sdk
from vonpay.checkout import VonPayCheckout

def report_to_sentry(err, ctx):
sentry_sdk.capture_exception(
err,
tags={"sdk": "vonpay-python", "method": ctx.method, "code": ctx.code},
contexts={"vonpay": ctx.__dict__},
)

client = VonPayCheckout(
api_key=os.environ["VON_PAY_SECRET_KEY"],
error_reporter=report_to_sentry,
)

Logging example

import logging
from vonpay.checkout import VonPayCheckout

log = logging.getLogger("myapp")

client = VonPayCheckout(
api_key=os.environ["VON_PAY_SECRET_KEY"],
error_reporter=lambda err, ctx: log.error(
"vonpay sdk error", extra={"err": str(err), "ctx": ctx.__dict__}
),
)

error_reporter is opt-in and additive — if you don't configure it, errors still propagate via raise and nothing else changes.


Auto-Retry

The SDK automatically retries on 429 (rate limited) and 5xx (server error) responses using exponential backoff. Default is 2 retries; configure with the max_retries constructor argument.


Sample app

Clone-and-run reference integration using this SDK lives in Von-Payments/vonpay-samples:

  • checkout-flask — Flask hosted checkout with signed return verification + webhook handler

Ships with .env.example, a per-sample README, and pinned to a known-working SDK version.