Skip to main content
Looking for guides? Quick Start | Styling Guide | Troubleshooting | SDK Concepts

Table of Contents

  • Getting Started
  • Custom UI Payment Launcher
  • Core Concepts
  • Logging
  • Card Payments
  • Card Tokenization
  • Co-Branded Cards
  • Google Pay
  • Redirect Payments
  • Stored Instruments
  • Results and Errors

Compatibility Requirements

  • JDK 17
  • Android minSdk 21
  • Android compileSdk 35

Public Artifact

  • Distributed via Maven Central
  • Maven coordinate: com.payrails.android:checkout:<version>
  • Additional dependency: com.payrails.android:cse:<version>

Getting Started

Create a Session

Use a Configuration built from InitData plus optional Options. Kotlin
Java
To enable automatic SDK-managed recovery when a redirect flow is abandoned or remains non-terminal, pass onSessionExpired in Options.redirectSessionLifecycle:

Session-Scoped Helpers

Session is the merchant’s handle to all runtime SDK operations. Keep the reference returned by createSession(...) and call query/update/instrument/payment methods on it directly.
Breaking change: Payrails.getCurrentSession() is not part of the public API. Hold the Session returned by createSession(...) — methods like query, update, getStoredInstruments, deleteInstrument, updateInstrument, and getPaymentMethodConfig now live on Session. (Payment execution is not on Session; use PayrailsPaymentLauncher.)

Querying Session Data

Use Session.query() to read data from the active session.

Session.query(key)

Returns the value for key from the session, or null if the requested data is not present. Never throws. Example

PayrailsQuery<T>

Sealed class of typed query keys for Session.query(), in package com.payrails.sdk.
RemovedPayrailsQuery.AvailableRedirectMethods. Use Session.getPaymentMethodConfig(PaymentMethodFilter.Redirect) instead.

PayrailsAmount

Represents the current checkout amount. value is the amount in wire format (e.g. "54.99"), consistent with AmountUpdate.value. currency is the ISO 4217 code (e.g. "EUR").
A backend action link. href is the URL to call; method is the HTTP method (e.g. "POST", "DELETE"). Either field may be null if not provided by the backend.

PayrailsPaymentMethodConfig

Configuration for a payment method from the active session. All fields except paymentMethodCode are optional and sourced from the session payload.

Updating Session State

Use Session.update() to change the checkout amount after createSession() has completed, without reinitialising the session.

Session.update(changes)

Updates in-memory session state. No network request is made. The updated values take effect on the next pay() call. Throws Example

PayrailsUpdate

Container for session updates passed to Session.update(), in package com.payrails.sdk. Each field is optional — null means “leave unchanged”. Additional fields may be added in future SDK versions without breaking existing call sites.

Session Payment APIs

Session exposes a Google Pay capability check. Payment execution is not on Session — it is public only via PayrailsPaymentLauncher.

Session.isGooglePayAvailable(context)

Returns true when Google Pay is configured for the session and the device reports isReadyToPay() == true. Does not require a GooglePayButton to be rendered.

Executing a payment

Session exposes no public payment trigger. Payment execution is a public API only through PayrailsPaymentLauncher.authorize(...), which owns the Activity, the Google Pay sheet, and the 3DS / redirect Custom Tab, and handles frictionless and step-up (3DS) outcomes uniformly. The SDK button components and the launcher delegate into Session’s internal networking; merchants do not call it directly. The terminal outcome of any authorize(...) is the public ActionResult type.

ActionResult

AuthorizationFailure

Session.getPaymentMethodConfig(filter)

Returns the payment method options configured for the active session, filtered by the supplied PaymentMethodFilter. Returns an empty list when no options match (never null).

PaymentMethodFilter

Example

AmountUpdate

Represents a new checkout amount. Both fields are required when updating the amount.
Note on value formatThe SDK validates that value is parseable as a positive number but does not reformat it. Pass the string in the exact format expected by your backend (for example, "49.99", not "4999").

Custom UI Payment Launcher

PayrailsPaymentLauncher lets you run a complete payment flow from your own button while the SDK owns the post-tap work — opening the Google Pay sheet, the 3DS / PayPal / redirect Custom Tab, and the polling. It is the public “bring-your-own-button” entry point — and the only public way to execute a payment.

