Authentication required All requests must include the header X-API-Token: <token>. Missing or invalid tokens return 401 Unauthorized.

Endpoints

Two endpoints — trigger a payment prompt, then poll for the result.

POST /api/stk-push Trigger STK Push

Sends an M-Pesa PIN prompt to the customer's phone. When QUEUE_CONNECTION=sync the full record is returned immediately (200). With a real queue driver only the tracking_id is returned (202).

FieldTypeDescription
phonestringrequiredAccepts 07xx, 254xx, or +254xx
amountintegerrequiredAmount in KES, minimum 1
referencestringrequiredAccount reference shown to the customer
tagstringoptionalInternal label, not shown to customer

Request

{
  "phone": "0712345678",
  "amount": 1500,
  "reference": "INV-2024-001",
  "tag": "loan-repayment"
}

200 — Sync (full record)

{
  "success": true,
  "data": {
    "id": 1,
    "tracking_id": "550e8400-...",
    "status": 0,
    "status_label": "Pending",
    "response_code": null,
    "transaction_code": null,
    ...
  }
}

In async mode the response is 202 with only { "success": true, "tracking_id": "...", "message": "..." }. Use the tracking_id to poll below.

GET /api/stk-push/{tracking_id} Check Payment Status

Returns the full STK Push record. Poll every 10 seconds until status is 1. Payment confirmation from Safaricom typically arrives within 10–60 seconds.

200 — Success

{
  "success": true,
  "data": {
    "tracking_id": "550e8400-...",
    "phone_number": "254712345678",
    "amount": "1500",
    "reference": "INV-2024-001",
    "transaction_code": "RBC12ABC34",
    "status": 1,
    "status_label": "Success",
    "response_code": "0",
    "meta": {
      "transaction_date": "2024-03-21 14:30:55"
    }
  }
}

200 — Pending

{
  "success": true,
  "data": {
    "tracking_id": "550e8400-...",
    "status": 0,
    "status_label": "Pending",
    "response_code": null,
    "transaction_code": null,
    ...
  }
}

404 — Not Found

{
  "success": false,
  "message": "Record not found."
}

A 404 immediately after triggering is normal in async mode — the job may not have run yet. Retry after a few seconds.

ANY /hooks/stk-push Safaricom Callback

Receives async payment results from Safaricom. This endpoint is public, CSRF-exempt, and should not be called directly. It updates the STK Push record and sets status, response_code, and transaction_code.

Payment Status Reference

Returned in status_label after Safaricom's callback is received.

Pending

status=0, response_code=null

Prompt sent, awaiting customer PIN.

Success

status=1, response_code=0

Payment confirmed. Check transaction_code for the M-Pesa receipt.

Cancelled by User

status=1, response_code=1032

Customer dismissed the PIN dialog.

Insufficient Balance

status=1, response_code=1

Customer's M-Pesa balance was too low.

Timed Out

status=1, response_code=1037

Customer did not respond within the timeout window.

Transaction Expired

status=1, response_code=1019

STK request expired before the customer acted.

Phone Number Formats

All formats are normalised to 254XXXXXXXXX automatically.

Local format

07XXXXXXXX

254XXXXXXXXX

International

254XXXXXXXXX

254XXXXXXXXX

With plus prefix

+254XXXXXXXXX

254XXXXXXXXX