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:

  1. Your frontend opens the native Apple Pay sheet; on the onvalidatemerchant event it calls your backend, which calls Mercuryo's validate-merchant endpoint and returns the merchant session to the browser. All Mercuryo calls — carrying your Sdk-Partner-Token and X-Signature — happen server-side, never from the browser.
  2. After the buyer authorizes the payment, your frontend receives an encrypted Apple Pay paymentToken.
  3. Your backend sends the token and the buyer's details to Mercuryo's mobile-pay endpoint, which creates the transaction and returns its initial status.
  4. 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, and Sign 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 options requestPayerName, 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 — event is an onmerchantvalidation event, and you answer with event.complete(merchantSession).
  • Apple Pay JS — event is an onvalidatemerchant event, and you answer with applePaySession.completeMerchantValidation(merchantSession), where applePaySession is your ApplePaySession instance.

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, or applePaySession.completePayment(ApplePaySession.STATUS_SUCCESS) with Apple Pay JS.
  • order_failed — complete as failure: response.complete("fail") or applePaySession.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.