---
title: Building with AI agents
description: How to point an AI coding agent at the ZevPay Checkout docs, the rules every integration must follow, and a brief you can paste into your agent.
---

# 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.txt
```

It 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.md
```

If 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](/checkout/standard) | 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](/checkout/inline) | Runs in the browser with the public key. Add one serverless function to verify and receive webhooks. |
| A WordPress or WooCommerce store | [WooCommerce plugin](/sdks/woocommerce) | No code needed. |
| A mobile app | [React Native](/sdks/react-native) or [Flutter](/sdks/flutter) SDK | |

## Rules every integration must follow

Paste these into your agent's instructions as they are.

1. **Secret keys stay on the server.** `sk_test_...` and `sk_live_...` go in server environment variables only, never in browser or mobile code. Public keys (`pk_...`) are the only keys allowed in the browser.
2. **Amounts are in kobo.** ₦2,000 is `200000`. Every amount in requests, responses and webhooks is in the currency's smallest unit.
3. **Responses are wrapped.** Read fields from `data` in `{ "success": true, "data": { ... } }`.
4. **Send your own `reference`** (your order or payment ID) on every initialize. It makes retries safe and is how you find the payment later.
5. **The return to your site is not proof of payment.** Confirm with [verify](/api/verify-session) 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](/guide/confirming-payments).
6. **Fulfil from the webhook.** [`charge.success`](/webhooks/events#charge-success) arrives even when the customer closes the page before returning. Use the redirect or callback only to show the customer a result.
7. **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-signature` header. Parse the JSON only after the check passes. See [Serverless platforms](/webhooks/signatures#serverless-platforms) for Next.js, Vercel and Supabase.
8. **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 same `reference` after a timeout: it returns the same session. See [idempotency and retries](/guide/confirming-payments#idempotency-everything-can-safely-happen-twice).
9. **Check the mode.** Every webhook and verify response carries `livemode`. In production fulfil only when it is `true`.
10. **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

1. Build with test keys (`sk_test_` / `pk_test_`). They work before your account verification is approved.
2. Pay a test session with **Simulate successful transfer** on the payment page, or `POST /v1/checkout/session/{session_id}/simulate-payment` with your test secret key. A real, signed `charge.success` is sent to your test webhook URL.
3. When everything works, create live keys in the dashboard, swap `sk_test_` for `sk_live_`, and set the production webhook URL on the live key. No other code changes.
4. Make one small live payment end to end, webhook included, before opening payments to everyone.

Full details: [Test Mode](/guide/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` |

## Related

- [Confirming payments](/guide/confirming-payments)
- [Quick Start](/guide/quick-start)
- [Use Cases](/guide/use-cases)
- [Standard Checkout](/checkout/standard)
- [Inline Checkout](/checkout/inline)
- [Verifying Signatures](/webhooks/signatures)