PayrailsPaymentLauncher

Construct it with one of the factory functions below — never directly. Each pay(...) call resolves to exactly one terminal ActionResult, delivered to the onResult callback supplied at construction (user dismissal of the sheet or Custom Tab is reported as Failed with code == USER_CANCELLED).

rememberPayrailsPaymentLauncher(session, onResult)

Compose factory. Returns a launcher that is stable across recompositions and registers the Google Pay Activity Result contract for the current activity. Call it during composition (e.g. at the top of your checkout composable).

Payrails.createPaymentLauncher(activity, session, onResult)

View / Activity factory. Must be called from Activity.onCreate — it registers a Google Pay Activity Result contract, and the Android Activity Result API forbids registration after the activity is STARTED (calling it later throws). Example (Compose)
See How to Build a Custom Pay Button for a full dropdown-plus-single-button walkthrough.

Core Concepts

Payment Methods

PaymentMethod supports:
  • PaymentMethod.card
  • PaymentMethod.googlePay
  • PaymentMethod.payPal
  • PaymentMethod.genericRedirect
Card, Google Pay, and generic redirect flows are creatable via Payrails factories.

Options

Options configures SDK behavior:
  • env: Env — Env.PRODUCTION (default) or Env.TEST
  • collectMetadata: Boolean — whether the SDK collects client context metadata (default true)
  • redirectSessionLifecycle: RedirectSessionLifecycle — configures automatic session recovery
  • onRequestStart: RequestStartHandler? — optional gate awaited before every authorization (default null)

Pre-authorization gate (onRequestStart)

Optional handler invoked once per payment attempt, before the authorization request is sent and before any provider UI (wallet sheet, redirect Custom Tab) is presented. RequestStartDecision.Proceed lets the attempt continue; RequestStartDecision.Refuse stops it. For Google Pay the handler is consulted the moment the button is tapped, before the Google Pay sheet opens — so a refusal means the customer never sees the sheet, and the handler runs before they have chosen a card. A check that depends on the basket (voucher, wallet balance, loyalty points) is unaffected; one that depends on the chosen card is not possible here.
Refuse.message, when supplied, becomes AuthorizationFailure.message on the delivered VALIDATION_FAILED. It is passed through verbatim and is not displayed by the SDK. The gate fires for every payment method configured on the session. A handler that only gates one method must return Proceed on the other branches. Action.TOKENIZE is reserved: the tokenization flow is not gated in this version, so action is always AUTHORIZE today. The timeout and throw cases do not carry the SDK’s diagnostic into failure.message: both describe an integration fault rather than something phrased for a customer, and an exception string may carry internals. Only a deliberate Refuse(message) travels outward. When the attempt is stopped, no authorization request is sent, the initiating button returns to ButtonState.ENABLED, and its delegate receives onAuthorizeFailed(button, failure) with failure.code == VALIDATION_FAILED. Invoked on a background dispatcher, not the main thread — a suspending handler can make its network call directly, and anything touching UI must switch context itself. The 10-second bound can only interrupt a handler that suspends; one that blocks its thread runs to completion regardless, since coroutine cancellation is cooperative. Omitting the handler leaves the payment path fully synchronous — the SDK skips the gate rather than taking an asynchronous detour. A Kotlin-only API, like onSessionExpired: suspend functions are not implementable from Java. See How to gate payment authorization.

Redirect Session Lifecycle (onSessionExpired)

onSessionExpired is configured once through Options.redirectSessionLifecycle and is shared for redirect-capable flows (3DS now, other redirect methods in future). The callback should run the merchant client-init call and return fresh InitData. Behavior:
  • Triggered when redirect reconciliation is classified as abandoned or stuck non-terminal.
  • If callback is configured and succeeds, SDK refreshes active session/execution state automatically.
  • If callback is missing/fails/returns invalid data, SDK does not continue the stale execution.
  • Current payment attempt still resolves through standard failure handling (the Failed path).

Client Context Metadata

