API reference / Payments
Payments
A payment represents one attempt to collect money from a customer. Create it on your server, send the customer to checkout, then track its status.
Payment lifecycle
pending→processing→succeededorfailed
| Status | Meaning | What to do |
|---|---|---|
pending | Created, waiting for the customer to pay. | Send the customer to checkout_url. |
processing | The customer has paid and the bank is confirming. Bank transfers can stay here for up to 30 minutes. | Wait for a webhook. Don't fulfil yet. |
succeeded | Funds are confirmed. Final. | Fulfil the order. |
failed | The payment didn't complete. Final. See failure_code. | Ask the customer to try again with a new payment. |
Unpaid payments expire after 24 hours and move to failed with the code expired.
Create a payment
POST/v2/payments
Body parameters
| Parameter | Description |
|---|---|
amountrequiredinteger | Amount in kobo. Minimum 10000 (₦100.00), maximum 1000000000 (₦10,000,000.00). |
currencyrequiredstring | Three-letter ISO code. Only NGN is supported. |
referencerequiredstring | Your own ID for the order, up to 64 characters. Must be unique per account; reusing one returns 409 reference_in_use. |
customer.emailrequiredstring | Where Ledgerline sends the receipt. |
redirect_urloptionalstring | Where checkout sends the customer afterwards. Must use HTTPS in live mode. |
channelsoptionalarray | Limit payment methods to card, bank_transfer or both. Defaults to both. |
metadataoptionalobject | Up to 20 key-value pairs, returned unchanged on the payment and in webhooks. |
Headers
| Header | Description |
|---|---|
Idempotency-Keyrecommended | Makes retries safe. See Idempotency. |
Returns
The payment object with status pending and a checkout_url, with HTTP 201.
RequestNode.js
const res = await fetch('https://api.ledgerline.example/v2/payments', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LEDGERLINE_KEY}`,
'Idempotency-Key': order.paymentKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: order.totalKobo,
currency: 'NGN',
reference: order.id,
customer: { email: order.email },
redirect_url: 'https://yourshop.example/thanks',
}),
});
const payment = await res.json();
Retrieve a payment
GET/v2/payments/{id}
Returns the current state of a payment. You can also look one up by your own reference with GET /v2/payments?reference=order_1042.
The payment object
| Field | Description |
|---|---|
idstring | Unique ID, starting with pay_. |
statusstring | One of the lifecycle statuses. |
amount, currencyinteger, string | As requested. |
feeinteger | Ledgerline's fee in kobo. Set once the payment succeeds. |
channelstring or null | card or bank_transfer, once the customer has chosen. |
failure_codestring or null | Why a payment failed, for example card_declined or expired. |
paid_atstring or null | ISO 8601 time the payment succeeded. |
Errors
| Status | Code | Cause and fix |
|---|---|---|
| 400 | amount_invalid | Amount isn't a whole number of kobo, or is outside the limits. |
| 401 | key_invalid | Missing, revoked or wrong-environment key. Check you're not using a test key against the live URL. |
| 409 | reference_in_use | The reference was used before. Retrieve the existing payment by reference instead. |
| 422 | idempotency_mismatch | The same idempotency key was sent with a different body. Generate a new key for a new operation. |
| 429 | rate_limited | More than 100 requests a second. Back off and retry after the Retry-After header. |
Last updated 3 November 2026