This guide explains how to integrate Apple Pay on your website using us as the payment processor. All Apple Pay certificates are stored and managed on our side. You request a session and submit the Apple token for payment processing.

Requirements

  1. Your website must use HTTPS
  2. Your domain must be registered with your Apple Merchant ID
  3. You have created the Apple Pay certificate signing requests (CSR). Information on how to do that can be found here
  4. Customer must use Safari (iOS/macOS)
  5. window.ApplePaySession must be available in the browser

1. Display the Apple Pay button (frontend)

<script src="https://applepay.cdn-apple.com/jsapi/v1.3.2/apple-pay-sdk.js" integrity="sha384-DZRWMZLyVXr+7shJfal8pIG2v4KisLoSWFjZQMUv0+GWaCwoa82qeHsWrbBIUDPU" crossorigin="anonymous"></script>
<script>
    document.addEventListener('DOMContentLoaded', async function () {
        if (!window.ApplePaySession || !ApplePaySession.supportsVersion(14)) return;
        const merchantIdentifier = 'merchant.some.domain';
        try {
            const applePayCapabilities = await ApplePaySession.applePayCapabilities(merchantIdentifier);
            const paymentCredentialStatus = applePayCapabilities?.paymentCredentialStatus;
            if (paymentCredentialStatus === 'paymentCredentialsAvailable' || paymentCredentialStatus === 'paymentCredentialStatusUnknown') {
                showApplePayButton();
            }
        } catch {
            const can = await ApplePaySession.canMakePayments();
            if (can) showApplePayButton();
        }
        function showApplePayButton() {
            const btn = document.getElementById('apple-pay-button');
            if (!btn) return;
            btn.style.display = 'inline-block';

            btn.addEventListener('click', async () => {
                const paymentRequest = {
                    countryCode: 'US',
                    currencyCode: 'USD',
                    supportedNetworks: ['visa', 'masterCard', 'amex'],
                    merchantCapabilities: ['supports3DS'],
                    total: { label: 'Your Store', amount: '10.00' }
                };

                const session = new ApplePaySession(14, paymentRequest);

                // STEP 1: Ask your own backend to retrieve an Apple Pay session from CentroBill
                session.onvalidatemerchant = async (event) => {
                    try {
                        const res = await fetch('/api/applepay/session', {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/json' },
                            body: JSON.stringify({ validationUrl: event.validationURL })
                        });
                        if (!res.ok) throw new Error('Merchant validation failed');

                        const merchantSession = await res.json();
                        session.completeMerchantValidation(merchantSession);
                    } catch (e) {
                        console.error(e);
                        session.abort();
                    }
                };

                // STEP 2: Handle authorized payment and forward token to your backend
                session.onpaymentauthorized = async (event) => {
                    try {
                        const paymentResponse = await fetch('/api/pay', {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/json' },
                            body: JSON.stringify({
                                paymentSource: {
                                    type: 'applepay',
                                    token: event.payment.token
                                },
                                amount: '10.00',
                                currency: 'USD',
                                orderId: 'ORD-12345'
                            })
                        });

                        const result = await paymentResponse.json();
                        session.completePayment(
                                result.success ? ApplePaySession.STATUS_SUCCESS : ApplePaySession.STATUS_FAILURE
                        );
                    } catch (e) {
                        console.error(e);
                        session.completePayment(ApplePaySession.STATUS_FAILURE);
                    }
                };

                session.oncancel = () => {
                    console.warn('Apple Pay cancelled by user');
                };

                session.begin();
            });
        }
    });
</script>

<a id="apple-pay-button" style="display: none;" href="#">
    <img decoding="async" loading="lazy" alt="Apple Pay button" srcset="https://docs-assets.developer.apple.com/published/61bec328eef83e2a656d8f82768c219e/ap-button%402x.png" src="https://docs-assets.developer.apple.com/published/61bec328eef83e2a656d8f82768c219e/ap-button%402x.png" data-orientation="landscape" width="244" height="auto">
</a>

2. Validate the Apple Pay session (your backend → Gateway)

When the Apple Pay flow begins in the browser, your frontend receives a validationUrl from Apple. This must be sent to your backend, which then calls the Gateway to get a valid Apple Pay session object.

Frontend → your backend

POST https://<your-backend-domain>/api/applepay/session
Content-Type: application/json

Your backend → Gateway

POST https://api.centrobill.com/payment/applePaySession
Content-Type: application/json
{
    "domain": "yourstore.com"
}

Gateway → your backend (response)

{
  "epochTimestamp": 1680000000000,
  "expiresAt": 1680003600000,
  "merchantSessionIdentifier": "abc123...",
  "nonce": "xyz...",
  "merchantIdentifier": "merchant.com.example",
  "domainName": "yourstore.com"
}

Now the Apple Pay session is validated, and you can proceed with the payment step.

3. Process Apple Pay payment (your Backend → Gateway)

Once the customer authorizes the Apple Pay payment, the browser returns a payment.token. This token must be sent to your backend, which then forwards it to Gateway to complete the transaction.

Frontend → your backend

POST https://<your-backend-domain>/api/pay
Content-Type: application/json
{
  "paymentSource": {
    "type": "applePay",
    "token": {
      "version": "EC_v1",
      "data": "...",
      "signature": "...",
      "header": {
        "ephemeralPublicKey": "...",
        "publicKeyHash": "...",
        "transactionId": "..."
      }
    }
  },
  "orderId": "ORDER-123456",
  "amount": 10.00,
  "currency": "USD",
  "customer": {
    "email": "[email protected]"
  }
}

Your backend → Gateway

POST https://api.centrobill.com/payment
Content-Type: application/json
{
  "paymentSource": {
    "type": "applePay",
    "token": {
      "version": "EC_v1",
      "data": "...",
      "signature": "...",
      "header": {
        "ephemeralPublicKey": "...",
        "publicKeyHash": "...",
        "transactionId": "..."
      }
    }
  }
  ...
}

Gateway → your backend (response)

{
  "payment": {
    "description": "APPROVED",
    "action": "charge",
    ...
}

Apple Pay flow is now complete, and the payment can be processed through us.