The SDK collects client context and attaches it to authorize requests under meta.clientContext by default. Collected fields:
  • osType (android)
  • userAgent
  • acceptHeader
  • language
  • screenHeight
  • screenWidth
  • colorDepth
  • timeZoneOffset
  • javaEnabled
  • javaScriptEnabled
Opt-out:

Request Headers

The SDK attaches the following headers to every API request: The x-client-version value is generated at build time from gradle.properties (sdk.version) and compiled into the SDK as an internal constant. Merchants do not need to configure it.

Logging

The SDK uses an internal logging system with two output channels:
  • In-memory log store — Always active. The SDK maintains an in-memory buffer of the last 500 log entries (with timestamps). This is used by the built-in debug viewer (DebugManager).
  • Logcat — Suppressed by default. Logcat output under the tag PayrailsSDK is gated behind Log.isLoggable(), so it produces no Logcat output unless explicitly enabled.

Enabling Logcat Output

To enable SDK debug logs in Logcat, run:
This persists until the device reboots. After enabling, filter Logcat by the PayrailsSDK tag:
To disable again:

Default State

Security

The SDK never logs raw card data, tokens, or PII through its logging system. Log messages contain only operational information (e.g., payment flow steps, error descriptions).

Card Payments

CardForm + CardPaymentButton

Create a CardForm, then a CardPaymentButton. Elements are decoupled and composed explicitly.
Kotlin/Compose onlyElement creation and Render() calls require Kotlin and Jetpack Compose. The delegate callbacks below are Java-compatible.
Kotlin
Java — setting the delegate
Order does not matter. If CardPaymentButton is created before CardForm, creating CardForm later will auto-attach it to the current button (web-sdk-aligned behavior). Behavior model (aligned with web-sdk):
  • Form mode: if no stored instrument is selected, the button validates/collects card form data, then authorizes.
  • Stored-instrument mode: if a stored instrument is selected, the button authorizes with that instrument and bypasses card form collection/validation.
  • Form interaction reset: if the user focuses/edits card fields, the selected stored instrument is cleared and button behavior returns to form mode.
  • Guardrail: if no stored instrument is selected and no card form is attached, payment does not proceed and the button emits authorization failure.
3DS redirect behavior:
  • The SDK opens 3DS URLs in a Custom Tab when available, falling back to the system browser.
  • On app return, the SDK polls execution status until terminal success/failure or expiry classification.
  • If status remains non-terminal through reconciliation window, SDK emits authorization failure and runs onSessionExpired callback (if configured).
  • On terminal success/failure, SDK performs best-effort Custom Tab close/return-to-app handling.
  • Avoid using WebView for 3DS challenge pages (issuer/ACS compatibility issues, reduced isolation, unreliable deep-link returns).

CardForm Configuration

CardFormConfig controls visibility and behavior:
  • showCardHolderName: Boolean
  • showStoreInstrumentCheckbox: Boolean
  • showSingleExpiryDateField: Boolean
  • layout: List<List<CardFieldType>>?
  • alwaysStoreInstrument: Boolean
  • defaultStoreInstrumentState: DefaultStoreInstrumentState (checked | unchecked)
  • events: CardFormEvents? (onFocus, onChange, onReady, onSaveInstrumentCheckboxChanged)
  • showCardIcon: Boolean (renders built-in Payrails network icons and default field icons)
  • cardIconAlignment: CardIconAlignment (left or right)
  • cardFieldIcons: CardFieldIcons? (custom icon URLs per field; overrides defaults when provided)
  • styles: CardFormStylesConfig?
  • translations: CardTranslations?
Use CardFormConfig.defaultConfig as a baseline. Payrails.createCardForm(...) reads save-instrument visibility only from CardFormConfig.showStoreInstrumentCheckbox; there is no separate standalone visibility argument on createCardForm(...). Migration rules:
  • defaultStoreInstrumentState defaults to unchecked. Visibility no longer implies a checked state.
  • alwaysStoreInstrument = true forces submission behavior to store the instrument regardless of toggle state.

Card Form Layout Options

