M-Pesa Express (STK Push)
M-Pesa Express, commonly called STK Push, sends a payment prompt to a customer’s phone. They confirm with their M-Pesa PIN and the money lands in your short code.
Push a prompt
Section titled “Push a prompt”use Starnerz\LaravelDaraja\Facades\Daraja;
$response = Daraja::stk()->push( phone: '0712345678', amount: 1500, accountReference: 'INV-001', description: 'Invoice 001',);
$response->accepted(); // true — the prompt was sent$response->checkoutRequestId; // keep this; it identifies the attempt$response->merchantRequestId;$response->customerMessage;Any Kenyan format works for phone — 0712345678, +254712345678,
254712345678, even with spaces or dashes. Invalid numbers raise a
DarajaException before a request is sent.
Field limits
Section titled “Field limits”| Field | Limit |
|---|---|
accountReference |
12 characters — shown to the customer in the prompt |
description |
13 characters, defaults to the account reference |
amount |
KES 1 to 250,000, rounded to whole shillings |
Buy Goods
Section titled “Buy Goods”For a till, the short code and the credit party are different numbers:
BusinessShortCode is your HO or store number, PartyB is the till.
use Starnerz\LaravelDaraja\Enums\TransactionType;
Daraja::stk()->push( phone: '0712345678', amount: 500, accountReference: 'ORDER-9', type: TransactionType::BuyGoods, partyB: '5678901', // the till number);Omit partyB and it defaults to the short code, which is correct for Pay Bill
and wrong for Buy Goods.
Query a push
Section titled “Query a push”$status = Daraja::stk()->query($response->checkoutRequestId);
$status->paid(); // ResultCode 0$status->cancelledByUser(); // ResultCode 1032$status->resultDescription;Use this as a fallback when a callback never arrives, not as a polling loop.
The callback
Section titled “The callback”use Starnerz\LaravelDaraja\Events\StkCallbackReceived;
class RecordPayment{ public function handle(StkCallbackReceived $event): void { $callback = $event->callback;
if (! $callback->successful()) { return; }
Order::where('checkout_request_id', $callback->checkoutRequestId) ->update([ 'mpesa_receipt' => $callback->receipt(), 'amount_paid' => $callback->amount(), 'paid_at' => now(), ]); }}CallbackMetadata is absent entirely when the payment fails, so amount() and
receipt() return empty values rather than throwing.
On success it is a list of {Name, Value} items — but not every item has a
Value. Sandbox returns {"Name": "Balance"} with the key omitted altogether,
so code doing $item['Value'] on each entry raises an undefined-key error. The
package reads them through ResultParameters, which returns null for a
missing value and leaves the surrounding items intact.
| Result code | Meaning |
|---|---|
0 |
Paid |
1032 |
Cancelled by the user, or the prompt timed out |
1037 |
Prompt never reached the handset |
1031 |
User did not enter a PIN in time |
2001 |
Wrong M-Pesa PIN |
1001 |
Another session is already open for that number |
Reversing
Section titled “Reversing”Unlike B2C, M-Pesa Express transactions can be reversed through the Reversal API.