Skip to content

Use Cases

This page maps common business needs to a concrete integration path. Each recipe is short on purpose: it tells you which pieces to use and links straight to the reference for the details. If you are brand new, start with the Quick Start, then come back here to find the shape that fits what you are building.

A quick orientation on the three checkout styles, since most recipes pick one:

StyleYou hostWe hostBest for
InlineYour page + our SDKThe payment widgetKeeping customers on your site, no backend required
StandardNothingThe whole payment pageFastest server-to-server integration
InvoiceNothingA shareable, itemised payment link that becomes a receiptBilling a specific customer for a specific amount

Everything below settles the same way and reports back through the same webhooks. You learn one settlement and reconciliation model once, then reuse it across every recipe.

Accept a one-time payment on your site

When: a customer checks out an order and you want them to pay now.

  1. On your server, call initialize with the amount (in kobo), the customer email, a callback_url, and your own reference.
  2. Redirect the customer to the returned checkout_url (Standard Checkout).
  3. When they finish, we redirect them back to your callback_url with a status and your merchant_reference.
  4. Confirm from your server with verify before you fulfil. The callback alone is not proof of payment.
  5. Fulfil once, keyed on the reference, when charge.success arrives (or verify returns completed).

Prefer to keep the customer on your own page? Use Inline Checkout instead: the flow is the same, but the widget renders in your page.

Accept payments without a backend

When: you have a static site or a frontend-only app and no server to hold a secret key.

Use Inline Checkout with your public key (pk_*). The SDK calls initialize directly from the browser, and you lock the key to your domains with domain whitelisting. Never ship a secret key to the browser. Because you have no server to receive webhooks, reconcile by having your backend (even a serverless function) call verify, or add a webhook endpoint when you are ready.

Send a payable invoice

When: you are billing a known customer for a known amount, and you want a link you can email or paste into a chat.

  1. Create the invoice with line items, optional tax, and a due date (Invoice Checkout).
  2. Share the returned payment link. The hosted page collects the payment and becomes a receipt once paid.
  3. Fulfil on the invoice.paid webhook. Partial payments (if enabled) fire invoice.payment_received with is_partial and is_fully_paid flags, and now carry the invoice's line_items and metadata so you can reconcile without a follow-up fetch.

Collect a balance settled outside ZevPay

When: part of an invoice was paid somewhere we cannot see (cash, a transfer straight to your own bank, or platform credit), and you need to collect the rest online.

An invoice only ever records money that reached you through us, so a part-settled invoice cannot represent the remainder. The same secret key drives standard checkout, so:

  1. Cancel the invoice so its old full-amount link stops working.
  2. Open a Standard Checkout session for exactly the outstanding amount.
  3. Reconcile the charge.success back to your invoice using merchant_reference and metadata.

This is the exact pattern our own products use. See the full walkthrough in Collecting a balance settled outside ZevPay.

Bill on a schedule

When: subscriptions, memberships, or any recurring charge.

We do not store cards for off-session charging, so recurring billing is customer-initiated each cycle:

  1. At the start of each cycle, create a fresh invoice (or session) for that period, with a reference unique to the cycle, for example SUB-{customer}-{yyyy-mm}.
  2. Email the invoice link, or if the customer is on your site, redirect them through checkout.
  3. Advance the subscription when invoice.paid (or charge.success) arrives for that cycle's reference.

A per-cycle reference keeps each period idempotent: retrying the same cycle never creates a second charge.

Reconcile every payment reliably

When: always. This is the backbone under every recipe above.

  • Webhooks are the source of truth. Fulfil on charge.success / invoice.paid, not on the browser redirect.
  • Verify signatures on every webhook against the raw request body, see Verifying Signatures.
  • Be idempotent. Key your fulfilment on the reference. We retry failed deliveries with backoff, so your endpoint will occasionally see the same event twice.
  • Confirm server-side with verify before fulfilling if you are acting on a redirect, and as a fallback if a webhook is delayed.
  • Every response is wrapped in { "success": true, "data": {...} }. Read your fields off data.

Map payments back to your orders

When: you need each payment to point at one of your records.

  • Set your own reference (your order id) on initialize or the invoice. We echo it back as merchant_reference in the webhook and on the callback redirect (on success, cancelled, and expired).
  • Attach anything else you need in metadata. We return it verbatim in the webhook, in verify, and on the transaction in your dashboard.

Between merchant_reference and metadata, you never have to store our identifiers to find your way back to an order.

Testing safely against live

We do not offer a full sandbox yet. Most integrations are built against production, so treat testing as a first-class part of your rollout:

  • Use test keys (sk_test_ / pk_test_) where available. They hit the same endpoints and exercise the same code paths as live keys.
  • Start with the smallest real amount on live keys for a true end-to-end check, then refund out of band.
  • Build reconciliation before you go live. A working webhook handler with signature verification and idempotency is what makes a first real payment safe.
  • Never fulfil on the redirect alone. Always confirm with a webhook or verify.
  • Roll out behind a flag so you can enable live checkout for a small cohort first.

Security checklist

A short list worth revisiting before launch:

  • Secret keys (sk_*) live only on your server. Public keys (pk_*) are the only keys that belong in a browser, and only with domain whitelisting.
  • Verify every webhook signature against the raw bytes.
  • Treat callback query params as untrusted hints, never as proof of payment.
  • Store the reference you care about at create time so a delayed or replayed event still maps home.

ZevPay Checkout Developer Documentation