CardFormConfig also supports label placement and field variant:
  • labelPlacement: LabelPlacement — FLOATING (default) or ABOVE. When ABOVE, labels render as separate Text composables above each field instead of floating inside the text field.
  • labelSpacing: Dp? — spacing between label and field when labelPlacement = ABOVE. Default: 4.dp.
  • fieldVariant: FieldVariant — OUTLINED (default) or FILLED. OUTLINED uses OutlinedTextField (full border); FILLED uses TextField (background fill with bottom indicator).

Card Form Styles

CardFormStylesConfig lets you style the wrapper, fields, labels, and errors. Key types:
  • CardWrapperStyle
  • CardFieldSpecificStyles
  • CardStyle (alias of Style)

Card Form Spacing Tokens

CardFormStylesConfig exposes spacing tokens that replace previously hardcoded layout values: All tokens are nullable. When null, the hardcoded default is used.

Card Translations

CardTranslations provides:
  • placeholders: CardTranslations.Placeholders
  • labels: CardTranslations.Labels
  • error: CardTranslations.ErrorMessages
Each map is keyed by CardFieldType (alias of ElementType).

Network-Aware State

The card form exposes network-aware metadata derived from the card number:
  • cardNetwork: CardNetwork (visa, mastercard, amex, discover, unknown)
  • bin: String (policy-driven: first 6 or 8 digits based on card network and PAN length; empty until sufficient digits are entered)
  • cvvMaxLength: Int
Field accessory behavior:
  • Card number: when showCardIcon is enabled, the SDK shows the detected network icon (e.g., Visa, Mastercard). When no network is detected, a default card icon is shown (ic-card.png). Card number does not switch to the clear affordance.
  • CVV: when showCardIcon is enabled, the field shows a default CVV icon (ic-cvv.png) while empty. When populated, it shows a clear affordance regardless of showCardIcon.
  • Expiry date: when showCardIcon is enabled, the field shows a default expiration icon (ic-expiration.png) while empty. When populated, it shows a clear affordance regardless of showCardIcon.
  • Split expiry month/year: when showCardIcon is enabled, both fields show the default expiration icon while empty. When populated, each field switches to a clear affordance independently regardless of showCardIcon.
  • Cardholder name: has no default empty-state icon, but still shows a clear affordance while populated regardless of showCardIcon. Merchants can add a custom empty-state icon via cardFieldIcons.cardholderName when showCardIcon is enabled.
All default icons are loaded from the Payrails assets CDN. Merchants can override any default icon — or add a cardholder name icon — by providing custom URLs via cardFieldIcons:
CardFieldIcons fields:
  • cardholderName: String? — custom icon URL for the empty cardholder name field when showCardIcon is enabled. No default icon exists; when populated, the field shows the clear affordance instead.
  • cardNumber: String? — custom icon URL for the card number field when no network is detected. Once a network is detected, the network icon takes precedence.
  • cvv: String? — custom empty-state icon URL for the CVV field when showCardIcon is enabled.
  • expiryDate: String? — custom empty-state icon URL for the expiration date field(s), including split expiry month/year fields, when showCardIcon is enabled.
Icon placement follows cardIconAlignment (left or right). BIN length policy (PCI SSC FAQ 1091 aligned):
  • 15-digit PANs (Amex): 6-digit BIN
  • 16-digit PANs (Visa/Mastercard/Discover): 8-digit BIN
  • 17–19 digit PANs or unknown networks: 6-digit BIN
Migration note: if your integration assumes a fixed 8-digit BIN, update routing/lookup logic to accept 6-digit BINs when provided. Do not infer or pad BIN length; rely on the SDK’s bin value.

Card Payment Button Translations

CardPaymenButtonTranslations(label: String?) sets the pay button text.

Card Payment Button Styling

Button appearance is configured on the button component (for example via createCardPaymentButton(buttonStyle = ...)). CardFormStylesConfig no longer includes button styling. Migration note: If you previously set CardFormStylesConfig.buttonStyle, move that styling to the button API (createCardPaymentButton(buttonStyle = ...)). Migration note: CardPaymentButton no longer exposes instrument-specific style/translation buckets. Keep one button settings surface and configure stored-instrument list/item UI in StoredInstrumentsStyle / StoredInstrumentsTranslations. CardButtonStyle is applied in CardPaymentButton.Render for:
  • backgroundColor, textColor
  • cornerRadius
  • borderWidth, borderColor
  • contentPadding
  • font
  • height, fillMaxWidth
  • disabledStyle, loadingStyle (state-variant styles)
  • loadingIndicatorColor
