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.
| Option | Required for v2? | Default | Purpose |
|---|---|---|---|
expected_success_url | Yes | — | The success_url you passed to sessions.create. Normalised (trailing slash stripped, query sorted, fragment dropped). |
expected_key_mode | Yes | — | "test" or "live". Prevents test-mode sigs from being accepted as live. |
max_age_seconds | No | 600 | Maximum 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_v2verification failures (signature mismatch, stale timestamp, malformed v2 header)
It does not fire on:
verify_signature/verify_return_signature— these returnbool, 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.