Apple Pay Developer Guidelines

1. Introduction

This guide provides detailed instructions on integrating Apple Pay for web and in-app applications, including domain verification, payment processing, and security compliance.

2. Setup & Integration

We support Apple Pay for e-commerce web and iOS applications. The following diagrams show all actions on Bonum and Enterprise user side:

1. If you need web application integration:

Bonum Logo
2. If you need in-application integration:
Bonum Logo

3. Web App Integration

3.1 Domain Verification

Bonum Logo
1.INSTRUCTION

Domain verification is a required step for enabling Apple Pay on your website. It confirms that you own the domain and are authorized to accept payments via Apple Pay.
The process involves placing a special verification file, provided by us (Bonum PSP), on your domain's web server and notifying us to verify it with Apple.

2.PREREQUISITES

Before proceeding, ensure you have:
- Access to your web server or hosting environment to upload files.
- A valid domain name that matches the one used for your Apple Pay integration.

Bonum Logo
3. STEPS FOR DOMAIN VERIFICATION

Step 1: Obtain the Verification File
- Bonum will provide this file (File name is apple-developer-merchantid-domain-association)

Step 2: Place the File on Your Web Server
1. Create the required directory:
On your web server, create a directory named .well-known in the root directory of your domain (if it doesn’t already exist).

Example Path:
https://yourdomain.com/.well-known/

2. Upload the file:
Place the downloaded apple-developer-merchantid-domain-association file inside the .well-known directory.
Ensure the file is accessible publicly via the following URL:
https://yourdomain.com/.well-known/apple-developer-merchantid-domain-association

3. Content-Type:
The Apple Pay web merchant validation file must be served with a Content-Type of text/plain when accessed via a browser or HTTP request.

4. Verify file placement:
Open a browser and navigate to the file's URL. You should see the contents of the file displayed as plain text.

Step 3: Notify Us
- After placing the file, let us be informed by any available communication channels.

Step 4: Domain Verification by Apple
Our system will communicate with Apple to verify your domain. This process usually completes within a few minutes. We will inform merchants once the verification is successful.

Bonum Logo
4. TROUBLESHOOTING

Issue 1: File Not Found
Cause: The apple-developer-merchantid-domain-association file is not correctly placed in the .well-known directory. Solution: Verify the file path and ensure the file is accessible via its URL.

Issue 2: Access Denied
Cause: Your server has restricted access to the .well-known directory or file.
Solution: Check your server's permissions and ensure the .well-known directory and file are publicly accessible.

3.2 Web App Implementation

Bonum Logo

APPLE PAY   >   PSP   >   Web App

PREREQUISITES

Before proceeding, ensure that you have completed:

  • Merchant ID (The Merchant ID should have been provided by Bonum PSP)
  • Merchant Key (The Merchant Key should have been provided by Bonum PSP)
  • Demo Web App Source apple-pay-example-v1.0.0.zip (Source files should have been provided by Bonum PSP)
Bonum Logo

APPLE PAY   >   PSP   >   Demo Web App Source

A.) DEMO SOURCE FILES

Extract apple-pay-example-v1.0.0.zip file in a folder:

  • index.html - The frontend with the Apple Pay button and JavaScript integration.
  • server.js - The backend server (Node.js with Express) that handles Apple Pay merchant validation and payment processing.
  • package.json - Lists dependencies needed for your backend (e.g., express, node-fetch).
  • package-lock.json - Automatically generated to lock dependency versions.
Bonum Logo

Web App   >   Frontend Integration

B.) INDEX.HTML

Note: Apple Pay button implementation


Bonum Logo

Web App   >   Frontend Integration

C.) INDEX.HTML

Note:
1.Replace “REPLACE_YOUR_MERCHANT_IDEN_TIFIER_HERE”with your merchant ID.
2. "total” represents the amount to be charged. To break down the payment details, use "lineItems".
3. Create a new Apple Pay session.

