Invoices
Invoices let you bill a customer for one or more line items and collect payment against them. Creating an invoice automatically generates a payment link for the customer and emails them a link to view and pay it.
Concepts
- An invoice belongs to one of your businesses and must have a
merchantReferencethat is unique for that business. - It has one or more items — the things being billed.
- It can optionally have charges — additional amounts on top of the items. A charge is either a
CHARGE(adds to the total, e.g. shipping, handling, tax) or aDEDUCTION(subtracts from the total, e.g. a discount).totalAmount = sum(item amounts) + sum(CHARGE amounts) - sum(DEDUCTION amounts), and must be greater than zero. - Creating an invoice generates a payment link behind the scenes; the invoice's
paymentLinkUrlis what the customer uses to pay. statusmoves through:CREATED→PAID,CANCELLED, orOVERDUE(past itsdueDatewithout being paid).frequency(ONE_TIME,WEEKLY,MONTHLY,QUARTERLY,YEARLY) is metadata describing how often you intend to bill this invoice — PayOnUs does not automatically regenerate or re-bill the invoice based on this value; you create a new invoice each time.
Create an Invoice
Required Parameters
| Parameter | Type | Description |
|---|---|---|
businessId |
string (UUID) | Your business ID |
merchantReference |
string | Unique reference for this invoice, scoped to the business |
customer |
object | The payer's details — see below |
customer.name |
string | Payer's name |
currency |
string | Currency code (e.g. NGN, KES, USD) |
frequency |
string | ONE_TIME, WEEKLY, MONTHLY, QUARTERLY, or YEARLY |
items |
array | At least one line item — see below |
items[].itemName |
string | Name of the item being billed |
items[].amount |
number | Amount for this item (must be ≥ 0) |
Optional Parameters
| Parameter | Type | Description |
|---|---|---|
description |
string | Free-text description of the invoice |
dueDate |
string (date) | Date the invoice is due, e.g. 2025-02-15 |
customer.phone |
string | Payer's phone number |
customer.email |
string | Payer's email — required if you want the invoice notification email to be sent |
charges |
array | Additional amounts on top of the items — see below |
charges[].chargeCategory |
string | CHARGE to add this amount to the total, or DEDUCTION to subtract it (e.g. a discount) |
charges[].chargeType |
string | One of SHIPPING_DELIVERY, HANDLING, INSTALLATION_SETUP, THIRD_PARTY_PASS_THROUGH_COST, LICENSING_SUBSCRIPTION, MAINTENANCE_SUPPORT, CONSULTATION_ADVISORY, TRAINING, TRAVEL_LOGISTICS, PAYMENT_PROCESSING_FEE, TAX_LEVY, DISCOUNT, OTHER |
charges[].name |
string | Label for this charge |
charges[].amount |
number | Amount for this charge. Always a positive number (≥ 0), regardless of category — for a DEDUCTION, the API subtracts this value itself; do not send a negative number |
Sample Request
{
"businessId": "{business_id}",
"merchantReference": "INV-REF-0001",
"customer": {
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+2348012345678"
},
"description": "Website design services",
"currency": "NGN",
"frequency": "ONE_TIME",
"dueDate": "2025-02-15",
"items": [
{ "itemName": "Design services", "amount": 150000.00 },
{ "itemName": "Hosting setup", "amount": 20000.00 }
],
"charges": [
{ "chargeCategory": "CHARGE", "chargeType": "HANDLING", "name": "Handling fee", "amount": 5000.00 },
{ "chargeCategory": "DEDUCTION", "chargeType": "DISCOUNT", "name": "Loyalty discount", "amount": 10000.00 }
]
}
Sample Response
{
"status": 200,
"message": "Success",
"data": {
"id": "xxx-xxx-xxx",
"businessId": "xxx-xxx-xxx",
"invoiceNumber": "INV-xxx-xxx-xxx",
"merchantReference": "INV-REF-0001",
"customer": {
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+2348012345678"
},
"description": "Website design services",
"currency": "NGN",
"frequency": "ONE_TIME",
"status": "CREATED",
"dueDate": "2025-02-15",
"subtotal": 170000.00,
"totalCharges": 5000.00,
"totalDeductions": 10000.00,
"totalAmount": 165000.00,
"amountPaid": 0.00,
"paidDate": null,
"paymentLinkUrl": "https://core-sandbox.payonus.com/payments/biz/xxx-xxx-xxx",
"items": [
{ "id": "xxx-xxx-xxx", "itemName": "Design services", "amount": 150000.00 },
{ "id": "xxx-xxx-xxx", "itemName": "Hosting setup", "amount": 20000.00 }
],
"charges": [
{ "id": "xxx-xxx-xxx", "chargeCategory": "CHARGE", "chargeType": "HANDLING", "name": "Handling fee", "amount": 5000.00 },
{ "id": "xxx-xxx-xxx", "chargeCategory": "DEDUCTION", "chargeType": "DISCOUNT", "name": "Loyalty discount", "amount": 10000.00 }
],
"createdDate": "2025-01-15 11:00:00",
"businessName": "Test Business",
"merchantName": "Test Merchant"
}
}
Notes
merchantReferencemust not already be in use for the business, or the request fails with409 Conflict.- At least one item is required, and the computed
totalAmount(items +CHARGEs −DEDUCTIONs) must be greater than zero, or the request fails with400 Bad Request. If your deductions would bring the total to zero or below, reduce them so the invoice still has a positive amount due. - If
customer.emailis provided, the customer is emailed a link to view and pay the invoice as soon as it's created.
List / Search Invoices
Required Query Parameters
| Parameter | Type | Description |
|---|---|---|
merchantId |
string (UUID) | Your merchant ID |
Optional Query Parameters
| Parameter | Type | Description |
|---|---|---|
businessIds |
string | Comma-separated business IDs to filter by. Must all belong to your merchant. Defaults to all your businesses if omitted |
id |
string (UUID) | Filter to a specific invoice ID |
invoiceNumber |
string | Filter by the system-generated invoice number |
merchantReference |
string | Filter by your reference |
status |
string | CREATED, PAID, CANCELLED, or OVERDUE |
currency |
string | Currency code |
createdFrom / createdTo |
string (date) | Filter by creation date range, e.g. 2025-01-01 |
pageNo |
number | Page number (default 1) |
pageSize |
number | Page size (default 30) |
Sample Response
{
"status": 200,
"message": "Success",
"data": {
"pageNo": 1,
"pageSize": 30,
"lastPage": 1,
"totalNumberOfItems": 1,
"content": [
{
"id": "xxx-xxx-xxx",
"businessId": "xxx-xxx-xxx",
"invoiceNumber": "INV-xxx-xxx-xxx",
"merchantReference": "INV-REF-0001",
"customer": { "name": "Jane Doe", "email": "jane@example.com", "phone": "+2348012345678" },
"currency": "NGN",
"frequency": "ONE_TIME",
"status": "CREATED",
"dueDate": "2025-02-15",
"subtotal": 170000.00,
"totalCharges": 5000.00,
"totalDeductions": 10000.00,
"totalAmount": 165000.00,
"amountPaid": 0.00,
"paymentLinkUrl": "https://core-sandbox.payonus.com/payments/biz/xxx-xxx-xxx",
"items": [],
"charges": [],
"createdDate": "2025-01-15 11:00:00",
"businessName": "Test Business",
"merchantName": "Test Merchant"
}
]
}
}
!!! note
Line items and charges are not returned on the list endpoint (items/charges are always empty arrays here) — fetch the single invoice below to see them.
Get an Invoice
Returns a single invoice, including its items and charges, and a freshly-computed amountPaid.
| Path Parameter | Type | Description |
|---|---|---|
businessId |
string (UUID) | The business the invoice belongs to |
id |
string (UUID) | The invoice ID |
Returns 404 Not Found if the invoice doesn't belong to businessId, or if businessId doesn't belong to your merchant.
The response body has the same shape as Create an Invoice above, with items and charges populated.
Cancel an Invoice
| Path Parameter | Type | Description |
|---|---|---|
businessId |
string (UUID) | The business the invoice belongs to |
id |
string (UUID) | The invoice ID |
Cancelling an invoice sets its status to CANCELLED and immediately expires its payment link, so the payment page stops accepting payment.
Errors
409 Conflict— the invoice has already been paid409 Conflict— a payment against the invoice isPENDING,PROCESSING, or alreadySUCCESSFUL(you cannot cancel while a payment is in flight or has gone through)404 Not Found— the invoice doesn't belong tobusinessId, orbusinessIddoesn't belong to your merchant
Resend an Invoice
| Path Parameter | Type | Description |
|---|---|---|
businessId |
string (UUID) | The business the invoice belongs to |
id |
string (UUID) | The invoice ID |
Re-sends the original invoice notification email to the customer, unchanged — it does not create a new invoice or modify the existing one.
!!! note
A 200 response means the resend was queued, not that the email was delivered — this endpoint does not return delivery status.
Errors
409 Conflict— the invoice has been cancelled409 Conflict— the invoice has already been paid404 Not Found— the invoice doesn't belong tobusinessId, orbusinessIddoesn't belong to your merchant
Example — cURL
curl -X POST \
"https://core-sandbox.payonus.com/api/v1/invoices" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"businessId": "<business-uuid>",
"merchantReference": "INV-REF-0001",
"customer": {"name": "Jane Doe", "email": "jane@example.com"},
"currency": "NGN",
"frequency": "ONE_TIME",
"items": [{"itemName": "Design services", "amount": 150000.00}]
}'