Payment flow
A ZenPays payment has three participants: your server, your customer, and us. You create an intent, your customer completes it, and we confirm the outcome and settle the funds.
The steps
-
You create a payment intent.
POST /api/v1/payment-intentswith an amount and currency returns an intent inrequires_payment_methodand a hosted checkout URL. The intent expires after 20 minutes. -
Your customer completes it on the hosted checkout. They choose a payment method from the options available for their currency and country.
-
We route it. When the checkout page loads payment options, we select a provider for that corridor. Which provider, and how it is chosen, is our concern — you never need to name one.
-
The customer confirms. The intent moves to
processingunder a lock, so a double submit cannot create two payments. -
The provider calls back. We record the outcome on the transaction.
-
Funds are credited. Your wallet is credited net of fees before the intent is marked
succeeded— so asucceededintent always means the money reached your balance. -
You receive a webhook.
payment.succeeded(orpayment.failed) is delivered to your endpoint. See Webhooks.
Status transitions
An intent starts at requires_payment_method, moves to processing on
confirmation, and ends at succeeded.
failed intent statusA payment that fails returns the intent to requires_payment_method so the
customer can try a different method. The intent only leaves that state for
succeeded, or for canceled when it expires or is cancelled outright.
Judge a payment by its transaction status, or by the webhook you receive — not by waiting for an intent status that never arrives.
The transaction underneath the intent carries the detail: initiated →
processing → success or failed, plus states for the cases in between such
as waiting_bank and waiting_customer.
What to build against
Treat the webhook as the source of truth, not the redirect. A customer can close the tab before being returned to your site, and the payment still succeeds — the webhook is what tells you.
Poll GET /api/v1/payment-intents/{id} only as a fallback if you have not
received a webhook.