Additional design tokens: These tokens participate in state-variant merging (disabledStyle, loadingStyle).

Stored Instrument Card Button

Single instrument mapping:

Coupled Wrappers (Breaking Change)

  • CardPaymentForm has been removed from the element API.
  • StoredInstrumentPaymentButton has been removed. Use CardPaymentButton + setStoredInstrument(...).
  • The createCardPaymentButton(storedInstrument = ...) overload has been removed. Create the button first, then call setStoredInstrument(...).
  • createStoredInstruments() and createStoredInstrumentView() have been removed. Use session.getStoredInstruments() to retrieve instruments and CardPaymentButton.setStoredInstrument(...) to pay with them.
  • Migrate to explicit composition with CardForm + CardPaymentButton.

Card Tokenization

Save a card to the Payrails vault without initiating a payment. The tokenize flow encrypts card data using CSE, POSTs it to the vault endpoint from vaultConfiguration.links.saveInstrument, and returns a SaveInstrumentResponse containing an instrument ID for future use.
Requires vault configurationThe session init payload must include vaultConfiguration with a saveInstrument link. Contact Payrails to enable this for your merchant account.

Session.tokenize(request, options?) — suspend

Saves a reusable payment instrument from a payment method without running a payment. Mirrors the iOS SDK’s session.tokenize(...).
Parameters Returns: SaveInstrumentResponse — the saved instrument record including id, status, and card metadata. Throws
  • PayrailsError.invalidCardData — card form validation failed; field errors are shown automatically on the form
  • PayrailsError.missingData("Vault configuration with providerConfigId is required...") — session init payload is missing vaultConfiguration
  • PayrailsError.missingData("holderReference is required...") — session init payload is missing holderReference
Defined as a Session extension in the checkout (UI) module. Import it from com.payrails.sdk; the call site is session.tokenize(...).
Example

Session.tokenize(request, options?, onSuccess, onFailed, onCancelled) — callback

Callback variant for callers not using coroutines (and Java callers). Exactly one of the three callbacks is invoked, exactly once, on the main thread.
Callbacks Example

TokenizationRequest

Sealed type selecting what to tokenize. Card and Google Pay are supported (mirroring the iOS SDK’s card / applePay cases).

GooglePayPresenter / rememberGooglePayPresenter(session)

GooglePayPresenter is an opaque handle that drives the Google Pay sheet for tokenize(TokenizationRequest.GooglePay(...)). It is obtained inside a Composable, which registers the Google Pay Activity-result launcher before the host reaches STARTED (Android requires this — a Google Pay token cannot be acquired from a plain suspend call).
Returns: a GooglePayPresenter bound to the current composition. Example

GooglePayTokenizeButton(...)

A compliant, Google-branded button that tokenizes via Google Pay (save, no charge). Wraps rememberGooglePayPresenter + Session.tokenize. Renders only when Google Pay is available for the session (config present and isReadyToPay succeeds). Exactly one of onSuccess/onFailed/onCancelled fires per tap, on the main thread.
Example

CardForm.tokenize(options?)

Convenience wrapper that tokenizes this form via Session.tokenize. Equivalent to session.tokenize(TokenizationRequest.Card(cardForm), options).
Parameters Returns: SaveInstrumentResponse — the saved instrument record including id, status, and card metadata. Throws
  • PayrailsError.invalidCardData — card form validation failed; field errors are shown automatically on the form
  • PayrailsError.missingData("Session is required for tokenization.") — CardForm was created without an active session
  • PayrailsError.missingData("Vault configuration with providerConfigId is required...") — session init payload is missing vaultConfiguration
  • PayrailsError.missingData("holderReference is required...") — session init payload is missing holderReference
Example

TokenizeOptions

Options controlling card vault behavior during tokenization.

FutureUsage

