M-Pesa Reconciliation
M-Pesa callbacks can be missed due to network issues, server downtime, or Safaricom delays. The reconciliation system ensures no payment is lost.
Three Recovery Mechanisms
flowchart TB
subgraph "1. Transaction Status Query"
A["Merchant notices missing callback"] --> B["POST /v1/payments/mpesa/check-status/{code}"]
B --> C["Daraja sends result to callback URL"]
C --> D["DB updated + merchant webhook sent"]
end
subgraph "2. Manual Reconciliation"
E["Merchant triggers"] --> F["POST /v1/payments/mpesa/reconcile"]
F --> G["Pull last 2h of transactions from Daraja"]
G --> H["Sync pending → completed"]
end
subgraph "3. Automatic Reconciliation"
I["ARQ cron every 15 min"] --> J["Pull last 2h from Daraja"]
J --> K["Auto-sync missed transactions"]
end
1. Transaction Status Query
For a specific transaction where you have the M-Pesa receipt number:
This is async — Daraja sends the result to your configured result_url. The response only confirms the query was accepted.
2. Manual Reconciliation
Pull all missed transactions at once:
One-time setup
Register once
This registers your shortcode with Daraja's Pull API. Only needs to be done once.
Trigger reconciliation
Response
| Field | Meaning |
|---|---|
synced |
Transactions updated from pending → completed |
skipped |
Already completed in our DB |
not_found |
In Daraja but not in our DB (different shortcode usage) |
3. Automatic Reconciliation
An ARQ cron job runs every 15 minutes automatically:
- Pulls the last 2 hours of transactions from Daraja
- Compares against our DB
- Updates any
pendingtransactions tocompleted - Enqueues
payment.completedwebhooks with"reconciled": trueflag
No action needed from the merchant — this runs in the background.
Reconciled Webhook Payload
When a transaction is synced via reconciliation, the outbound webhook includes a reconciled flag:
{
"type": "payment.completed",
"data": {
"payment_id": "txn-uuid-...",
"amount": "500",
"currency": "KES",
"provider": "mpesa",
"status": "completed",
"previous_status": "pending",
"receipt_no": "NEF61H8J60",
"reconciled": true
}
}
When to Use What
| Scenario | Mechanism |
|---|---|
| Single missing callback | Transaction Status Query |
| Server was down for a while | Manual Reconciliation |
| Ongoing safety net | Automatic (runs by itself) |