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:
| Guide | Why |
|---|---|
| iOS SDK | Surfaces, isolation model and flows |
| SDK Setup | Environment name and clientId |
| Top-Up Transfer | Estimate 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.
| Input | What it is | Source |
|---|---|---|
quote | WirexWalletQuote(estimationId:sourceAmount: WirexWalletMoney(amount:currency:)). Optional: destinationAmount, fee, rate, expiresAtMs | estimation_id and source_amount / source_currency from POST /api/v1/cards/topup/estimate |
providerConfig | WirexWalletProviderConfig(jsonText:) — the wallet provider block, passed verbatim | The topup.providers.<name> block of your app configuration |
auth | WirexWalletCheckoutAuth(checkoutToken:) — token mode only | access_token from POST /api/v1/cards/topup/token |
Trap:
WirexWalletMoney.amountis 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_paykey means Apple Pay is not offered.
Choose a Mode
| Token mode | Legacy mode | |
|---|---|---|
auth | WirexWalletCheckoutAuth(checkoutToken:) | nil |
| Who executes the top-up | The checkout, with the restricted token | Your backend |
| Events after the Pay sheet | .executing → .executed or .executeFailed | .token |
| What reaches app code | The top-up id and status | walletPaymentToken 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
checkoutTokenper armed quote. Mint a new one on every re-arm. estimationIdandcheckoutTokencome 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
| Event | Mode | Meaning |
|---|---|---|
.ready | Both | The checkout is rendered |
.naturalHeight(Double) | Both | Apply the height to the view's frame |
.sheetOpen | Both | The Apple Pay sheet is open |
.cancelled | Both | The user closed the sheet |
.attemptFailed(reason:) | Both | The attempt failed; the checkout stays armed |
.estimationExpired | Both | Re-price and rearm |
.token(WirexWalletPaymentToken) | Legacy | walletPaymentToken — your backend executes the top-up with it |
.executing | Token | The checkout is executing the top-up |
.executed(WirexWalletExecuteResult) | Token | id, status — the top-up was executed |
.executeFailed(WirexWalletExecuteError) | Token | reason — execute was rejected |
.failed(WirexWalletError) | Both | kind — the checkout failed |
.diagnostic(WirexWalletDiagnostic), .debug(level:message:) | Both | Diagnostics; 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.
Updated about 3 hours ago