function startApplePaySession() {
// Merchant-specific information
const merchantIdentifier = 'REPLACE_YOUR_MERCHANT_IDENTIFIER_HERE'; // Replace with your actual merchant ID

// Payment request details
const paymentRequest = {
  countryCode: 'MN', // Country code for Mongolia
  currencyCode: 'MNT', // Mongolian Tugrik
  supportedNetworks: ['visa', 'masterCard', 'amex'], // Supported card networks
  merchantCapabilities: ['supports3DS'], // Security capabilities
  displayName: 'Your Merchant Name', // Name displayed on the payment sheet
  total: {
    label: 'Your Merchant Name', // Total summary label
    amount: '100', // Total amount (in whole numbers for MNT (100.00 is invalid, 100 - is valid))
  },
  lineItems: [ //optional
    { label: 'Product A', amount: '200' },
    { label: 'Discount', amount: '-100' },
  ],
  applicationData: btoa(merchantIdentifier), // Base64 encoded merchant ID
};

// Ensure amount is a whole number for Mongolian Tugrik (MNT)
if (paymentRequest.currencyCode === 'MNT' && !Number.isInteger(Number(paymentRequest.total.amount))) {
  alert('Amounts in Mongolian Tugrik (MNT) must be whole numbers without decimal points.');
  return;
}

// Create a new Apple Pay session
const session = new ApplePaySession(3, paymentRequest);

// Step 3: Validate the merchant during the payment session
session.onvalidatemerchant = async (event) => {
  try {
    const response = await fetch('https://psp.bonum.mn/api/merchant/validate', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ validationURL: event.validationURL }),
    });
    const merchantSession = await response.json();
    session.completeMerchantValidation(merchantSession);
  } catch (error) {
    console.error('Merchant validation failed:', error);
    session.abort();
  }
};
Bonum Logo

Web App   >   Frontend Integration

D.) INDEX.HTML

Note: Handle payment authorization.

// Step 4: Handle payment authorization
session.onpaymentauthorized = async (event) => {
    const token = event.payment.token;

    try {
      //frontend will send token to its backend. merchant can customize to their needs.
      const response = await fetch('http://localhost:3000/api/payment/authorize', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token, orderId: 'REPLACE_ORDER_ID_HERE' }),
      });
      const result = await response.json();

      // merchant backend response parsing, customize to your needs.
      if (result.success) {
        session.completePayment(ApplePaySession.STATUS_SUCCESS); //mandatory
        ///alert("Payment succeeded: $ {result.description}");
      } else {
        session.completePayment(ApplePaySession.STATUS_FAILURE); //mandatory
        // alert("Payment failed: $ {result.description}"");
      }
    } catch (error) {
      console.error('Error processing payment:', error);
      session.completePayment(ApplePaySession.STATUS_FAILURE);
      alert('Unexpected error occurred while processing payment.');
    }
  };

  // Step 5: Handle payment cancellation
  session.oncancel = () => {
    console.log('Payment was canceled by the user.');
    alert('Payment was canceled.');
  };

  // Step 6: Begin the session
  session.begin();
}
Bonum Logo

Web App   >   The backend Integration

E.) SERVER.JS

Note: Handle payment authorization and process the payment.
Replace “REPLACE_YOUR_MERCHANT_KEY"with your merchant key.

const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const cors = require('cors');
const app = express();
const PORT = 3000;

// Allow specific origins (replace "http://example.com" with your frontend's URL)
app.use(cors({
  origin: 'https://psp.bonum.mn', // Allow this specific origin
}));

// Middleware: Parses incoming JSON request bodies
app.use(bodyParser.json());

/**
 * Endpoint to process payment authorization.
 * The client sends a token and an orderId, which are forwarded to the PSP (Payment Service Provider).
 */
