Apple Pay Code Examples

Implement Apple Pay on your own checkout when using Embedded Integration.


Code examples for Apple Pay on Embedded Integration — merchant validation, token handling, and server-side payment.

📘

Hosted checkout Apple Pay requires no merchant code. See Apple Pay on Hosted Checkout.

🚧

Domain verification is required before Apple Pay works on your site. See Domain Verification.

❗️

Never post Apple Pay tokens directly from the browser to DigetPay. Send tokens to your server first.

High-level Flow

sequenceDiagram
    participant Browser as Safari Browser
    participant Merchant as Your Server
    participant Apple as Apple Pay
    participant API as DigetPay API

    Browser->>Merchant: Load Checkout
    Merchant->>Browser: ApplePaySession Configuration
    Browser->>Apple: Authorize Payment
    Apple-->>Browser: Payment Token
    Browser->>Merchant: POST Payment Token
    Merchant->>API: POST /payment/s2s/sale
    API-->>Merchant: APPROVED / PENDING / 3DS
    Merchant-->>Browser: Success or 3DS Page

Step 1 — Domain verification

  1. Obtain apple-developer-merchantid-domain-association file from DigetPay / Apple
  2. Host at https://yourdomain.com/.well-known/apple-developer-merchantid-domain-association
  3. Verify in Apple Developer portal

See Apple Pay Domain Verification.

Step 2 — Frontend (Safari)

The frontend implementation is identical for all backend languages.

Create an Apple Pay button, start an ApplePaySession, validate the merchant, then send the payment token to your backend.


<button id="apple-pay-button" style="display:none;">Buy with Apple Pay</button>
<script>
if (window.ApplePaySession && ApplePaySession.canMakePayments()) {
  document.getElementById('apple-pay-button').style.display = 'block';
  document.getElementById('apple-pay-button').onclick = function () {
    const request = {
      countryCode: 'SA',
      currencyCode: 'SAR',
      total: { label: 'Your Store', amount: '10.00' },
      supportedNetworks: ['visa', 'masterCard', 'mada'],
      merchantCapabilities: ['supports3DS'],
    };
    const session = new ApplePaySession(3, request);
    session.onvalidatemerchant = async (event) => {
      const res = await fetch('/apple-pay/validate-merchant.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ validationURL: event.validationURL }),
      });
      session.completeMerchantValidation(await res.json());
    };
    session.onpaymentauthorized = async (event) => {
      const res = await fetch('/apple-pay/process.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token: event.payment.token, orderId: 'ORD-1001' }),
      });
      if (res.ok) {
        session.completePayment(ApplePaySession.STATUS_SUCCESS);
      } else {
        session.completePayment(ApplePaySession.STATUS_FAILURE);
      }
    };
    session.begin();
  };
}
</script>
// public/checkout.js

session.onvalidatemerchant = async (event) => {

    const response = await fetch("/apple-pay/validate-merchant", {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            validationURL: event.validationURL
        })
    });

    session.completeMerchantValidation(await response.json());

};

session.onpaymentauthorized = async (event) => {

    const response = await fetch("/apple-pay/process", {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            token: event.payment.token,
            orderId: "ORD-1001"
        })
    });
Use the same Apple Pay JS pattern — `onvalidatemerchant` and `onpaymentauthorized` call your Flask/Django routes at `/apple-pay/validate-merchant` and `/apple-pay/process`.
Use the same Apple Pay JS pattern — `onvalidatemerchant` and `onpaymentauthorized` call your Spring endpoints at `/apple-pay/validate-merchant` and `/apple-pay/process`.

Step 2 — Merchant Validation

Before Apple Pay can display the payment sheet, Apple must verify that your website is authorized to accept Apple Pay payments.

Your backend receives the validationURL from the browser, sends a secure request to Apple's Merchant Validation service using your Merchant Identity Certificate, then returns the merchant session back to the browser.

Note

The Merchant Identity Certificate and validation request are provided during Apple Pay onboarding.
Contact the DigetPay Integration team if you need assistance configuring your merchant validation endpoint.


<?php

declare(strict_types=1);

// apple-pay/validate-merchant.php

header('Content-Type: application/json');

$input = json_decode(file_get_contents('php://input') ?: '', true);

$validationURL = $input['validationURL'] ?? '';

if (!$validationURL) {
    http_response_code(400);
    echo json_encode([
        'error' => 'validationURL is required'
    ]);
    exit;
}

/*
|--------------------------------------------------------------------------
| Merchant Validation
|--------------------------------------------------------------------------
|
| 1. Load Merchant Identity Certificate
| 2. Connect to Apple's validationURL
| 3. Send Merchant Identifier
| 4. Receive Merchant Session
| 5. Return Merchant Session to Browser
|
*/

http_response_code(501);

echo json_encode([
    'error' => 'Implement with DigetPay-provided merchant certificate'
]);
// routes/applePay.js

import express from "express";

const router = express.Router();

router.post(
    "/validate-merchant",
    express.json(),
    async (req, res) => {

        const { validationURL } = req.body;

        if (!validationURL) {
            return res.status(400).json({
                error: "validationURL is required"
            });
        }

        /*
        |--------------------------------------------------------------------------
        | Merchant Validation
        |--------------------------------------------------------------------------
        |
        | 1. Load Merchant Identity Certificate
        | 2. POST to Apple's validationURL
        | 3. Receive Merchant Session
        | 4. Return Merchant Session
        |
        */

        return res.status(501).json({
            error: "Implement with DigetPay-provided merchant certificate"
        });

    }
);

export default router;
# routes/apple_pay.py

from flask import Blueprint, request, jsonify

apple_pay_bp = Blueprint("apple_pay", __name__)


