zennopay_flutter brings the PaymentSheet to Flutter with
the same shape as Stripe’s Flutter SDK: one await Zennopay.presentSheet(...)
and the terminal outcome is the resolved value. The sheet renders the full pay
experience — QR scan → amount + FX quote → slide-to-pay → result — and your
app never leaves the foreground.

The PaymentSheet, end to end, presented from the sample wallet app.
Requirements
- Flutter 3.19+ / Dart 3.4+
- iOS and Android targets (the sheet uses the device camera via
mobile_scanner) - A backend session endpoint that creates the intent and returns the Zennopay-minted session token
Install
Platform setup
The scanner uses the camera; add the platform declarations: iOS —ios/Runner/Info.plist:
CAMERA permission; nothing
to add. On denial (or no camera), the sheet falls back to a paste-QR field on
both platforms.
Configure
The environment is a config value, not a code path:Already shipped on
zennopay.in? Nothing to do. Previously published SDK
versions resolve sandbox / production to the api.zennopay.in hosts, and
those hosts continue to be served — same API, same credentials. You do not
need to ship an app update to stay working. See
Environments.Present the PaymentSheet
With a checkout session from your backend in hand, your app awaits one call:Handle the result
Flutter promotespending to a first-class case, and Completed/Pending
carry an optional Receipt:
Pendingmeans status polling timed out before a terminal state — the payment may still settle. Show a soft state and reconcile via your webhook or transaction history.Failedcarries a typedZennopayErrorwith a stableZennopayErrorCode(invalidJwt,intentMismatch,jwtExpired,quoteExpired,limitExceeded,networkError, …).
Customize appearance
ZennopayAppearance themes the sheet — colors (with per-mode dark variants),
corner radii, typography, primary button, and an optional header logo:
const ZennopayAppearance.automatic()) for the default Zennopay
look with system light/dark. Structural rules are not overridable — radii are
clamped to ≤ 12, amounts render in tabular figures, and the accent is reserved
for state.
Analytics hook
presentSheet accepts an optional onEvent callback with a small,
privacy-safe event stream (sheet_presented, scan_validated,
slide_committed, confirm_result, …) you can forward to your own analytics:
Test
- Simulator/emulator: no usable camera — use the sheet’s paste-QR fallback with any VietQR payload string; the backend does the authoritative parse.
- Sandbox end-to-end:
ZennopayConfig.sandbox+ a session from your sandbox backend drives the flow to a realcapturedon the sandbox payout rail. - Fail-fast checks: a blank or mismatched session token resolves immediately
with
Failed(invalidJwt/intentMismatch) before any UI is shown.
Next steps
Build your session endpoint
The one backend route the sheet needs.
Test your integration
The sandbox loops to run before release.
Webhooks
Reconcile terminal states server-side.
Per-user limits
The corridor limits Zennopay enforces for you.