Invoices API
Create and manage invoices programmatically. Invoices include automatic payment link generation for easy collection.
Generate professional invoices with automatic payment link and QR code generation. Track payment status, manage due dates, apply discounts, and handle partial payments. Each invoice creates a unique payment link that customers can use to pay online.
Use Cases
- Freelancers & Agencies: Bill clients for projects and services
- B2B Transactions: Create invoices for business customers
- Recurring Billing: Generate invoices for subscription-based services
- E-commerce: Invoice for custom orders or wholesale purchases
Available Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /business/invoice/create | Create an invoice |
GET | /business/invoice/list | List all invoices |
GET | /business/invoice/details/:id | Get invoice details |
PATCH | /business/invoice/update/:id | Update an invoice |
Invoice Statuses
| Status | Description |
|---|---|
draft | Invoice is being drafted |
unpaid | Invoice sent, awaiting payment |
partially_paid | Partial payment received |
paid | Invoice fully paid |
overdue | Past due date, unpaid |
cancelled | Invoice cancelled |
Create Invoice
Create a new invoice for a customer with automatic payment link generation.
Endpoint
POST /business/invoice/createRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
customerid | string | Yes | Customer ID (must exist in your business) |
items | array | Yes | Invoice line items (min: 1) |
duedate | string | Yes | Payment due date (ISO 8601) |
title | string | No | Invoice title (auto-generated if not provided) |
description | string | No | Invoice description or notes |
invoicedate | string | No | Invoice date (defaults to current date) |
taxid | string | No | Tax configuration ID |
discount | number | No | Discount amount |
discounttype | string | No | Discount type: percentage or fixed |
remark | string | No | Internal notes |
Item Object
| Field | Type | Required | Description |
|---|---|---|---|
itemid | string | Yes | Product/Service ID |
name | string | No | Item name |
quantity | integer | Yes | Quantity |
rate | number | Yes | Price per unit |
Example Request
curl -X POST "https://api.cashfin.africa/business/invoice/create" \
-H "Authorization: cs_your_client_secret" \
-H "Content-Type: application/json" \
-d '{
"customerid": "507f1f77bcf86cd799439011",
"items": [
{
"itemid": "507f191e810c19729de860ea",
"name": "Website Development",
"quantity": 1,
"rate": 150000.00
},
{
"itemid": "507f191e810c19729de860eb",
"name": "Hosting (Annual)",
"quantity": 1,
"rate": 12000.00
}
],
"title": "Website Development Project",
"description": "Complete website redesign with hosting",
"duedate": "2024-02-15",
"discount": 10,
"discounttype": "percentage"
}'const invoiceData = {
customerid: "507f1f77bcf86cd799439011",
items: [
{
itemid: "507f191e810c19729de860ea",
name: "Website Development",
quantity: 1,
rate: 150000.0,
},
{
itemid: "507f191e810c19729de860eb",
name: "Hosting (Annual)",
quantity: 1,
rate: 12000.0,
},
],
title: "Website Development Project",
description: "Complete website redesign with hosting",
duedate: "2024-02-15",
discount: 10,
discounttype: "percentage",
};
const response = await fetch(
"https://api.cashfin.africa/business/invoice/create",
{
method: "POST",
headers: {
Authorization: "cs_your_client_secret",
"Content-Type": "application/json",
},
body: JSON.stringify(invoiceData),
}
);
const data = await response.json();
console.log(data);<?php
$invoiceData = [
'customerid' => '507f1f77bcf86cd799439011',
'items' => [
[
'itemid' => '507f191e810c19729de860ea',
'name' => 'Website Development',
'quantity' => 1,
'rate' => 150000.00
],
[
'itemid' => '507f191e810c19729de860eb',
'name' => 'Hosting (Annual)',
'quantity' => 1,
'rate' => 12000.00
]
],
'title' => 'Website Development Project',
'description' => 'Complete website redesign with hosting',
'duedate' => '2024-02-15',
'discount' => 10,
'discounttype' => 'percentage'
];
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cashfin.africa/business/invoice/create",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($invoiceData),
CURLOPT_HTTPHEADER => [
"Authorization: cs_your_client_secret",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$result = json_decode($response, true);
print_r($result);import requests
invoice_data = {
'customerid': '507f1f77bcf86cd799439011',
'items': [
{
'itemid': '507f191e810c19729de860ea',
'name': 'Website Development',
'quantity': 1,
'rate': 150000.00
},
{
'itemid': '507f191e810c19729de860eb',
'name': 'Hosting (Annual)',
'quantity': 1,
'rate': 12000.00
}
],
'title': 'Website Development Project',
'description': 'Complete website redesign with hosting',
'duedate': '2024-02-15',
'discount': 10,
'discounttype': 'percentage'
}
response = requests.post(
'https://api.cashfin.africa/business/invoice/create',
headers={
'Authorization': 'cs_your_client_secret',
'Content-Type': 'application/json'
},
json=invoice_data
)
result = response.json()
print(result)Success Response
{
"success": true,
"message": "Invoice created successfully",
"data": {
"_id": "507f1f77bcf86cd799439020",
"invoiceno": "INV-2024-001",
"title": "Website Development Project",
"status": "unpaid",
"balance": 145800.00,
"invoicedate": "2024-01-15T00:00:00Z",
"duedate": "2024-02-15T00:00:00Z",
"items": [
{
"itemid": "507f191e810c19729de860ea",
"name": "Website Development",
"quantity": 1,
"rate": 150000.00
},
{
"itemid": "507f191e810c19729de860eb",
"name": "Hosting (Annual)",
"quantity": 1,
"rate": 12000.00
}
],
"customer": {
"_id": "507f1f77bcf86cd799439011",
"name": "John Doe",
"email": "[email protected]",
"phone": "+254712345678"
},
"paymentlink": {
"_id": "507f1f77bcf86cd799439021",
"shorturl": "https://yourbusiness.cashfin.africa/pay/abc12345"
},
"qrcode": "https://res.cloudinary.com/cashfin/image/upload/invoice-qr.png",
"createdat": "2024-01-15T10:30:00Z"
}
}Response Fields
| Field | Description |
|---|---|
_id | Unique invoice identifier |
invoiceno | Human-readable invoice number (e.g., INV-2024-001) |
title | Invoice title |
status | Current invoice status |
balance | Amount due after discounts |
paymentlink | Auto-generated payment collection link |
qrcode | QR code URL for quick payments |
List Invoices
Retrieve a paginated list of all invoices.
Endpoint
GET /business/invoice/listQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
limit | integer | 10 | Items per page (max: 100) |
status | string | - | Filter by status |
search | string | - | Search in title, description, invoice number |
customerid | string | - | Filter by customer ID |
Example Request
curl -X GET "https://api.cashfin.africa/business/invoice/list?page=1&limit=20&status=unpaid" \
-H "Authorization: cs_your_client_secret"const params = new URLSearchParams({
page: "1",
limit: "20",
status: "unpaid",
});
const response = await fetch(
`https://api.cashfin.africa/business/invoice/list?${params}`,
{
headers: {
Authorization: "cs_your_client_secret",
},
}
);
const data = await response.json();
console.log(data);<?php
$params = http_build_query([
'page' => 1,
'limit' => 20,
'status' => 'unpaid'
]);
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cashfin.africa/business/invoice/list?{$params}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: cs_your_client_secret"
],
]);
$response = curl_exec($curl);
$data = json_decode($response, true);
print_r($data);import requests
response = requests.get(
'https://api.cashfin.africa/business/invoice/list',
headers={'Authorization': 'cs_your_client_secret'},
params={
'page': 1,
'limit': 20,
'status': 'unpaid'
}
)
data = response.json()
print(data)Example Response
{
"success": true,
"data": [
{
"_id": "507f1f77bcf86cd799439020",
"invoiceno": "INV-2024-001",
"title": "Website Development Project",
"status": "unpaid",
"balance": 145800.00,
"duedate": "2024-02-15T00:00:00Z",
"createdat": "2024-01-15T10:30:00Z"
},
{
"_id": "507f1f77bcf86cd799439021",
"invoiceno": "INV-2024-002",
"title": "Monthly Retainer",
"status": "paid",
"balance": 0,
"duedate": "2024-01-31T00:00:00Z",
"createdat": "2024-01-10T08:00:00Z"
}
],
"pagination": {
"total": 45,
"page": 1,
"limit": 20,
"pages": 3
}
}Get Invoice Details
Retrieve detailed information about a specific invoice including customer and payment information.
Endpoint
GET /business/invoice/details/:idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Invoice ID (MongoDB ObjectID) |
Example Request
curl -X GET "https://api.cashfin.africa/business/invoice/details/507f1f77bcf86cd799439020" \
-H "Authorization: cs_your_client_secret"const invoiceId = "507f1f77bcf86cd799439020";
const response = await fetch(
`https://api.cashfin.africa/business/invoice/details/${invoiceId}`,
{
headers: {
Authorization: "cs_your_client_secret",
},
}
);
const data = await response.json();
console.log(data);<?php
$invoiceId = '507f1f77bcf86cd799439020';
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cashfin.africa/business/invoice/details/{$invoiceId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: cs_your_client_secret"
],
]);
$response = curl_exec($curl);
$data = json_decode($response, true);
print_r($data);import requests
invoice_id = '507f1f77bcf86cd799439020'
response = requests.get(
f'https://api.cashfin.africa/business/invoice/details/{invoice_id}',
headers={'Authorization': 'cs_your_client_secret'}
)
data = response.json()
print(data)Example Response
{
"success": true,
"data": {
"_id": "507f1f77bcf86cd799439020",
"invoiceno": "INV-2024-001",
"title": "Website Development Project",
"description": "Complete website redesign with hosting",
"status": "unpaid",
"balance": 145800.00,
"subtotal": 162000.00,
"taxamount": 0,
"discount": 16200.00,
"discounttype": "percentage",
"invoicedate": "2024-01-15T00:00:00Z",
"duedate": "2024-02-15T00:00:00Z",
"qrcode": "https://res.cloudinary.com/cashfin/image/upload/invoice-qr.png",
"items": [
{
"itemid": "507f191e810c19729de860ea",
"name": "Website Development",
"quantity": 1,
"rate": 150000.00,
"total": 150000.00
},
{
"itemid": "507f191e810c19729de860eb",
"name": "Hosting (Annual)",
"quantity": 1,
"rate": 12000.00,
"total": 12000.00
}
],
"customer": {
"_id": "507f1f77bcf86cd799439011",
"name": "John Doe",
"email": "[email protected]",
"phone": "+254712345678"
},
"paymentlinks": [
{
"_id": "507f1f77bcf86cd799439021",
"shorturl": "abc12345",
"rawurl": "https://yourbusiness.cashfin.africa/pay/abc12345",
"status": "unpaid"
}
],
"createdat": "2024-01-15T10:30:00Z",
"updatedat": "2024-01-15T10:30:00Z"
}
}Update Invoice
Update an existing invoice. Only certain fields can be updated after creation.
Endpoint
PATCH /business/invoice/update/:idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Invoice ID (MongoDB ObjectID) |
Request Body
All fields are optional. Only provided fields will be updated.
| Field | Type | Description |
|---|---|---|
title | string | Invoice title |
description | string | Invoice description |
status | string | Invoice status (see valid values below) |
duedate | string | Due date (ISO 8601 format) |
discount | number | Discount amount |
discounttype | string | Discount type: percentage or fixed |
Valid Status Values
draftunpaidpartially_paidpaidoverduecancelled
Example Request
curl -X PATCH "https://api.cashfin.africa/business/invoice/update/507f1f77bcf86cd799439020" \
-H "Authorization: cs_your_client_secret" \
-H "Content-Type: application/json" \
-d '{
"status": "paid",
"description": "Paid in full on 2024-01-20"
}'const invoiceId = "507f1f77bcf86cd799439020";
const response = await fetch(
`https://api.cashfin.africa/business/invoice/update/${invoiceId}`,
{
method: "PATCH",
headers: {
Authorization: "cs_your_client_secret",
"Content-Type": "application/json",
},
body: JSON.stringify({
status: "paid",
description: "Paid in full on 2024-01-20",
}),
}
);
const data = await response.json();
console.log(data);<?php
$invoiceId = '507f1f77bcf86cd799439020';
$updateData = [
'status' => 'paid',
'description' => 'Paid in full on 2024-01-20'
];
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cashfin.africa/business/invoice/update/{$invoiceId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode($updateData),
CURLOPT_HTTPHEADER => [
"Authorization: cs_your_client_secret",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$result = json_decode($response, true);
print_r($result);import requests
invoice_id = '507f1f77bcf86cd799439020'
response = requests.patch(
f'https://api.cashfin.africa/business/invoice/update/{invoice_id}',
headers={
'Authorization': 'cs_your_client_secret',
'Content-Type': 'application/json'
},
json={
'status': 'paid',
'description': 'Paid in full on 2024-01-20'
}
)
result = response.json()
print(result)Example Response
{
"success": true,
"message": "Invoice updated successfully",
"data": {
"_id": "507f1f77bcf86cd799439020",
"invoiceno": "INV-2024-001",
"updated": {
"status": "paid",
"description": "Paid in full on 2024-01-20",
"updatedat": "2024-01-20T14:30:00Z"
}
}
}Error Responses
Validation Error
{
"success": false,
"error": "At least one item is required"
}Customer Not Found
{
"success": false,
"error": "Customer not found in this business"
}Product Not Found
{
"success": false,
"error": "product not found: 507f191e810c19729de860ea"
}Invoice Not Found
{
"success": false,
"error": "Invoice not found"
}Invalid Date Format
{
"success": false,
"error": "Invalid duedate format. Use ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SSZ)"
}Integration Examples
Complete Invoice Workflow
import Cashfin from "@cashfin/node";
const cashfin = new Cashfin({ apiKey: process.env.CASHFIN_API_KEY });
async function createAndSendInvoice(customerId, items, dueDate) {
// 1. Create the invoice
const invoice = await cashfin.invoices.create({
customerid: customerId,
items: items,
duedate: dueDate.toISOString(),
});
console.log(`Invoice ${invoice.invoiceno} created`);
console.log(`Payment link: ${invoice.paymentlink.shorturl}`);
return invoice;
}
// Usage
const items = [
{ itemid: "product_123", name: "Consulting", quantity: 10, rate: 5000 },
];
const invoice = await createAndSendInvoice(
"customer_456",
items,
new Date("2024-02-28")
);Check Overdue Invoices
async function getOverdueInvoices() {
const invoices = await cashfin.invoices.list({
status: "overdue",
limit: 100,
});
console.log(`Found ${invoices.pagination.total} overdue invoices`);
for (const invoice of invoices.data) {
console.log(`${invoice.invoiceno}: KES ${invoice.balance} due`);
}
return invoices.data;
}Update Invoice Status After Payment
async function markInvoiceAsPaid(invoiceId, paymentNote) {
const updated = await cashfin.invoices.update(invoiceId, {
status: "paid",
description: paymentNote,
});
console.log(`Invoice ${updated.invoiceno} marked as paid`);
return updated;
}
// Usage after receiving payment webhook
markInvoiceAsPaid("invoice_789", "Paid via M-Pesa on 2024-01-20");Webhooks
Receive notifications when invoice events occur:
| Event | Description |
|---|---|
invoice.created | New invoice created |
invoice.updated | Invoice details updated |
invoice.paid | Invoice fully paid |
invoice.partially_paid | Partial payment received |
invoice.overdue | Invoice past due date |
Webhook Payload Example
{
"event": "invoice.paid",
"timestamp": "2024-01-20T14:30:00Z",
"data": {
"_id": "507f1f77bcf86cd799439020",
"invoiceno": "INV-2024-001",
"status": "paid",
"balance": 0,
"customer": {
"_id": "507f1f77bcf86cd799439011",
"name": "John Doe"
}
}
}See Webhooks Guide for setup instructions.
Best Practices
1. Always Validate Customer First
Ensure the customer exists before creating an invoice:
const customer = await cashfin.customers.get(customerId);
if (!customer) {
// Create customer first
const newCustomer = await cashfin.customers.create({...});
customerId = newCustomer.id;
}2. Use Descriptive Titles
Include relevant information in the invoice title:
const invoice = await cashfin.invoices.create({
title: `${projectName} - ${month} ${year}`,
// ...
});3. Set Reasonable Due Dates
Consider your payment terms when setting due dates:
// Net 30 payment terms
const dueDate = new Date();
dueDate.setDate(dueDate.getDate() + 30);4. Handle Partial Payments
Track partial payments by checking the balance:
if (invoice.status === "partially_paid") {
const amountPaid = invoice.subtotal - invoice.balance;
console.log(`Received partial payment of KES ${amountPaid}`);
}