ViewModel-driven flow, your own
“Pay” button — instead of rendering a prebuilt SDK button component. The single public
payment trigger is PayrailsPaymentLauncher:
you draw the controls, the SDK owns the post-tap work (Google Pay sheet, 3DS / PayPal /
redirect Custom Tab, polling).
There is no publicSession.authorize(...). Payment execution is launcher-only, so a singleauthorize(...)call handles both frictionless and 3DS outcomes — you never branch on whether a charge will need a step-up. See Custom UI: the launcher and the internal client.
Prerequisites
- An active Payrails session (see Quick Start) — hold the
Sessionreturned byPayrails.createSession(...). - A
ComponentActivityhost. The launcher is lifecycle-bound; it cannot live in a bareViewModel(it registers a Google Pay Activity Result contract), but yourViewModelcan drive when it fires. - For stored-instrument payments: at least one saved instrument (see How to Tokenize a Card).
Steps
1. Create the launcher early
Construct it inonCreate (or a Compose remember) so its Activity Result contract registers
before the host is STARTED:
2. Charge a stored instrument from your own UI
The most common headless case — no SDK button, your own list:3. Charge a fresh card you encrypted yourself
If you collect and encrypt card data with the client-side encryption library, pass the already-encrypted string. The SDK exposes no encryption API, and raw card fields never cross this call:4. Trigger other methods by type
5. Handle the result
Everyauthorize(...) resolves to exactly one
ActionResult, delivered to the callback from step 1:
Full example — stored-instrument checkout driven from a ViewModel
TheViewModel owns selection and state; the activity owns the launcher and fires it:
Troubleshooting
Problem: The launcher throws when created Solution:Payrails.createPaymentLauncher(...) must be called from Activity.onCreate
(or rememberPayrailsPaymentLauncher during composition). Registering the Google Pay Activity
Result contract after the activity is STARTED is not allowed by the Android Activity Result API.
Problem: ActionResult.Failed with code == UNKNOWN_ERROR (rawError sdkNotInitialized)
Solution: The session was destroyed or replaced (for example a newer createSession()
superseded it). Obtain a fresh Session from Payrails.createSession().
Problem: ActionResult.Failed with code == UNKNOWN_ERROR (rawError unsupportedPayment)
Solution: The payment method is not configured on the session. Call
session.getPaymentMethodConfig()
to confirm what is available before triggering.
See also
- How to Build a Custom Pay Button — the launcher with a method picker + single button
PayrailsPaymentLauncherAPI Reference — all factories,authorize(...)overloads, and parametersActionResultAPI Reference — every terminal payment outcome- How to Tokenize a Card — save a card, then charge it from your own UI
- Custom UI: the launcher and the internal client — why payment execution is launcher-only