app.post('/api/payment/authorize', async (req, res) => {
  const { token, orderId } = req.body;

  // Step 1: Validate incoming request data
  if (!token || !orderId) {
    return res.status(400).json({
      success: false,
      message: 'Missing token or orderId',
    });
  }

  try {
    // Step 2: Forward the payment data to the PSP
    const response = await axios.post(
      'https://psp.bonum.mn/api/payment/process', // PSP endpoint URL
      {
        token,          // Payment token received from Apple Pay
        order_id: orderId, // Merchant invoice/order id
      },
      {
        headers: {
          'Content-Type': 'application/json',
          'x-merchant-key': 'REPLACE_YOUR_MERCHANT_KEY', // Replace with your actual merchant key
        },
      }
    );
        console.log('resp', response.data);
    // Step 3: Respond to the client with the PSP's response
    res.json({
      success: response.data.success,       // Indicates if the payment was successful
      status_code: response.data.status_code, // PSP's status code for the operation
      orderId: response.data.orderId,       // The order ID provided in the response
      description: response.data.desc,      // Additional information about the payment
    });
  } catch (error) {
    console.error('Error processing payment:', error.message);

    // Step 4: Handle errors from the PSP or network issues
    if (error.response) {
      // Errors returned directly by the PSP
      return res.status(error.response.status).json({
        success: error.response.data.success,       // Whether the PSP recognized the payment as successful
        status_code: error.response.data.status_code, // PSP-specific error code
        orderId: error.response.data.orderId,       // Order ID (if available)
        description: error.response.data.desc,      // PSP-provided error description
      });
    }

    // Step 5: Handle unexpected or generic errors (network, server, etc.)
    res.status(500).json({
      success: false,
      status_code: 500,
      orderId,                           // Original order ID for traceability
      description: 'Unexpected error occurred while processing payment.', // Generic error message
    });
  }
});

// Start the Express server
app.listen(PORT, () => {
  console.log("Server is running on http://localhost:" +PORT);
});
Bonum Logo

Web App   >   The backend integration

F.) CHECK PAYMENT

Note: You can use the /api/payment-log/read API for handling any payment failure cases.
Replace “REPLACE_YOUR_MERCHANT_KEY" with your merchant key.
This API call should be executed on your backend.

func checkPaymentByOrderId(orderId: String) {
  
  let manager = AFHTTPSessionManager()
  manager.requestSerializer = AFJSONRequestSerializer()
  manager.responseSerializer = AFJSONResponseSerializer()
  manager.responseSerializer.acceptableContentTypes = manager.responseSerializer.acceptableContentTypes?.union(["application/json"])
  //TODO: set Merchant Key here. Bonum will provide Merchant Key.
  manager.requestSerializer.setValue("SET-YOUR-MERCHANT-KEY-HERE", forHTTPHeaderField: "x-merchant-key")
  
  
  //Demo URL. Note: This URL charges the bank transaction. Please use small amount when you test
  var urlString = "https://testpsp.bonum.mn/api/payment-log/read"
  //Production URL. When you push your Build to the production
  //var urlString = "https://psp.bonum.mn/api/payment-log/read"
  
  urlString = urlString + "?order_id=" + orderId
  // Convert the JSON object to a JSON string
  print("API Url: \(urlString)")
  
  manager.get(urlString,
              parameters: nil,
              headers: nil, progress: { progress in
      print("Download progress: \(progress.totalUnitCount)")
  }, success: { task, responseObject in
      print("Transactions for Order ID: \(orderId)")
      print("GET response: \(responseObject ?? "No response")")
  }, failure: { task, error in
      print("Error on GET request: \(error.localizedDescription)")
  })
}
Bonum Logo

Web App   >   The backend integration

G.) CHECK PAYMENT RESPONSE

Note: "success": false indicates that the transaction failed for some reason.

Note: "success": true indicates that the transaction was processed successfully.

[
    {
      "merchant_order_id": "9876543",
      "amount": 5000,
      "success": false,
      "createdAt": "2025-01-24T03:22:03.135Z"
    },
    {
      "merchant_order_id": "9876543",
      "amount": 5000,
      "success": true,
      "createdAt": "2025-01-24T03:22:03.135Z"
    }
]

4. IOS App Integration

4.1 Apple Payment Certificate Creation

Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

INSTRUCTION

Follow the instruction to generate Apple Payment Certificate. After certificate creation, please send us certificate file.

1. Go to Apple Developer Account
2. Log in with your developer account
Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

