Apple Pay and Google Pay
Apple Pay and Google Pay settle as normal card charges: same USD balance, same callbacks, same status endpoint. They cannot go through the direct card API (/wallet/card/charge), because the card is tokenized on the customer device and no card number is exposed.
There are three ways to offer them.
| Option | Front-end work | Domain registration |
|---|---|---|
| A. Hosted checkout (redirect) | None | Not needed |
| B. Hosted checkout in an iframe | An <iframe> | Ask support to allow your origin |
| C. Embedded on your page (Express Checkout Element) | Stripe.js on your page | Your domain must be registered |
All three start with the same call: POST /wallet/deposit/payment with method_pay=card. See Card payments (hosted checkout) for the full field list.
The wallet parameter
wallet parameterSend wallet to show a single wallet on the hosted checkout, with no card form and no other wallet button. Use it when the customer already chose the method on your page.
{
"token": "YOUR_TOKEN",
"secret": "YOUR_SECRET",
"amount": 49.90,
"method_pay": "card",
"wallet": "apple_pay",
"postback": "https://example.com/callbacks/card",
"return_url": "https://example.com/orders/1043/thanks"
}| Value | Effect |
|---|---|
| omitted | Card form plus any wallet the device supports. |
apple_pay | Only the Apple Pay button. |
google_pay | Only the Google Pay button. |
Any other value returns 422 INVALID_WALLET.
The customer fields (debtor_name, email, phone, debtor_document_number) are optional for card. When you omit them, name and email come from the wallet. If you send them, they are kept as declared and not overwritten.
Option A: hosted checkout
Redirect the customer to checkout_url. Apple Pay and Google Pay appear automatically on supported devices. No domain setup on your side.
Option B: hosted checkout in an iframe
- Ask support to allow your site origin as a frame ancestor. Only
https://origins are accepted (for examplehttps://shop.example.com). - Load
checkout_urlin an iframe withallow="payment". Without that attribute the browser blocks the wallet APIs inside the frame.
<iframe
src="CHECKOUT_URL"
allow="payment"
width="100%"
height="720"
style="border:0"></iframe>Until your origin is allowed, browsers refuse to render the page inside your frame.
Option C: embedded on your own page
Use the client_secret, publishable_key and on_behalf_of from the create response to mount Stripe's Express Checkout Element on your HTTPS page.
<div id="express-checkout-element"></div>
<script src="https://js.stripe.com/v3/"></script>
<script>
// Values from the POST /wallet/deposit/payment response:
const publishableKey = "pk_test_YOUR_PUBLISHABLE_KEY";
const clientSecret = "pi_..._secret_...";
const onBehalfOf = "acct_...";
// Do NOT pass { stripeAccount } here.
const stripe = Stripe(publishableKey);
// onBehalfOf is required and must equal on_behalf_of from the response.
const elements = stripe.elements({ clientSecret, onBehalfOf });
const ece = elements.create('expressCheckout');
ece.mount('#express-checkout-element');
ece.on('confirm', async () => {
const { error: submitError } = await elements.submit();
if (submitError) { console.error(submitError.message); return; }
const { error } = await stripe.confirmPayment({
elements,
clientSecret,
confirmParams: { return_url: 'https://example.com/checkout/complete' },
redirect: 'if_required',
});
if (error) { console.error(error.message); return; }
// Wait for the "paid" callback (or check the status endpoint) before fulfilling.
});
</script>Rules:
- Initialize
Stripe()withpublishable_keyonly. Passing{ stripeAccount }turns the charge into a different type and confirmation fails. - Pass
onBehalfOftostripe.elements(). It is required for these charges. client_secretconfirms only this payment. It can go to the browser over HTTPS, but never log it or put it in a URL.publishable_keymatches the environment of the credentials you used (sandbox or live). Do not mix a sandbox key with a live charge.
Register your domain
Apple Pay only renders on domains registered for our platform, and Google Pay needs HTTPS plus registration. Send support the exact domain that shows the buttons (for example checkout.example.com). Registration is per environment, so we register it for sandbox and live separately. You do not need to host any /.well-known/ file.
The buttons render only when all of these hold:
- The domain is registered and active.
- The page is served over HTTPS.
- The device, browser and region support the wallet, and the wallet has a card.
To show the buttons even before the wallet is set up on the device, create the element with paymentMethods: { applePay: 'always', googlePay: 'always' }.
Result
Same as any card charge:
paidcallback withamountandcurrency, and the USD balance is credited.- If the customer closes the wallet sheet and never pays, nothing is charged. The session expires after
expires_in_secondsand you receive acancelledcallback withfailure_code: expired. - Refunds and disputes work as for any card charge.
Testing
Wallets work in sandbox, but you need a real device with a real card in the wallet and, for option C, a domain registered in the sandbox environment over HTTPS. The card is tokenized as a test token and no money moves.
Updated about 2 hours ago
