Building with AI agents
Building with an AI coding agent (Claude, ChatGPT, Cursor, Copilot, v0, Lovable, Bolt and the like)? This page gives it what it needs to integrate ZevPay Checkout correctly the first time.
Give your agent the docs
Start your agent with this link:
https://docs.zevpaycheckout.com/llms.txtIt is a short index of every page, with the facts agents most often get wrong written out inline. From there, every page is available as plain markdown by adding .md to its URL, for example:
https://docs.zevpaycheckout.com/checkout/standard.mdIf your agent can read a lot at once, https://docs.zevpaycheckout.com/llms-full.txt is the whole documentation in one file.
Pick the integration
| You have | Use | Notes |
|---|---|---|
| A website or app with a backend (Next.js, Express, Laravel, serverless functions, Supabase) | Standard Checkout | Your server creates the payment with the secret key; the customer pays on our hosted page and returns to you. |
| A frontend-only site, or you want the payment form on your own page | Inline Checkout | Runs in the browser with the public key. Add one serverless function to verify and receive webhooks. |
| A WordPress or WooCommerce store | WooCommerce plugin | No code needed. |
| A mobile app | React Native or Flutter SDK |
Rules every integration must follow
Paste these into your agent's instructions as they are.
- Secret keys stay on the server.
sk_test_...andsk_live_...go in server environment variables only, never in browser or mobile code. Public keys (pk_...) are the only keys allowed in the browser. - Amounts are in kobo. ₦2,000 is
200000. Every amount in requests, responses and webhooks is in the currency's smallest unit. - Responses are wrapped. Read fields from
datain{ "success": true, "data": { ... } }. - Send your own
reference(your order or payment ID) on every initialize. It makes retries safe and is how you find the payment later. - The return to your site is not proof of payment. Confirm with verify from your server, or with the webhook. Verify accepts the session ID, our reference, or your own reference. All the options are compared in Confirming payments.
- Fulfil from the webhook.
charge.successarrives even when the customer closes the page before returning. Use the redirect or callback only to show the customer a result. - Verify the webhook signature over the raw body. HMAC-SHA256 of the exact request text with your webhook secret, hex encoded, compared in constant time with the
x-zevpay-signatureheader. Parse the JSON only after the check passes. See Serverless platforms for Next.js, Vercel and Supabase. - Fulfil exactly once. Webhooks can arrive more than once, and the webhook and your return page may both confirm the same payment. Key fulfilment on
data.reference(for example a unique constraint) so a repeat does nothing. Retry initialize with the samereferenceafter a timeout: it returns the same session. See idempotency and retries. - Check the mode. Every webhook and verify response carries
livemode. In production fulfil only when it istrue. - The webhook URL must be public HTTPS. No localhost or private addresses; use a tunnel such as ngrok while developing. Redirects are not followed.
Test, then go live
- Build with test keys (
sk_test_/pk_test_). They work before your account verification is approved. - Pay a test session with Simulate successful transfer on the payment page, or
POST /v1/checkout/session/{session_id}/simulate-paymentwith your test secret key. A real, signedcharge.successis sent to your test webhook URL. - When everything works, create live keys in the dashboard, swap
sk_test_forsk_live_, and set the production webhook URL on the live key. No other code changes. - Make one small live payment end to end, webhook included, before opening payments to everyone.
Full details: Test Mode.
A brief to paste into your agent
Replace the bracketed parts, then paste it in.
text
Integrate ZevPay Checkout into [describe the app, e.g. "a React + Vite site on
Vercel with a Supabase database"]. Customers pay for [what, e.g. "a monthly
membership of NGN 2,000"].
Read first: https://docs.zevpaycheckout.com/llms.txt
Then: https://docs.zevpaycheckout.com/guide/ai-agents.md
https://docs.zevpaycheckout.com/checkout/standard.md
https://docs.zevpaycheckout.com/guide/confirming-payments.md
https://docs.zevpaycheckout.com/webhooks/signatures.md
https://docs.zevpaycheckout.com/guide/test-mode.md
Build:
1. A server endpoint that calls
POST https://api.zevpaycheckout.com/v1/checkout/session/initialize
with header x-api-key: <ZEVPAY_SECRET_KEY from env>, and body:
amount (kobo), currency "NGN", email, customer_name, callback_url,
reference (unique per payment, e.g. "<userId>_<YYYY-MM>"), metadata.
Save the reference with status "pending", then redirect the browser to
data.checkout_url.
2. A callback page that reads ?status=&merchant_reference= and shows the
result. It does not grant access by itself.
3. A webhook endpoint that reads the raw body, verifies x-zevpay-signature
(HMAC-SHA256, hex, constant-time) with ZEVPAY_WEBHOOK_SECRET, then on
event "charge.success" marks data.merchant_reference as paid exactly once
(idempotent on data.reference) and grants access. Check livemode.
4. Optional: GET /v1/checkout/session/{reference}/verify with the secret key
before showing success; fulfil only when data.status is "completed".
Keep all secret keys server-side. Test with sk_test_ keys and the
"Simulate successful transfer" button, then switch to sk_live_ keys.Common mistakes
| Mistake | What happens | Fix |
|---|---|---|
Amount sent in naira (2000) | Customer is charged ₦20 | Send kobo: 200000 |
| Secret key used in React or mobile code | Anyone can take it from your site | Call initialize from a server function |
| Body parsed to JSON before checking the signature | Signatures never match | Verify over the raw text, then parse |
| Access granted from the callback URL | Anyone can type ?status=success | Grant from the webhook or a verify call |
| No idempotency on fulfilment | Double access or double credit on a retried webhook | Unique constraint on data.reference |
localhost webhook URL | Refused when you save it | Use a tunnel such as ngrok |
| Test key in production | Payments never settle | Use sk_live_ keys and check livemode |