A.) SELECT "IDENTIFIERS"

Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

B.) SELECT MERCHANT IDS

Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

C.) CLICK + ADD

Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

D.) CLICK CONTINUE

Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

E.) FILL DESCRIPTION AND MERCHANT ID AS BELOW:

Merchant ID: [ENTER YOUR MERCHANT ID]
Note: Your Merchant ID has been sent to you via email from Bonum PSP. Please disregard merchant.portal.mn on the screen shot.
Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

F.) CLICK REGISTER:

Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

G.) ENTER MERCHANT DETAIL:

Merchant ID: merchant.portal.mn


Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

H.) CREATE APPLE PAYMENT PROCESS CERTIFICATE:

Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

I.) CLICK CONTINUE:

Note: Select "No" for the question.

Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

J.) UPLOAD:

Upload attached "SigningCertRequest.csr"
Note: The .csr file has been sent to you via email from Bonum PSP.

Bonum Logo
Bonum Logo

APPLE PAY   >   PSP   >   Payment Certificate

J.) DOWNLOAD

Download Payment Certificate file and send Payment Certificate file to us.

Bonum Logo

4.2 In-App Implementation

Bonum Logo

APPLE PAY   >   PSP   >   In App

PREREQUISITES


1. Before proceeding, ensure that you have completed:
  • Xcode Project
  • Merchant ID (The Merchant ID should have been provided by Bonum PSP, and you needed to create your Merchant ID according to the provided instructions.)
  • Your Apple Payment Certificate (This certificate should have been successfully installed on the Bonum PSP server.)
  • Merchant Key (The Merchant Key should have been provided by Bonum PSP)
Bonum Logo

XCODE   >   Select Target   >   Signing & Capabilities

A.) ADD APPLE PAY CAPABILITY
Bonum Logo
Bonum Logo

XCODE   >   Select Target   >   Signing & Capabilities

B.) CLICK + CAPABILITY

Search as “Apple Pay”

img2
Bonum Logo

XCODE   >   Select Target   >   Signing & Capabilities

C.) SELECT APPLE PAY

After Apple Pay is enabled, it appears as shown below.
Your Merchant ID should be displayed in place of 'merchant.your.merchant.id'

img3
Bonum Logo

XCODE   >   Select Target   >   Signing & Capabilities

D.) CHECK YOUR MERCHANT ID

Your Merchant ID should be displayed in place of 'merchant.your.merchant.id' .

img4
Bonum Logo

XCODE   >   Select Target   >   ApplePayViewController

E.) EXAMPLE CODE IN SWIFT
ApplePayViewController.swift should have been provided by Bonum PSP.
Note: Please read the instruction and replace //TODO: highlighted code with your own code.
The important items to replace in the code are:
1. Replace “merchant.your.merchant.id” with your Merchant ID.
2. Replace “SET-YOUR-MERCHANT-KEY-HERE” with your Merchant Key.
3. Use the order ID (invoice, SKU, etc.) instead of the generateRandomOrderString function. This will allow any payment item to be uniquely identified. We will use it for transaction verification.

ApplePayViewController.swift uses PassKit and “AFNetworking”.
  • PassKit is a framework provided by Apple that allows developers to integrate Apple Pay
  • AFNetworking is an open-source networking library used for sending payment payload data to the Bonum PSP server.
  • Your view controller should implement the PKPaymentAuthorizationControllerDelegate methods.
Bonum Logo

XCODE   >   ApplePayViewController.swift

