Requirements
- React Native 0.73+ or Expo SDK 50+
react-native-webview>= 13react-native-safe-area-context>= 4
Expo Go can preview the sheet and hosted eSewa/Khalti screens. Native QR
sharing and reliable installed-app detection require the config plugin and a
development build. Expo Go cannot apply native app-query configuration.
Installation
app.json
A bare React Native app without Expo adds the same entries by hand. Without the
iOS photo text, leave
allowSaveToPhotos off: iOS ends an app that saves a
photo without it.
How it works
Your backend creates an amount-bound session using your secret API key. Your app receives that short-lived session and uses a publishable key to present the server-approved methods. Your secret API key never touches the device.Payment sheet (recommended)
The sheet shows whichever payment methods the merchant has on. Your app never picks a provider or builds payment screens, so turning a method on is a dashboard change, not an app release.
A merchant with Fonepay: Bank App (detected apps only), Fonepay QR, eSewa, Khalti.

The same sheet for a merchant without Fonepay bank-app access: Fonepay QR, eSewa, Khalti.
1. Your backend creates a session
Session creation requires thepayments:write scope when your secret key has an explicit scope list. Unrestricted secret keys continue to work. The app uses a publishable key and the session client secret for the device calls.
Call POST /v1/mobile/session with your secret key and no provider:
methods comes from the server, based on the merchant’s providers, mode and
plan. Payment limits are checked again when the buyer picks a method.
If a supported bank app is installed, Bank App comes before Fonepay QR. One
bank opens directly; several show a short picker.
Return session_id and client_secret to your app. Do not send your secret
key to the device.
Use one Idempotency-Key per order, so a retry returns the same session
instead of a second one.
2. Your app presents the sheet
The app uses your publishable key (safe to ship) and the session’s client
secret, which works for that one session only. After the session expires, the
secret cannot start a payment but can still read the status, so keep it in
secure storage and out of logs.
How each method behaves

Bank App lists only the bank apps installed on the device.

Fonepay QR renders natively with a countdown and one QR button: Save QR where the phone can save, otherwise Share QR.
Confirming a payment
onComplete reports a confirmed success, or expired when no payment is
still pending; otherwise the sheet keeps checking. While the hook stays mounted,
each session reports once, and reopening a reported session closes the sheet
without another callback (after an app restart it may report again). A failed
or cancelled attempt goes back to the method picker when it is safe to retry.
After returning from an app or timing out, the buyer can check the status by
hand.
A buyer can close the bank app after paying, so fulfil orders from the
payment.succeeded webhook, as on web.

The demo app after onComplete: the sheet heard success, the server's webhook is still the final word.
App restart recovery
The SDK does not store the session for you. Save it in secure storage and callresume(session) when your checkout screen comes back. Clear it when
onComplete reports success, or when onComplete or onCancel reports
paymentPending: false. While paymentPending is true,
keep it: the buyer may have paid in their bank app, and resuming shows the
result instead of starting a second payment. On Android, initialise callbacks during
lifecycle setup; do not rely on in-memory checkout variables.
usePaymentSheet(options)
Returns
{ present, resume, dismiss, isVisible, loading, paymentSheetProps }.
Theming
appearance accepts tokens only: colors, radius, typography and the primary
button. Light and dark are both supported. Layout is deliberately not
overridable so the sheet stays upgradeable.
Usage (legacy usePayBridgeNP)
usePayBridgeNP hook (recommended)
Let the user pick the provider - session is created lazily after they tap.
Pre-built session
Use this when your backend picks the provider before showing the sheet.ProviderSheet directly
API reference
usePayBridgeNP(options)
Returns
{ present, dismiss, isVisible, sheetProps }.
Pass either
session or createSession - not both. createSession is preferred as it defers session creation until the user has picked a provider.ProviderSheet props
Same options as usePayBridgeNP, plus visible: boolean.
PayBridgeNPMobileConfig
PayBridgeMobileConfig is still exported as a deprecated alias, so existing imports keep compiling.
CheckoutResult
MobileSession
Sandbox testing
Create the session with ask_test_... key and the sheet runs in test mode. eSewa and Khalti need no setup: buyers sign in with the test accounts below. Fonepay has no test environment.
eSewa (sandbox, rc-epay.esewa.com.np)
Khalti (test checkout,
test-pay.khalti.com)
Khalti’s test wallets are shared by everyone.
9800000001 to 9800000004 are often drained; errors like “insufficient balance” come from Khalti’s sandbox, not your integration.
Fonepay (no sandbox, real money)
The sandbox testing guide walks through the same flow on the hosted checkout page.