Apple Pay Top-Up

Embed the Wirex-hosted Apple Pay checkout in an iOS app for a top-up your backend priced, in token or legacy mode.

Before You Start

Read the following guides before proceeding:

GuideWhy
iOS SDKSurfaces, isolation model and flows
SDK SetupEnvironment name and clientId
Top-Up TransferEstimate with apple_pay and the wallet-method execute body

Overview

WirexWalletCheckoutView embeds the Wirex-hosted checkout for a top-up your backend has already priced. The
checkout renders the quote and the Apple Pay button, and presents the Apple Pay sheet itself. Your app needs no
Apple Pay entitlement and no merchant identifier.

An Apple Pay top-up requires the WalletTopup capability — separate from CardTopup. Check it via
GET /api/v2/user before offering the Pay button.

InputWhat it isSource
quoteWirexWalletQuote(estimationId:sourceAmount: WirexWalletMoney(amount:currency:)). Optional: destinationAmount, fee, rate, expiresAtMsestimation_id and source_amount / source_currency from POST /api/v1/cards/topup/estimate
providerConfigWirexWalletProviderConfig(jsonText:) — the wallet provider block, passed verbatimThe topup.providers.<name> block of your app configuration
authWirexWalletCheckoutAuth(checkoutToken:) — token mode onlyaccess_token from POST /api/v1/cards/topup/token

Trap: WirexWalletMoney.amount is a decimal string ("10.00"), not a number.

Trap: pass the provider block exactly as received. Do not re-case keys or add defaults — an absent
apple_pay key means Apple Pay is not offered.


Choose a Mode

Token modeLegacy mode
authWirexWalletCheckoutAuth(checkoutToken:)nil
Who executes the top-upThe checkout, with the restricted tokenYour backend
Events after the Pay sheet.executing → .executed or .executeFailed.token
What reaches app codeThe top-up id and statuswalletPaymentToken for your backend to relay

A failed token mint is not fatal in-app: arm the checkout in legacy mode instead.


Step 1: Price the Top-Up

Your backend calls POST /api/v1/cards/topup/estimate with payment_method set to apple_pay. Request and
response: Estimate Top-Up.


Step 2: Mint a Checkout Token (Token Mode)

Your backend calls POST /api/v1/cards/topup/token with the user token and passes access_token from the
response to the app as checkoutToken. The token is accepted only by the top-up estimate and execute
endpoints. Request, response and code: Restricted Top-Up Token.

  • One checkoutToken per armed quote. Mint a new one on every re-arm.
  • estimationId and checkoutToken come from two independent calls; neither is derived from the other.
  • Never hand the user's session bearer to the checkout — pass only the restricted token.

Step 3: Check Availability

let config = WirexWalletConfig(environment: try WirexWalletEnvironment.resolve("test"))
let checker = WirexWalletAvailabilityChecker(config: config, providerConfig: providerConfig)
checker.onChange = { [weak self] availability in self?.payButton.isHidden = !availability.applePay }
checker.start()

onChange reports the native canMakePayments answer. Start the checker with the real provider block before
showing a Pay button, and call checker.stop() when done.

WirexWalletConfig(cache:) takes an optional WirexWalletAvailabilityCache key-value store so the answer
survives relaunch. The SDK writes one key with two booleans.

Note: the Simulator reports Apple Pay unavailable and cannot present the Pay sheet (no Secure Element).
Test on a device with a provisioned card.


Step 4: Mount the Checkout

func mount(config: WirexWalletConfig, quote: WirexWalletQuote, providerConfigJson: String, checkoutToken: String?) throws {
    let checkout = WirexWalletCheckoutView(
        config: config,
        quote: quote,
        providerConfig: try WirexWalletProviderConfig(jsonText: providerConfigJson),
        auth: checkoutToken.map { WirexWalletCheckoutAuth(checkoutToken: $0) })
    checkout.onEvent = { [weak self] event in self?.handle(event) }
    view.addSubview(checkout)
    self.checkout = checkout
}

func handle(_ event: WirexWalletCheckoutEvent) {
    switch event {
    case .naturalHeight(let height): checkout?.frame.size.height = height
    case .estimationExpired: repriceAndRearm()
    case .token(let token): sendToBackend(token.walletPaymentToken)
    case .executed(let result): showResult(result.id, result.status)
    case .executeFailed(let error): showError(error.reason)
    case .failed(let error): showError(error.kind)
    default: break
    }
}

The estimation has a short TTL. On .estimationExpired, re-price on your backend and call
checkout.rearm(quote:providerConfig:auth:) — in token mode with a freshly minted token.

Events

EventModeMeaning
.readyBothThe checkout is rendered
.naturalHeight(Double)BothApply the height to the view's frame
.sheetOpenBothThe Apple Pay sheet is open
.cancelledBothThe user closed the sheet
.attemptFailed(reason:)BothThe attempt failed; the checkout stays armed
.estimationExpiredBothRe-price and rearm
.token(WirexWalletPaymentToken)LegacywalletPaymentToken — your backend executes the top-up with it
.executingTokenThe checkout is executing the top-up
.executed(WirexWalletExecuteResult)Tokenid, status — the top-up was executed
.executeFailed(WirexWalletExecuteError)Tokenreason — execute was rejected
.failed(WirexWalletError)Bothkind — the checkout failed
.diagnostic(WirexWalletDiagnostic), .debug(level:message:)BothDiagnostics; ignore in production

Legacy Mode: Execute on Your Backend

Pass walletPaymentToken as wallet_payment_token to POST /api/v1/cards/topup/execute, together with the
other wallet-method fields — see Execute Top-Up.


Did this page help you?