F.) PKPAYMENTBUTTON IMPLEMENTATION
override func viewDidLoad() {
    super.viewDidLoad()
    
    //TODO: Implement PKPaymentButton with its style here.
    var button: UIButton?
    //Checks whether payment can be made or not.
    if PKPaymentAuthorizationController.canMakePayments() {
        button = PKPaymentButton(paymentButtonType: .buy, paymentButtonStyle: .black)
        button?.addTarget(self, action: #selector(startApplePay), for: .touchUpInside)
    } else if PKPaymentAuthorizationController.canMakePayments(usingNetworks: [.masterCard, .visa, .amex]) {
        button = PKPaymentButton(paymentButtonType: .setUp, paymentButtonStyle: .black)
        button?.addTarget(self, action: #selector(setupPressed(_:)), for: .touchUpInside)
    }
    
    if let button = button {
        button.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(button)
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }
}
Bonum Logo

XCODE   >   ApplePayViewController.swift

G.) START PAYMENT IN APP

Note: Set the amount and label on the PKPaymentSummaryItem. Selling a multiple items differs from selling single item. See examples in the code.


@objc func startApplePay() {
    guard PKPaymentAuthorizationController.canMakePayments() else {
        print("Apple Pay is not available on this device.")
        return
    }
    
    guard PKPaymentAuthorizationController.canMakePayments(usingNetworks: [.masterCard, .visa, .amex]) else {
        print("Apple Pay is not set up with a supported card.")
        return
    }
    
    let paymentRequest = PKPaymentRequest()
    paymentRequest.merchantIdentifier = "merchant.your.merchant.id" // TODO: Set Your Merchant ID here
    paymentRequest.supportedNetworks = [.masterCard, .visa, .amex]
    paymentRequest.merchantCapabilities = [.threeDSecure]
    paymentRequest.countryCode = "MN" //Country Code of Mongolia
    paymentRequest.currencyCode = "MNT" //Currency code of tugrik
            
    //TODO: One-time purchase for multiple items. Replace the label and amount here.
    let item1 = PKPaymentSummaryItem(label: "Apple", amount: NSDecimalNumber(string: "5.1"))
    let item2 = PKPaymentSummaryItem(label: "Banana", amount: NSDecimalNumber(string: "4.12"))
    //TODO: This item represents the total of all items. Its amount should be the sum of all individual items. For example: 5.1 + 4.12 = 9.22.
    let total = PKPaymentSummaryItem(label: "Total", amount: NSDecimalNumber(string: "9.22"))
    paymentRequest.paymentSummaryItems = [item1, item2, total]
    
    // TODO: One-time purchase for a single item. Replace the label and price here.
    // let total = PKPaymentSummaryItem(label: "Kiwi", amount: NSDecimalNumber(string: "10"))
    // paymentRequest.paymentSummaryItems = [total]
    
    let paymentController = PKPaymentAuthorizationController(paymentRequest: paymentRequest)
    paymentController.delegate = self
    
    paymentController.present { success in
        if success {
            print("Payment sheet presented successfully.")
        } else {
            print("Failed to present payment sheet.")
        }
    }
}
Bonum Logo

XCODE   >   ApplePayViewController.swift

H.) HANDLE PAYMENT AUTHORIZATION

Note:
processPaymentData function will process the transaction.
convertPKPaymentToJSON function will create Payload JSON object with order_id for payment process.


func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler: @escaping (PKPaymentAuthorizationResult) -> Void) {
    print("Payment authorized: \(payment.token)")
    print("Payment Network: \(String(describing: payment.token.paymentMethod.network))")
    print("Payment Transaction Identifier: \(payment.token.transactionIdentifier)")
    processPaymentData(payment) { result in
        handler(result)
    }
}

