When you initiate a disbursement with requires_approval: "YES", Kulmi Pay holds the payment in a PREVIEW-AND-APPROVE state until you explicitly approve it. This gives you a window to review the transactions before any money moves. Once you approve, Kulmi Pay queues the file for processing. You can also cancel a file at any point while it’s still in PREVIEW-AND-APPROVE.
Payment file states
Every disbursement moves through a series of states from initiation to completion:
| State | Description |
|---|
PENDING | File has been created but not yet started |
PREVIEW-AND-APPROVE | File is ready for review — transactions are validated but not yet sent |
PROCESSING | File has been approved and payments are being sent to recipients |
COMPLETED | All transactions have been processed (individual transactions may succeed or fail) |
FAILED | The file could not be processed |
You can only approve or cancel a payment file while it is in the PREVIEW-AND-APPROVE state. Attempting to approve a file in any other state will return an error.
Approve a disbursement
Call POST /api/v1/send-money/approve/ with the file_id and the full list of transaction_id values from the initiation response. Kulmi Pay checks that the number of transaction IDs you supply matches the number of transactions in the file — this acts as a confirmation that you have reviewed every recipient.
curl -X POST https://app.kulmipay.com/api/v1/send-money/approve/ \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"file_id": "f1a2b3c4-0000-0000-0000-000000000001",
"transactions": [
"t9z8y7x6-0000-0000-0000-000000000001",
"t9z8y7x6-0000-0000-0000-000000000002"
]
}'
You can also identify the file by tracking_id instead of file_id:
{
"tracking_id": "550e8400-e29b-41d4-a716-446655440000",
"transactions": ["t9z8y7x6-0000-0000-0000-000000000001"]
}
Cancel a disbursement
Call POST /api/v1/send-money/cancel/ with the file_id to cancel the payment file. Once cancelled, no transactions in the file will be processed.
curl -X POST https://app.kulmipay.com/api/v1/send-money/cancel/ \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"file_id": "f1a2b3c4-0000-0000-0000-000000000001"
}'
Check disbursement status
Call POST /api/v1/send-money/status/ with the tracking_id to fetch the current state of a payment file and the status of every transaction within it.
curl -X POST https://app.kulmipay.com/api/v1/send-money/status/ \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"tracking_id": "550e8400-e29b-41d4-a716-446655440000"
}'
Response
{
"file_id": "f1a2b3c4-0000-0000-0000-000000000001",
"tracking_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "COMPLETED",
"status_code": null,
"transactions_count": 2,
"total_amount": "1000.00",
"actual_charges": "20.00",
"paid_amount": "1000.00",
"failed_amount": "0.00",
"transactions": [
{
"transaction_id": "t9z8y7x6-0000-0000-0000-000000000001",
"status": "SUCCESS",
"account": "254712345678",
"name": "Jane Doe",
"amount": "500.00",
"charge": "10.00",
"narrative": "Salary payment",
"provider_reference": "OD12345678",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:31:45Z"
},
{
"transaction_id": "t9z8y7x6-0000-0000-0000-000000000002",
"status": "SUCCESS",
"account": "254798765432",
"name": "James Mwangi",
"amount": "500.00",
"charge": "10.00",
"narrative": "Salary payment",
"provider_reference": "OD12345679",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:31:50Z"
}
],
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:31:50Z"
}
Validate a recipient account
Before initiating a disbursement, you can verify that a recipient account exists and retrieve the registered account name. Call POST /api/v1/send-money/validate-account/.
curl -X POST https://app.kulmipay.com/api/v1/send-money/validate-account/ \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"provider": "PESALINK",
"account": "1234567890",
"bank_code": "68"
}'
Response
{
"account": "1234567890",
"name": "John Kamau",
"status": "SUCCESS"
}
For M-Pesa B2B, include account_type ("PayBill" or "TillNumber") in the request:
{
"provider": "MPESA-B2B",
"account": "400200",
"account_type": "PayBill"
}