Skip to main content

Rate Limits

Von Payments enforces rate limits via sliding-window counters. Some buckets are counted per-IP and some per API key — the table says which for each. Two routes are metered on both axes at once (session create, and the public session read), so a request can be refused by either.

Buckets

BucketEndpoint(s)Limit
sessionsPOST /v1/sessions, POST /api/sessions10 / 60s per IP
sessionsPerKeyPOST /v1/sessions (per-API-key axis)30 / 60s per key
paymentOpsPOST /v1/payment_intents (+ /{id} sub-routes: retrieve, capture, void), POST /v1/refunds, POST /v1/tokens, POST /v1/public/tokens, /v1/buyers + /v1/buyers/{id}100 / 60s per key
sessionReadGET /v1/sessions/:id, GET /v1/capabilities, GET /api/checkout/session30 / 60s per IP
publicSessionReadGET /v1/public/sessions/:id, POST /v1/public/binder-load1000 / 60s per key
publicSessionReadPerIpthe same two routes (per-IP axis)80 / 60s per IP
publicWebhookReadGET /v1/webhook_subscriptions + /{id}, GET /v1/webhook_events/{id}100 / 60s per key
webhook_subscription_writesPOST / PATCH / DELETE /v1/webhook_subscriptions (+ sub-routes)30 / 60s per key
webhookListenSseConnectionsGET /v1/webhook_listen30 / 60s per key
sdkTelemetryPOST /v1/sdk-telemetry30 / 60s per key
browserTelemetryPOST /v1/public/telemetry/browser30 / 60s per IP
checkoutInitPOST /api/checkout/init, POST /api/checkout/complete20 / 60s per IP
webhooksPOST /api/webhooks/* (provider inbound)100 / 60s per IP
clientErrorPOST /api/checkout/client-error, POST /api/csp-report10 / 60s per IP
adminPOST /api/admin/*, POST /api/merchant-accounts, /api/cron/*5 / 60s per IP
healthDeepGET /api/health?deep=true5 / 60s per IP

Shallow GET /api/health (no deep param) is intentionally unmetered — it's what uptime monitors hit.

A session-create request can be rate-limited on either the per-IP sessions bucket or the per-key sessionsPerKey bucket. The per-IP rejection emits rate_limit_exceeded; the per-key rejection emits rate_limit_exceeded_per_key so SDKs can tell them apart and react differently.

The public session read is metered the same way, and the two axes are far apart: 1000/min against your publishable key, but only 80/min from a single IP. The per-key ceiling is generous because a publishable key is shared by every buyer on your site; the per-IP one is what a single browser — or a load test running from one machine — will hit first. If you are polling session state from the browser, that 80 is the number that matters.

POST /v1/public/binder-load shares BOTH of those buckets, not just the per-key one. It routes to the same limiter as the session read, and the per-IP axis is applied to that limiter rather than to the individual route — so binder-load calls and session reads from one browser draw down the same 80/min allowance. Budget them together.

Response headers

X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset are emitted on both successful responses and 429s — the proxy sets them when it admits a request and when it rejects one. Retry-After is emitted on 429 responses only.

HeaderWhenDescription
X-RateLimit-Limitsuccess + 429Maximum requests allowed in the current window
X-RateLimit-Remainingsuccess + 429Requests remaining in the current window (0 on a 429)
X-RateLimit-Resetsuccess + 429Unix epoch seconds when the window resets
Retry-After429 onlySeconds to wait before retrying

Handling 429

{
"error": "Too many requests",
"code": "rate_limit_exceeded",
"fix": "Too many requests — wait and retry (see Retry-After header)",
"docs": "https://docs.vonpay.com/reference/api#rate-limits"
}

The error envelope is flat (not nested). The example above shows the fields you'll branch on (error, code, fix, docs); every error response also carries a selfHeal object — see Error Codes for the full envelope.

SDK auto-retry

The Node and Python SDKs automatically retry on 429 and 5xx responses with exponential backoff:

  • The SDK reads Retry-After when present
  • Retry delay capped at 60 seconds
  • Default maxRetries is 2 — configurable via the constructor

Hitting the per-key ceiling

If you legitimately need to exceed 30 session creates/minute per API key (e.g. high-volume batch fulfillment), contact support. The per-key limit is platform-protective, not commercial — we can raise it for real integrations.