Enum signaling intended future card use to the card network. Sent as part of the vault request.

SaveInstrumentResponse

Response returned by tokenize(). Represents the saved instrument record from the vault.

SaveInstrumentResponse.InstrumentResponseData


InstrumentAPIResponse.Save

The Save variant of the InstrumentAPIResponse sealed class, returned when using lower-level instrument API calls. CardForm.tokenize() returns SaveInstrumentResponse directly rather than wrapping it.

Google Pay

GooglePayButton

Create a GooglePayButton after initializing a session. The button handles Google Pay availability checks, payment sheet presentation, and authorization automatically.
Kotlin/Compose onlyElement creation and Render() require Kotlin and Jetpack Compose. The delegate callbacks below are Java-compatible.
Kotlin
Java — setting the delegate
The button is hidden by default and becomes visible only after isReadyToPay() succeeds. The onGooglePayAvailable callback fires when the button becomes visible.

Google Pay Configuration

Google Pay configuration is provided by the Payrails backend through paymentCompositionOptions. The SDK reads clientConfig.additionalConfig for the Google Pay payment option, which contains:
  • apiVersion / apiVersionMinor — Google Pay API version (defaults to 2 / 0)
  • allowedPaymentMethods — Payment methods array including tokenizationSpecification (gateway configuration)
  • merchantInfo — Merchant identifier and name (required in production)
  • emailRequired — Whether to request the payer’s email
  • shippingAddressRequired / shippingAddressParameters — Shipping address collection
The countryCode for transactionInfo is extracted from meta.order.billingAddress.country.code in the execution metadata. No client-side configuration of gateway credentials is needed. The PAYMENT_GATEWAY, gateway, and gatewayMerchantId values are provided by the backend.

GooglePayButtonStyle

GooglePayButtonStyle controls the button appearance:

GooglePayButtonTranslations

GooglePayButtonTranslations provides:
  • storeInstrument: String? — Checkbox label text when showStoreInstrumentCheckbox is enabled. Defaults to "Save this payment method".

PayrailsGooglePayButtonDelegate

Store Instrument Checkbox

Pass showStoreInstrumentCheckbox = true to createGooglePayButton(...) to render a checkbox below the Google Pay button. When checked, the payment token is stored as an instrument for future use.

3DS for Google Pay

If the authorize response requires 3DS verification, the SDK opens the challenge URL in a Custom Tab and polls for the terminal result, following the same 3DS flow used for card payments. The onThreeDSecureChallenge delegate callback fires when this happens.

PayPal

PayPalButton

Create a PayPalButton after initializing a session. The button handles PayPal redirect presentation, polling for results, and authorization automatically.
Kotlin/Compose onlyElement creation and Render() require Kotlin and Jetpack Compose. The delegate callbacks below are Java-compatible.
Kotlin

PayPalButtonStyle

PayPalButtonTranslations

PayrailsPayPalButtonDelegate

Only onPaymentSessionExpired has no default implementation and must be provided — the session cannot be reused after a PayPal cancellation or expiry, so the merchant must handle this to allow retries.

Redirect Payments

GenericRedirectButton

Create a GenericRedirectButton for redirect-based payment methods (iDEAL, Bancontact, Sofort, etc.). Use Session.getPaymentMethodConfig(PaymentMethodFilter.Redirect) to discover which methods are configured.
Kotlin/Compose onlyElement creation and Render() require Kotlin and Jetpack Compose. The delegate callbacks below are Java-compatible.

Discovering Available Redirect Methods

Returns an empty list if no redirect methods are configured. See Session.getPaymentMethodConfig(filter) for the full filter API.

PayrailsPaymentOption

Creating a Redirect Button

Java — setting the delegate

GenericRedirectPaymentButtonDelegate

Redirect Flow Behavior

When the user taps the button, the SDK:
  1. Opens the payment provider’s redirect URL in a Custom Tab (falls back to system browser)
  2. Polls the execution status in the background until terminal success/failure
  3. Delivers the result through delegate callbacks
The redirect flow shares the same polling and session recovery infrastructure as card 3DS and Google Pay 3DS redirects. If the redirect is abandoned or remains non-terminal, or the provider reports an authentication/session-expiry error, the onPaymentSessionExpired callback (if implemented) is invoked for automatic recovery.

