Apple Pay
Accept payments from Apple Pay wallets. This page covers the wallet-specific part of the flow — how your frontend obtains the encrypted pay_token and how the payment is created. Statuses are described below. Refunds and webhooks are shared by all mobile pay-ins.
How it works
Apple Pay pay-ins combine a browser-side Apple Pay flow with three server-to-server calls to Mercuryo:
- Your frontend opens the native Apple Pay sheet; on the
onvalidatemerchantevent it calls your backend, which calls Mercuryo'svalidate-merchantendpoint and returns the merchant session to the browser. All Mercuryo calls — carrying yourSdk-Partner-TokenandX-Signature— happen server-side, never from the browser. - After the buyer authorizes the payment, your frontend receives an encrypted Apple Pay
paymentToken. - Your backend sends the token and the buyer's details to Mercuryo's
mobile-payendpoint, which creates the transaction and returns its initial status. - Mercuryo processes the payment asynchronously. Track the outcome by polling the status endpoint or by consuming a webhook.
Onboarding
Mercuryo operates the Apple Pay merchant identity and holds all Apple Pay certificates and keys. You do not need an Apple Developer account, a Merchant Identity Certificate, or a Payment Processing Certificate — Mercuryo validates the merchant session and decrypts the payment token on your behalf.
Onboarding covers two things:
- your partner credentials —
service_id,secret, andSign Key— issued by your integration manager; - the web domain(s) that serve your Apple Pay button — Apple requires each domain to be registered, so share them with your integration manager.
Country restrictions
Apple Pay pay-ins are not available in these cases:
- buyers located in the United States (
US) or United Kingdom (GB); - cards issued in the United States (
US) or United Kingdom (GB), regardless of the buyer's location.
Mercuryo enforces this server-side. Apply the same checks in your frontend to improve the buyer's experience.
Step 1: Frontend — Apple Pay request
Your frontend creates and displays the Apple Pay request using the W3C Payment Request API (PaymentRequest) or ApplePayPaymentRequest, and requests all the buyer data Mercuryo needs for processing.
Configure the request with:
merchantCapabilities:supports3DS,supportsCredit,supportsDebit;supportedNetworks:masterCard,visa;- billing contact fields — request the buyer's name, email, and billing address (
requiredBillingContactFields: ["postalAddress", "name", "email"], or the W3C optionsrequestPayerName,requestPayerEmail,requestBillingAddress).
The name, email, and billing address you collect here must be forwarded to Mercuryo in Step 3.
Handle the merchant validation event by calling your backend, which forwards the validationURL to Mercuryo (Step 2), and hand the returned merchant session back to the browser:
- Payment Request API —
eventis anonmerchantvalidationevent, and you answer withevent.complete(merchantSession). - Apple Pay JS —
eventis anonvalidatemerchantevent, and you answer withapplePaySession.completeMerchantValidation(merchantSession), whereapplePaySessionis yourApplePaySessioninstance.
Pick one API and stay with it. After the buyer authorizes the payment, Base64-encode the token.paymentData JSON for Step 3.
References: Apple Pay on the Web, W3C Payment Request API.
Step 2: Validate the merchant session
When the browser fires onmerchantvalidation (onvalidatemerchant in Apple Pay JS), POST the validation_url and your domain to Mercuryo. Mercuryo performs the mTLS call to Apple and returns the merchant session for you to pass back to the browser.
Endpoint: POST /sdk-partner/alternative-mobile-pay/validate-merchant
Request:
{
"validation_url": "https://apple-pay-gateway.apple.com/paymentservices/startSession",
"domain": "shop.example.com"
}
Response — the Apple merchant session is nested under data.data:
{
"status": 200,
"data": {
"data": {
"epochTimestamp": 1783513967000,
"merchantSessionIdentifier": "SSH2A0…",
"displayName": "Merchant",
"signature": "…"
}
}
}
Pass the data.data object back to the browser as the merchant session: event.complete(merchantSession) with the Payment Request API, or applePaySession.completeMerchantValidation(merchantSession) with Apple Pay JS.
Step 3: Create the payment
After the buyer authorizes the payment, take token.paymentData from the Apple Pay payment object, serialize it to JSON and Base64-encode the result. Send it as pay_token together with the buyer's details. Encoding the whole token object instead of paymentData fails decryption.
Endpoint: POST /sdk-partner/alternative-mobile-pay/mobile-pay
Field types, limits, and required parameters are defined in the endpoint's API Reference.
Request:
{
"pay_token": "<base64 of the paymentData JSON>",
"pay_system": "apple",
"email": "john.doe@example.com",
"name": "John Doe",
"fiat_amount": "10.00",
"fiat_currency": "USD",
"ip": "203.0.113.10",
"billing_address": {
"country_code": "DE",
"street_line_1": "Unter den Linden 1",
"city": "Berlin",
"zip_code": "10115"
},
"merchant_transaction_id": "order-8841"
}
Response — the transaction id and its initial status:
{
"status": 200,
"data": { "id": "28a3c125a28075453", "status": "pending" }
}
Use data.id to poll the status and to issue refunds.
Close the wallet sheet as soon as the request returns, and pick the completion status from data.status, not from the HTTP code: a repeated request with the same merchant_transaction_id also answers 200, carrying the state the payment already has, which can be a failure.
pending,order_scheduled,redirect_pending,paid— complete as success:response.complete("success")with the Payment Request API, orapplePaySession.completePayment(ApplePaySession.STATUS_SUCCESS)with Apple Pay JS.order_failed— complete as failure:response.complete("fail")orapplePaySession.completePayment(ApplePaySession.STATUS_FAILURE), so the buyer does not see a successful sheet for a rejected payment.
Apple gives you only seconds to answer, so do not hold the sheet open waiting for the final result. Closing the sheet ends the wallet interaction and nothing more: a pending payment is still in progress, and its outcome comes from the status endpoint or a webhook — see Payment statuses.
Payment status
Poll GET /sdk-partner/alternative-mobile-pay/mobile-pay/{id}/status or wait for a webhook. Status values and the response shape are common to every pay-in — see Payment statuses.
Webhook
Payment notifications use the shared webhook contract. Process final outcomes according to Payment statuses, and handle duplicate deliveries idempotently.