@apple_pay_bp.route("/apple-pay/validate-merchant", methods=["POST"])
def validate_merchant():

    validation_url = request.json.get("validationURL")

    if not validation_url:
        return jsonify({
            "error": "validationURL is required"
        }), 400

    """
    --------------------------------------------------------------
    Merchant Validation

    1. Load Merchant Identity Certificate
    2. POST to Apple's validationURL
    3. Receive Merchant Session
    4. Return Merchant Session
    --------------------------------------------------------------
    """

    return jsonify({
        "error": "Implement with DigetPay-provided merchant certificate"
    }), 501
@RestController
@RequestMapping("/apple-pay")
public class ApplePayController {

    @PostMapping("/validate-merchant")
    public ResponseEntity<Map<String, Object>> validateMerchant(
            @RequestBody Map<String, String> body) {

        String validationURL = body.get("validationURL");

        if (validationURL == null || validationURL.isBlank()) {
            return ResponseEntity.badRequest().body(
                    Map.of(
                            "error",
                            "validationURL is required"
                    )
            );
        }

        /*
        ------------------------------------------------------------------
        Merchant Validation

        1. Load Merchant Identity Certificate

        2. POST to Apple's validationURL

        3. Receive Merchant Session

        4. Return Merchant Session to Browser
        ------------------------------------------------------------------
        */

        return ResponseEntity.status(501).body(
                Map.of(
                        "error",
                        "Implement with DigetPay-provided merchant certificate"
                )
        );

    }

}

🚧

Merchant Validation

Your Merchant Identity Certificate and private key should never be exposed to the browser.

Merchant validation must always be performed securely on your backend server.

📘

Next Step

After the browser receives the Merchant Session, Apple Pay authorizes the payment and returns an encrypted payment token.

In the next step, your backend receives that token and sends the payment request to DigetPay.

Step 3 — Process Apple Pay Payment

After the customer authorizes the payment, Apple Pay returns an encrypted payment token.

Your backend receives the token, validates the request, maps the token into the DigetPay payment payload, then sends the payment request securely to DigetPay.

Apple Pay tokens should never be processed directly from browser JavaScript.

Always send the payment token to your backend first.

<?php

declare(strict_types=1);

require_once __DIR__ . '/../src/DigetPayEmbeddedClient.php';

$input = json_decode(file_get_contents('php://input') ?: '', true);

$token = $input['token'] ?? null;
$orderId = $input['orderId'] ?? ('ORD-' . time());

if (!$token) {
    http_response_code(400);

    echo json_encode([
        'error' => 'Apple Pay token is required'
    ]);

    exit;
}

$config = require __DIR__ . '/../config/digetpay.php';

$client = new DigetPayEmbeddedClient($config);

/*
|--------------------------------------------------------------------------
| Build DigetPay Apple Pay Request
|--------------------------------------------------------------------------
|
| Map Apple Pay token fields to the Embedded Sale payload.
|
| Confirm the final field mapping with the DigetPay
| Integration Team before going live.
|
*/

$response = [
    'status' => 'pending_implementation'
];

http_response_code(200);

echo json_encode($response);
// routes/applePay.js

router.post(
    "/process",
    express.json(),
    async (req, res) => {

        const { token, orderId } = req.body;

        if (!token) {
            return res.status(400).json({
                error: "Apple Pay token is required"
            });
        }

        /*
        |--------------------------------------------------------------------------
        | Build DigetPay Apple Pay Request
        |--------------------------------------------------------------------------
        |
        | Map Apple Pay token fields into the
        | Embedded Sale request payload.
        |
        | Confirm the final mapping with
        | DigetPay Integration Team.
        |
        */

        return res.json({
            status: "pending_implementation"
        });

    }
);
# routes/apple_pay.py

@apple_pay_bp.route("/apple-pay/process", methods=["POST"])
def process_apple_pay():

    token = request.json.get("token")
    order_id = request.json.get("orderId")

    if not token:
        return jsonify({
            "error": "Apple Pay token is required"
        }), 400

    """
    --------------------------------------------------------------

    Build DigetPay Apple Pay Request

    Map Apple Pay token fields to the Embedded
    Sale request payload.

    Confirm the final mapping with DigetPay
    Integration Team.

    --------------------------------------------------------------
    """

    return jsonify({
        "status": "pending_implementation"
    })
@PostMapping("/process")
public ResponseEntity<Map<String, String>> processApplePay(
        @RequestBody Map<String, Object> body) {

    Object token = body.get("token");
    String orderId = (String) body.get("orderId");

    if (token == null) {

        return ResponseEntity.badRequest().body(
                Map.of(
                        "error",
                        "Apple Pay token is required"
                )
        );

    }

    /*
    ----------------------------------------------------------------

    Build DigetPay Apple Pay Request

    Map Apple Pay token fields to the Embedded
    Sale request payload.

    Confirm the final mapping with
    DigetPay Integration Team.

    ----------------------------------------------------------------
    */

    return ResponseEntity.ok(
            Map.of(
                    "status",
                    "pending_implementation"
            )
    );

}

🚧

Apple Pay Token Mapping

Apple Pay payment tokens contain encrypted payment data that must be mapped to the DigetPay Embedded Sale request.

The exact payload mapping depends on your Apple Pay configuration.

Always confirm the final request format with the DigetPay Integration Team before moving to production.

📘

Once the payment request is submitted to DigetPay, handle the payment response just like a standard Embedded Integration transaction.

Depending on the response, you may receive:

- APPROVED — Payment completed successfully.
- PENDING — Payment is awaiting final confirmation.
- 3-D Secure HTML — Render the returned HTML to complete customer authentication when required.


Did this page help you?