func convertPKPaymentToJSON(payment: PKPayment, orderId: String) -> Any? {
    // Extract the payment token details
    let paymentToken = payment.token
    let paymentData = convertToJson(data: paymentToken.paymentData)
    let transactionIdentifier = paymentToken.transactionIdentifier
    let paymentMethod = paymentToken.paymentMethod
    // Extract billing and shipping contacts
    let billingContact = payment.billingContact
    let shippingContact = payment.shippingContact
    // Construct the JSON object
    var jsonObject: [String: Any] = [:]
    
    jsonObject["token"] = [
        "paymentData": paymentData,
        "transactionIdentifier": transactionIdentifier,
        "paymentMethod": [
            "displayName": paymentMethod.displayName ?? "",
            "network": paymentMethod.network?.rawValue ?? "",
            "type": paymentMethod.type == .debit ? "debit" :
                paymentMethod.type == .credit ? "credit" : "unknown"
        ],
    ]
    //If unnecessary, don't use
    if let billing = billingContact {
        jsonObject["billingContact"] = [
            "givenName": billing.name?.givenName ?? "",
            "familyName": billing.name?.familyName ?? "",
            "emailAddress": billing.emailAddress ?? "",
            "phoneNumber": billing.phoneNumber?.stringValue ?? ""
        ]
    }
    //If unnecessary, don't use
    if let shipping = shippingContact {
        jsonObject["shippingContact"] = [
            "givenName": shipping.name?.givenName ?? "",
            "familyName": shipping.name?.familyName ?? "",
            "emailAddress": shipping.emailAddress ?? "",
            "phoneNumber": shipping.phoneNumber?.stringValue ?? ""
        ]
    }
    //Your ORDER ID should be set here
    jsonObject["order_id"] = orderId
    return jsonObject
}
Bonum Logo

XCODE   >   ApplePayViewController.swift

I.) PROCESS PAYMENT

Note:
processPaymentData function will process the transaction.
Recommendation: Server-to-Server /api/payment/process API call. This API call should be executed on your backend.


func processPaymentData(_ payment: PKPayment, completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
    let manager = AFHTTPSessionManager()
    manager.requestSerializer = AFJSONRequestSerializer()
    manager.responseSerializer = AFJSONResponseSerializer()
    manager.responseSerializer.acceptableContentTypes = manager.responseSerializer.acceptableContentTypes?.union(["application/json"])
    //TODO: set Merchant Key here. Bonum will provide Merchant Key.
    manager.requestSerializer.setValue("SET-YOUR-MERCHANT-KEY-HERE", forHTTPHeaderField: "x-merchant-key")
    
    //TODO: Set Payment process API url here
    //Demo URL. Note: This URL charges the bank transaction. Please use small amount when you test
    let urlString = "https://testpsp.bonum.mn/api/payment/process"
    //Production URL. When you push your Build to the production
    //let urlString = "https://psp.bonum.mn/api/payment/process"
    
    //TODO: set your order/invoice/sku/ id here.
    let orderId = generateRandomOrderString(length: 20)
    orderIdLbl.text = orderId
    let jsonPayload = convertPKPaymentToJSON(payment: payment, orderId: orderId)
    
    // Convert the JSON object to a JSON string
    if let jsonData = try? JSONSerialization.data(withJSONObject: jsonPayload ?? "", options: .prettyPrinted) {
        let jsonString = String(data: jsonData, encoding: .utf8)
        print("Payload data: \(jsonString ?? "No response")")
    }
    
    manager.post(urlString, parameters: jsonPayload, headers: nil, progress: { progress in
        print("Download progress: \(progress.totalUnitCount)")
    }, success: { task, responseObject in
        print("POST response: \(responseObject ?? "No response")")
        // Safely cast responseObject to [String: Any]
        if let responseDict = responseObject as? [String: Any] {
            // Access the boolean field
            if let success = responseDict["success"] as? Bool {
                print("Success: \(success)")  // Output: Success: true/false
                if success {
                    let successResult = PKPaymentAuthorizationResult(status: .success, errors: nil)
                    completion(successResult)
                } else {
                    let failureResult = PKPaymentAuthorizationResult(status: .failure, errors: nil)
                    completion(failureResult)
                }
            } else {
                print("Key 'success' is missing or not a boolean.")
                let failureResult = PKPaymentAuthorizationResult(status: .failure, errors: nil)
                completion(failureResult)
            }
        } else {
            print("Failed to parse response as dictionary.")
            let failureResult = PKPaymentAuthorizationResult(status: .failure, errors: nil)
            completion(failureResult)
        }
        
    }, failure: { task, error in
        print("Error on GET request: \(error.localizedDescription)")
        let failureResult = PKPaymentAuthorizationResult(status: .failure, errors: nil)
        completion(failureResult)
    })
}
Bonum Logo

XCODE   >   ApplePayViewController.swift

