Standard Checkout
Create a checkout session on your server, redirect the customer to our hosted page, and handle the result when they return. This keeps your secret key on the server and lets us host the payment page.
If you want the checkout to appear as a modal on your own page, use Inline Checkout.
How it works
- Your server creates a session with your secret key.
- You redirect the customer to the returned
checkout_url. - The customer selects a method and pays on our hosted page.
- The customer is redirected to your
callback_urlwith the status. - Your server verifies the payment before fulfilling the order.
Step 1: Create a session
Call the initialize endpoint from your server with your secret key.
const response = await fetch('https://api.zevpaycheckout.com/v1/checkout/session/initialize', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'sk_test_your_secret_key',
},
body: JSON.stringify({
amount: 500000, // ₦5,000 in kobo
currency: 'NGN',
email: 'customer@example.com',
customer_name: 'John Doe', // optional
callback_url: 'https://yoursite.com/payment/callback',
reference: 'order_12345', // optional
metadata: { orderId: '12345' }, // optional
}),
});
const { data } = await response.json();
// data.checkout_url -> https://secure.zevpaycheckout.com/{sessionId}
// data.session_id -> save this for verificationimport requests
response = requests.post(
"https://api.zevpaycheckout.com/v1/checkout/session/initialize",
headers={
"Content-Type": "application/json",
"x-api-key": "sk_test_your_secret_key",
},
json={
"amount": 500000,
"currency": "NGN",
"email": "customer@example.com",
"customer_name": "John Doe",
"callback_url": "https://yoursite.com/payment/callback",
"reference": "order_12345",
},
)
data = response.json()["data"]
checkout_url = data["checkout_url"]
session_id = data["session_id"]$ch = curl_init('https://api.zevpaycheckout.com/v1/checkout/session/initialize');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-api-key: sk_test_your_secret_key',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 500000,
'currency' => 'NGN',
'email' => 'customer@example.com',
'customer_name' => 'John Doe',
'callback_url' => 'https://yoursite.com/payment/callback',
'reference' => 'order_12345',
]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);
$checkoutUrl = $response['data']['checkout_url'];
$sessionId = $response['data']['session_id'];The response returns the hosted page URL and the identifiers you need later.
{
"session_id": "ecc48011-e36e-4741-9b99-657f4a1ee86e",
"reference": "ZVP-CKO-S-abc123",
"checkout_url": "https://secure.zevpaycheckout.com/ecc48011-e36e-4741-9b99-657f4a1ee86e",
"amount": 500000,
"currency": "NGN",
"expires_at": "2026-01-01T12:30:00.000Z",
"enabled_payment_methods": ["bank_transfer", "payid"]
}Step 2: Redirect the customer
Send the customer to checkout_url.
window.location.href = data.checkout_url;Or link to it directly:
<a href="https://secure.zevpaycheckout.com/ecc48011-e36e-4741-9b99-657f4a1ee86e">
Complete payment
</a>Step 3: Handle the callback
After the customer finishes or leaves, we redirect them to your callback_url with query parameters.
https://yoursite.com/payment/callback?status=success&reference=ZVP-CKO-S-abc123| Parameter | Values | Description |
|---|---|---|
status | success | Payment completed. |
status | cancelled | Customer cancelled or closed the page. |
status | expired | Session expired before payment. |
reference | string | Transaction reference. Present on success. |
Step 4: Verify the payment
Always verify
The callback query parameters are not proof of payment. Confirm every payment from your server before you fulfil an order.
app.get('/payment/callback', async (req, res) => {
const { status } = req.query;
if (status === 'success') {
const verification = await fetch(
`https://api.zevpaycheckout.com/v1/checkout/session/${sessionId}/verify`,
{ headers: { 'x-api-key': 'sk_test_your_secret_key' } },
);
const { data } = await verification.json();
if (data.status === 'completed') {
await fulfillOrder(data.reference, data.amount);
return res.redirect('/order/success');
}
return res.redirect('/order/pending');
}
if (status === 'cancelled') return res.redirect('/checkout');
if (status === 'expired') return res.redirect('/checkout?error=expired');
});Initialize parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Amount in kobo. |
email | string | Yes | Customer's email address. |
currency | string | No | "NGN" (default) or "USD". |
callback_url | string | No | Where to redirect the customer after checkout. |
reference | string | No | Your unique reference. Used for idempotency, see below. |
customer_name | string | No | Shown in the dashboard instead of "Anonymous". |
metadata | object | No | Custom data attached to the session. |
payment_methods | string[] | No | Methods to offer, for example ["bank_transfer", "payid"]. Defaults to ["bank_transfer", "payid"]. |
line_items | array | No | Optional line items, each { name, description?, quantity, amount } with amount in kobo. Renders an itemised summary on the page. |
Authentication
Both key types can call initialize. Use your secret key from a server, which is the pattern shown here. A public key also works, in which case its allowed domains are enforced against the request origin. Never put a secret key in client-side code.
Idempotency
If you retry initialize with the same reference while a session is still active, we return the existing session rather than creating a second one. Use a stable reference per order to make retries safe.
Session lifetime
A checkout session is valid for 30 minutes. After that the hosted page shows an expired state with a link back to your site, and the callback status is expired.
Compared to Inline Checkout
| Aspect | Standard | Inline |
|---|---|---|
| Session creation | Server-side, secret key | Browser, public key |
| Experience | Full-page redirect | Modal on your page |
| Server required | Yes | No |
| Result delivery | Callback URL | JavaScript callback |
| Best for | Server-rendered stores, payment links | Vanilla JS and single-page apps |