Button Styling

GenericRedirectButton accepts the same CardButtonStyle and CardPaymenButtonTranslations as CardPaymentButton. See Card Payment Button Styling for available properties.

Stored Instruments

StoredInstrument Interface

Each StoredInstrument exposes: The SDK maps the backend instrument field default to StoredInstrument.isDefault.

CardInstrumentMetadata

Public data class with typed card presentation data: Migration note: prefer displayName and cardMetadata over parsing the description string. description remains available for backwards compatibility.

Retrieving Stored Instruments

Use session.getStoredInstruments() to retrieve available instruments, then set one on the button: Kotlin
Java

Instrument Management APIs

Use typed methods on Session to delete or update stored instruments:
The return type is InstrumentAPIResponse, a sealed class with Delete, Update, and Save variants (capitalized). See Card Tokenization for the Save variant and the tokenize() method.

Results and Errors

Payment results are surfaced through delegate interfaces: Card payments — PayrailsCardPaymentButtonDelegate:
  • onAuthorizeSuccess — payment succeeded
  • onAuthorizeFailed — payment failed (includes session-expiry outcomes from redirect reconciliation)
  • onThreeDSecureChallenge — 3DS challenge started
  • onPaymentButtonClicked — button was tapped
Google Pay — PayrailsGooglePayButtonDelegate:
  • onAuthorizeSuccess — payment succeeded
  • onAuthorizeFailed — payment failed
  • onThreeDSecureChallenge — 3DS challenge started
  • onPaymentButtonClicked — button was tapped
  • onGooglePayAvailable — Google Pay is ready on this device
PayPal — PayrailsPayPalButtonDelegate:
  • onAuthorizeSuccess — payment authorized
  • onAuthorizeFailed — payment failed or was rejected
  • onCancelled — user explicitly cancelled in the browser
  • onPaymentSessionExpired — session expired and must be refreshed before retry (required)
  • onPaymentButtonClicked — button was tapped
Generic Redirect — GenericRedirectPaymentButtonDelegate:
  • onAuthorizeSuccess — payment authorized
  • onAuthorizeFailed — payment failed or was rejected
  • onCancelled — user explicitly cancelled the redirect
  • onPaymentSessionExpired — redirect was abandoned or session expired
  • onPaymentButtonClicked — button was tapped
Failed includes session-expiry outcomes from redirect reconciliation (for example browser abandoned/non-terminal timeout), including cases where automatic onSessionExpired recovery is attempted. Errors are represented by PayrailsError (e.g., authenticationError, missingData).

Co-Branded Cards

Support for cards carrying two networks (a local scheme like mada plus an international one like mastercard). Activates only when the session is co-branded-enabled (backend featureConfig.coBrandedCardsRollout flag + a binLookup link). See the how-to and the concept.

Session.binLookup(bin)

One-shot BIN lookup against the session’s binLookup endpoint. Non-throwing: returns null on invalid input (not 6-8 digits), an inactive session, a missing endpoint, or a network error (coroutine cancellation propagates). No throttling or caching — the card form’s internal as-you-type lookup handles that.

BinLookupResponse

IssuerCountry

CardFormEvents.onPreferredSchemeChanged

Invoked when the shopper’s preferred scheme changes: on resolution to a co-branded card (default selection), on a selection change, and once with an empty payload when co-branded state clears. De-duplicated.

PreferredSchemeChange

CardScheme

Selector UI, styling, and translations

The Card Brand selector renders automatically inside CardForm for co-branded cards. Customize:
  • Text — CardTranslations.Labels.cardBrandSelectorTitle / cardBrandSelectorSubtitle (defaults "Card Brand" / "Select your preferred network").
  • Look — CardFormStylesConfig.cardBrandSelector: CardBrandSelectorStyle?; see the Card Brand Selector styling reference.

Payment

When a co-branded card is paid, the selected scheme is submitted as paymentInstrumentData.preferredScheme on the authorize request; it is omitted for single-brand cards.

Further Reading

Last modified on September 30, 2026