J.) PAYLOAD DATA FOR PAYMENT PROCESS
{
   "token":{
      "paymentMethod":{
         "type":"debit",
         "network":"MasterCard",
         "displayName":"MasterCard 1588"
      },
      "transactionIdentifier":"4be88bbec5d887d696b536b87d9a28a25d5ca5e6cbbac6e06bb3c14b0967f16f",
      "paymentData":{
         "data":"lAGF6hAH+z\/vZz1UG",
         "signature":"BkAiA+zmtT6wYi6JxyrpjEqYSYRw82kMhjxXSZIvyd1G9zNgAAAAAAAA==",
         "header":{
            "publicKeyHash":"EalQwLcwQ0Mqh9R1qWtAwsO4Eht+6T2w9pMNypx2sP8=",
            "ephemeralPublicKey":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzy8Acl6MTWG7luHdWeA\/sI+7mXMczg698cdOB9lYJBVVg2WYNgP4Ila4+vLfqvYQmBurR7wK1UQ2W8Ma2kNUAA==",
            "transactionId":"4be88bbec5d887d696b536b87d9a28a25d5ca5e6cbbac6e06bb3c14b0967f16f"
         },
         "version":"EC_v1"
      }
   },
   "order_id":"1nnuqsc4j6bzpl5hm26z"
}
Bonum Logo

XCODE   >   ApplePayViewController.swift

K.) CHECK PAYMENT

Note: You can use the /api/payment-log/read API for handling any payment failure cases.

Recommendation: Server-to-Server /api/payment-log/read API call.
This API call should be executed on your backend.

func checkPaymentByOrderId(orderId: String) {
    
    let manager = AFHTTPSessionManager()
    manager.requestSerializer = AFJSONRequestSerializer()
    manager.responseSerializer = AFJSONResponseSerializer()
    manager.responseSerializer.acceptableContentTypes = manager.responseSerializer.acceptableContentTypes?.union(["application/json"])
    //TODO: set Merchant Key here. Bonum will provide Merchant Key.
    manager.requestSerializer.setValue("SET-YOUR-MERCHANT-KEY-HERE", forHTTPHeaderField: "x-merchant-key")
    
    
    //Demo URL. Note: This URL charges the bank transaction. Please use small amount when you test
    var urlString = "https://testpsp.bonum.mn/api/payment-log/read"
    //Production URL. When you push your Build to the production
    //var urlString = "https://psp.bonum.mn/api/payment-log/read"
    
    urlString = urlString + "?order_id=" + orderId
    // Convert the JSON object to a JSON string
    print("API Url: \(urlString)")
    
    manager.get(urlString,
                parameters: nil,
                headers: nil, progress: { progress in
        print("Download progress: \(progress.totalUnitCount)")
    }, success: { task, responseObject in
        print("Transactions for Order ID: \(orderId)")
        print("GET response: \(responseObject ?? "No response")")
    }, failure: { task, error in
        print("Error on GET request: \(error.localizedDescription)")
    })
}
Bonum Logo

XCODE   >   ApplePayViewController.swift

L.) CHECK PAYMENT RESPONSE

Note: "success": false indicates that the transaction failed for some reason.

Note: "success": true indicates that the transaction was processed successfully.

[
    {
      "merchant_order_id": "9876543",
      "amount": 5000,
      "success": false,
      "createdAt": "2025-01-24T03:22:03.135Z"
    },
    {
      "merchant_order_id": "9876543",
      "amount": 5000,
      "success": true,
      "createdAt": "2025-01-24T03:22:03.135Z"
    }
]

5. SUPPORT & CONTACT

References:
Apple Pay on Web Demo by Apple - https://applepaydemo.apple.com
Apple Pay Human Interface Guidelines - https://developer.apple.com/design/human-interface-guidelines/apple-pay
Apple Pay Marketing Resources - https://developer.apple.com/apple-pay/marketing
Apple Pay Marketing Guidelines - https://developer.apple.com/apple-pay/marketing


If you need further assistance, please contact our team:
- Email: [email protected]
- Phone: +976 7200-5000