Wallets
Thirteen wallets, one payload shape. Device wallets (Apple Pay, Google Pay) confirm with a biometric payment sheet; app wallets (PayPal, Alipay, TWINT, …) approve in the wallet's own app. Either way you get the same Payment object, the same webhooks, and the same refund call.
The wallet methods
| Wallet | payment_method | Region |
|---|---|---|
| Apple Pay | apple_pay | Global |
| Google Pay | google_pay | Global |
| PayPal | paypal | Global |
| Alipay | alipay | China / Asia |
| WeChat Pay | wechat_pay | China / Asia |
| Cash App Pay | cashapp | US |
| Kakao Pay | kakao_pay | South Korea |
| GrabPay | grabpay | Southeast Asia |
| GoPay | gopay | Indonesia |
| MobilePay | mobilepay | Denmark / Finland |
| Vipps | vipps | Norway |
| TWINT | twint | Switzerland |
| Satispay | satispay | Italy |
Regions and currencies for each are in the method catalog. Behind the wallet, the funding source varies — a tokenized card for the device wallets, a linked bank account or stored balance for most of the app wallets. You don't handle the difference; it shows up only in what comes back and in dispute exposure.
How the flow works
Every wallet payment starts the same way: POST /v1/payments answers requires_action with a next_action.url. What happens on that Finscale-hosted page depends on the wallet family:
- Device wallets —
apple_pay,google_pay. The hosted page presents the native payment sheet; the customer confirms with Face ID, Touch ID, or the device lock. The wallet hands over a tokenized card with a one-time cryptogram — never the underlying PAN. - App wallets — everything else. The page hands off to the wallet app on mobile, or shows a QR code to scan on desktop. The customer approves inside the wallet and is returned to your
return_url.
On hosted checkout you skip even the create call — checkout shows each shopper the wallets that fit their device and region, and Apple Pay / Google Pay buttons render natively.
Creating a wallet payment
curl https://api.finscale.dev/v1/payments \
-H "Authorization: Bearer sk_test_51FinscaleDemo…" \
-H "Idempotency-Key: idem_ord_9f21_0716" \
-H "Content-Type: application/json" \
-d '{
"amount": 4900,
"currency": "EUR",
"payment_method": "apple_pay",
"reference": "ord_9f21_0716",
"customer": { "email": "anna@example.com" },
"return_url": "https://shop.example.com/checkout/return"
}'
The response is the standard requires_action shape — redirect the customer to next_action.url and wait for the webhook, exactly as in the quickstart.
What comes back
Once the wallet approves, payment_method_details carries a snapshot keyed by the method id. For device wallets that includes the underlying card's brand and last4 — note this is the device account number, not the plastic in the customer's pocket, so don't match it against a card on file:
{
"id": "pay_8Q2mX4nT1cVb",
"object": "payment",
"amount": 4900,
"currency": "EUR",
"status": "succeeded",
"payment_method": "apple_pay",
"payment_method_details": {
"apple_pay": { "brand": "visa", "last4": "0342", "funding": "debit" }
},
"risk": {
"score": 9,
"decision": "approved",
"checks": { "avs_result": "unavailable", "cvv_result": "unavailable" }
},
"reference": "ord_9f21_0716",
"provider": "prov_eu_acq_01",
"next_action": null,
"created_at": "2026-07-16T09:24:31Z",
"livemode": false
}
Risk & authentication
Apple Pay and Google Pay are card-family methods, so risk screening runs and risk is populated. Expect avs_result and cvv_result to be unavailable — wallet charges authenticate with a per-transaction cryptogram instead, which is also why wallet fraud rates run low and 3-D Secure challenges are rarely required on top.
The app wallets authenticate the customer inside the wallet itself (login + app approval), so risk is null — there is nothing further for Finscale to score.
Refunds & disputes
Refunds are the standard call — POST /v1/refunds, full or partial — and the money returns to whatever funded the wallet payment. See Refunds.
Dispute exposure follows the funding rail. Device-wallet payments are card payments underneath: chargebacks are possible and arrive as Dispute objects (dp_…), though biometric confirmation keeps fraudulent disputes rare. App wallets run buyer-protection programs inside their own ecosystems; when a wallet claim lands, Finscale normalizes it into the same Dispute object with the same reason enum, deadlines, and evidence API — one dispute queue, whatever the source.
Settlement timing
Wallet approvals confirm in seconds. Funds clear on the underlying rail's schedule — card-speed for the device wallets, wallet-scheme timing for the rest — and join your unified payout on the standard T+2 schedule. One payout per currency, wallets included; see Settlement & payouts.
Error scenarios
| Scenario | What the API does |
|---|---|
| Underlying card declines (device wallets) | Standard card error: card_declined, insufficient_funds, … The payment is failed with the matching failure_code. |
| Wallet balance or account can't cover it | payment.failed with failure_code: "insufficient_funds". |
| Customer dismisses the sheet or app prompt | The payment stays requires_action until the session expires, then fails. Cancel it sooner with POST /v1/payments/{id}/cancel if checkout restarts. |
| Wallet not available for the currency or region | 400 invalid_request_error with currency_not_supported at create — surface only wallets that fit the customer, as hosted checkout does. |
| Wallet scheme outage | Retriable failures route to the next capable provider automatically — see Smart routing. |
Related
- Payment methods overview — all families and the 43-method catalog
- Cards & 3DS — the rail under Apple Pay and Google Pay
- Hosted checkout — native wallet buttons with zero extra code
- Disputes — the normalized dispute queue
- Method catalog on finscale.dev — regions and currencies