daraja 0.2.0
daraja: ^0.2.0 copied to clipboard
M-Pesa STK Push and B2C disbursements for Flutter — initiation, real-time callback delivery, timeout handling, and killed-app recovery. Backed by Appwrite.
Changelog #
0.2.0 — 2026-06-21 #
Backend and permission fixes verified end to end against a live Appwrite project (1.9.5) and the Daraja sandbox. Under the previous release, no payment result reached the UI; these are the fixes that make it work.
Breaking
Darajatakes an optionalappwriteClient. Pass your signed-in AppwriteClientfor per-user document isolation; omit it for public mode (read("any")).userIdonstkPush()/b2cPush()is now optional. Passing it without an authenticated client throws — that combination silently never resolves.DarajaClient.initiateB2c()returns the responseOriginatorConversationIDand no longer takes a client-generated one.
Fixed
- The Appwrite Function read a non-existent
APPWRITE_API_KEYand returned 500 on every callback. It now reads the dynamic key from thex-appwrite-keyheader (Appwrite 1.7+). - Per-user documents were unreadable by the package's unauthenticated client, so every payment timed out; this is what the two-mode
appwriteClientchange above fixes. - B2C tracked a client-generated
OriginatorConversationID, but Safaricom assigns its own and uses it in the callback, so disbursements never resolved. Now keyed on the response value, with the subscription opening after initiation (mirrors STK Push).
Added
DarajaConfig.baseUrlOverridefor integration testing against a local Daraja emulator (Pesa Playground).
Docs
- Documented the function's required scopes (
databases.read,documents.read,documents.write), the execute-access-needs-redeploy behaviour, and thedart-3.11runtime floor — each of which otherwise drops every callback silently. - README cut to orientation plus the minimum correct path.
0.1.2 — 2026-05-11 #
- Fixed B2C API endpoint (
/v3/→/v1/). - Added
Daraja.restorePendingDisbursement()for killed-app recovery on B2C — mirrorsrestorePendingPayment(). - Added
Daraja.disbursementStreamfor a global B2C state listener, consistent withDaraja.streamfor STK Push. - B2C lifecycle (Realtime subscription, polling at T+15s/T+45s/T+75s, T+90s timeout, SharedPreferences persistence) extracted into
DisbursementNotifier. - Added
==andhashCodeto allPaymentStateandDisbursementStatesubclasses. - Replaced null-bang env var access in the Appwrite Function with a throwing
_env()helper.
0.1.1 — 2026-04-06 #
- Added dartdoc comments across all public API elements (exceeds pub.dev 20% threshold).
- Added
example/lib/main.dartminimal Flutter example for pub.dev scoring. - Added B2C disbursement support:
Daraja.b2cPush(),DisbursementStatesealed class,B2cCommandId,SecurityCredential.
0.1.0 — 2026-03-31 #
Initial release.
Core package
Daraja— public entry point.stkPush()returns aStream<PaymentState>that closes on terminal state.restorePendingPayment()recovers any session killed before the payment resolved.DarajaConfig— typed config withDarajaEnvironment.sandbox/productiontoggle.PaymentState— sealed class with 8 states:PaymentIdle,PaymentInitiating,PaymentPending,PaymentSuccess,PaymentFailed,PaymentCancelled,PaymentTimeout,PaymentError.DarajaClient— direct HTTP to Safaricom. OAuth with in-memory token cache (60-second buffer). EAT password generation. Phone normalisation for all six Kenyan formats.PaymentSubscription— Appwrite Realtime subscription on a single document channel. Database poll fallback on reconnection.PaymentNotifier— orchestrates the full flow.WidgetsBindingObserverfor foreground-resume polling. Timeout cascade at T+10, T+30, T+70 seconds. Hard cutoff at T+90 →PaymentTimeout.SharedPreferencespersistence for killed-app recovery.
Appwrite Function (function/)
- Dart runtime callback handler. Parses Safaricom STK Push callback, writes result document to Appwrite Database. Uses
documentId = checkoutRequestIdfor idempotent duplicate handling. ReturnsResultCode: 0unconditionally so Safaricom stops retrying.
Demo (example/chama/)
- Split-bill chama app demonstrating concurrent per-member payments, shared pot aggregation, all terminal state variants, and killed-app recovery.