daraja 0.2.0 copy "daraja: ^0.2.0" to clipboard
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

  • Daraja takes an optional appwriteClient. Pass your signed-in Appwrite Client for per-user document isolation; omit it for public mode (read("any")).
  • userId on stkPush() / b2cPush() is now optional. Passing it without an authenticated client throws — that combination silently never resolves.
  • DarajaClient.initiateB2c() returns the response OriginatorConversationID and no longer takes a client-generated one.

Fixed

  • The Appwrite Function read a non-existent APPWRITE_API_KEY and returned 500 on every callback. It now reads the dynamic key from the x-appwrite-key header (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 appwriteClient change 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.baseUrlOverride for 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 the dart-3.11 runtime 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 — mirrors restorePendingPayment().
  • Added Daraja.disbursementStream for a global B2C state listener, consistent with Daraja.stream for STK Push.
  • B2C lifecycle (Realtime subscription, polling at T+15s/T+45s/T+75s, T+90s timeout, SharedPreferences persistence) extracted into DisbursementNotifier.
  • Added == and hashCode to all PaymentState and DisbursementState subclasses.
  • 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.dart minimal Flutter example for pub.dev scoring.
  • Added B2C disbursement support: Daraja.b2cPush(), DisbursementState sealed class, B2cCommandId, SecurityCredential.

0.1.0 — 2026-03-31 #

Initial release.

Core package

  • Daraja — public entry point. stkPush() returns a Stream<PaymentState> that closes on terminal state. restorePendingPayment() recovers any session killed before the payment resolved.
  • DarajaConfig — typed config with DarajaEnvironment.sandbox / production toggle.
  • 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. WidgetsBindingObserver for foreground-resume polling. Timeout cascade at T+10, T+30, T+70 seconds. Hard cutoff at T+90 → PaymentTimeout. SharedPreferences persistence for killed-app recovery.

Appwrite Function (function/)

  • Dart runtime callback handler. Parses Safaricom STK Push callback, writes result document to Appwrite Database. Uses documentId = checkoutRequestId for idempotent duplicate handling. Returns ResultCode: 0 unconditionally 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.
0
likes
150
points
188
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

M-Pesa STK Push and B2C disbursements for Flutter — initiation, real-time callback delivery, timeout handling, and killed-app recovery. Backed by Appwrite.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

appwrite, clock, encrypt, flutter, flutter_riverpod, http, meta, pointycastle, shared_preferences

More

Packages that depend on daraja