Point the SDK at the sandbox
The environment is a config value, not a code path — one integration serves testing and production:
In the sandbox the sheet shows a SANDBOX pill in its header, so a build
pointed at the wrong environment is visible at a glance. Your backend must
use its sandbox credentials against the sandbox REST host — sandbox HMAC keys
are rejected by production and vice versa (see
Environments).
Scanning without a camera
Simulators and emulators have no usable camera. The sheet detects this and swaps the viewport for the paste-QR fallback automatically — paste any VietQR/EMVCo payload string and the flow proceeds identically, because the backend does the authoritative parse (CRC, tags, merchant extraction) either way. The same fallback appears on real devices when the user denies camera access, so the flow is always completable.The loops to run
1
Sandbox end-to-end
Run the sandbox config with a session from your sandbox backend and a
real VietQR payload (paste-QR works fine). The payout runs on the sandbox
rail and the intent reaches
captured — assert your completed handling
debits your ledger and renders the receipt, and that your
webhook endpoint received
payment_intent.captured.2
Fail-fast token checks
Pass a blank or mismatched session token and assert an immediate
failed
with invalid_jwt / intent_mismatch — the SDK validates the token’s
structure, expiry, and intent binding before showing any UI.3
Session expiry mid-flow
Let a session token lapse inside the sheet (its
session_expires_at passes);
your refreshSession hook should re-mint for the same intent via
POST /v1/payment_intents/:id/session and the flow should continue without
the user noticing.4
A limit-blocked payment
Per-user corridor limits are enforced against the
same windows in sandbox. Drive a payment over the per-transaction limit
and assert the sheet renders the limit copy and your app receives
failed with limit_exceeded.5
Pending and reconciliation
If status polling times out, the result is
pending (Flutter and React
Native) or failed with timed_out (iOS and Android) — the payment may
still settle. Verify you reconcile via the webhook or
GET /v1/payment_intents/:id rather than assuming a terminal failure.Before release: a physical device
Camera scanning, the torch and gallery fallbacks, and the runtime permission prompt (Android) can only be exercised for real on hardware — that’s the pre-release checklist on every platform guide.Next steps
Environments
Base URLs and how keys map to sandbox vs production.
Webhooks
Verify signatures and reconcile terminal states.
Per-user limits
The corridor limits enforced in both environments.
Authentication
The HMAC signing spec and the session-token contract.