Payments API
M-Pesa STK Push (Lipa Na M-Pesa) and Paystack card payments.
Base: /api/v1/payments | X-Tenant-ID required
M-Pesa
POST
/api/v1/payments/mpesa/stkpush
🔒 Auth Required
Initiate an M-Pesa STK Push prompt to the customer's phone.
Request Body
{ "order_id": "uuid", "phone": "0712345678" }
Response
{ "success": true, "data": { "checkout_request_id": "ws_CO_...", "customer_message": "Please enter your PIN" } }
Possible Errors
| Code | HTTP | When |
|---|---|---|
| NOT_FOUND | 404 | Order not found |
| PAYMENT_FAILED | 400 | Order already paid |
| PAYMENT_FAILED | 500 | Safaricom API error |
POST
/api/v1/payments/mpesa/stkquery
🔒 Auth Required
Poll the status of an STK push by its CheckoutRequestID.
Request Body
{ "checkout_request_id": "ws_CO_..." }
Response
{ "success": true, "data": { "ResultCode": 0, "ResultDesc": "The service request is processed successfully." } }
POST
/api/v1/payments/mpesa/callback
Public
Daraja webhook endpoint. Called automatically by Safaricom on payment completion. Updates order payment_status to "paid" and triggers invoice + notification.
Response
200 OK — { "ResultCode": 0, "ResultDesc": "Accepted" }
Paystack
POST
/api/v1/payments/paystack/initiate
🔒 Auth Required
Initialize a Paystack transaction and get a payment URL.
Request Body
{ "order_id": "uuid", "email": "jane@email.com", "amount": 1766 }
Response
{ "success": true, "data": { "authorization_url": "https://checkout.paystack.com/...", "access_code": "...", "reference": "ALO-2024-00001-..." } }
Possible Errors
| Code | HTTP | When |
|---|---|---|
| PAYMENT_FAILED | 500 | Paystack API error |
GET
/api/v1/payments/paystack/verify/:ref
Public
Verify a Paystack payment by reference. Updates order if not already paid.
Response
{ "success": true, "data": { "reference": "...", "status": "success", "amount": 1766, "currency": "NGN", "paid_at": "2024-01-10T09:00:00Z" } }
POST
/api/v1/payments/paystack/webhook
Public
Paystack webhook endpoint. Verifies HMAC-SHA512 signature before processing. Updates order on charge.success event.
Response
200 OK
Coupons
POST
/api/v1/coupons/validate
Public
Validate a coupon code against the cart total. Check expiry, usage limits, and per-user limits.
Request Body
{ "code": "WELCOME10", "cart_total": 1500 }
Response
{ "success": true, "data": { "valid": true, "code": "WELCOME10", "type": "percentage", "value": 10, "discount": 150 } }
Possible Errors
| Code | HTTP | When |
|---|---|---|
| COUPON_INVALID | 422 | Invalid, inactive, or exceeded |
| COUPON_EXPIRED | 422 | Past expiry date |