• Documentation
  • API Reference
  • Documentation
  • API Reference
Expand All Collapse All
< BACK TO HOME
  • General
    • Introduction to APMs
    • APM Input Fields and APIs
    • APM subMethod Class
    • Account Details Capture
    • APM Countries and Currencies
  • US and Canada Guides
    • ACH
    • Interac Instant
    • Mazooma
    • PayNearMe
    • PlayPlus
      • PlayPlus (REST)
      • PlayPlus (Web SDK)
    • VIP Preferred
      • VIP Preferred (REST)
      • VIP Pref. (Web SDK/Checkout)
  • Europe Guides
    • Okto Cash
    • Open Banking
  • Global Guides
    • Apple Pay
      • Registering with Apple Pay
        • (Manually) Register in the Apple System
          • Create an Apple ID
          • Enroll in the Apple Developer Program
            • Submit an Enrollment Request
            • Complete the Enrollment Process
            • Activate your Apple Developer Program Account
          • Register a Merchant ID in the Apple System
            • Create a Merchant ID
            • Create a Payment Processing Certificate
            • Create a Merchant Identity Certificate
            • Register and Verify Your Domain
      • Nuvei Apple Pay Implementations
        • Payment Page using IFrame
        • Static Apple Pay Button
        • Static Pay Button (Web SDK)
        • Dynamic Apple Pay Button
      • Apple Pay Integration
        • Apple Pay Guide (REST API)
        • Apple Pay Guide (Web SDK)
        • Apple Pay Guide (Checkout)
        • Apple Pay Integration Testing
    • Google Pay
      • Google Pay (REST API)
      • Google Pay (Web SDK)
      • Google Pay (Checkout)
    • Neteller
    • PayPal
    • Skrill
    • Visa Checkout
  • Latin America Guides
    • PIX
    • PIX Payouts
    • STPmex
  • Asia Pacific Guides
    • Alipay HK
    • Dana
    • DragonPay
    • GCash
    • India Payouts
    • KakaoPay
    • TouchnGo
    • TrueMoney

Dynamic Apple Pay Button

On this page:
  • Overview
  • Prerequisites and Notes
  • 1. Create a Button Handler
  • 2. Create a Result Handler
  • 3. Frontend to Backend Transfer
  • 4. Initiate a Session
    • 4.1 For a Regular Payment
    • 4.2 For a Recurring Payment
  • 5. Send the Payment Request
  • 6. Backend to Frontend Transfer
  • Appendix
    • Example JavaScript code for a Dynamic Apple Pay Button

Overview

This topic describes how to create the JavaScript code to do the following:

  • Integrate the Apple Pay button into your own payment page.
  • Allow the total transaction amount to be changed from inside the Apple Pay payload, based on customer choices.
  • Use the finalized payment details to send a /payment request for a regular payment or an initial recurring payment.

Prerequisites and Notes

  1. Include the Nuvei “CDN”  library by adding this script tag to your payment page.
    This is a light JavaScript wrapper over the Apple API provided by Nuvei, which is used to verify identity with Nuvei servers.
    <script type="text/javascript" 
    src="https://cdn.safecharge.com/safecharge_resources/v1/sc_api_applepay.min.js"></script>
  2. Before beginning, it is important to be familiar with how to enable Apple Pay on the web using Apple Pay JS or the Payment Request API.It is strongly recommended reading about these topics on the Apple Pay site by referring to:
    • For specific details required in this procedure: How to Display Apple Pay Buttons
    • For a general overview: Apple Pay on the Web Interactive Demo
  3. One of the main differences between the Dynamic JavaScript button solution and the other implementations (Static Apple Pay Button, Static Apple Pay Button using Web SDK, and Payment Page using IFrame), is that it allows you to change the transaction total amount inside the Apple Pay payload, based on customer choices collected in the Apple Pay overlay.
    For example, you can calculate the shipping price based on the billing address, or the shipping option selected, or the country/area for delivery, or taxes.

An example of the following steps is shown in the Example JavaScript code for a Dynamic Apple Pay Button section.

1. Create a Button Handler

Initialize the button handler.

When the button is clicked, invoke the overlay to show relevant fields according to your business requirements, and prompt the customer to enter the relevant details, for example: currency, amount, line items, billing address, shipping address, etc.

2. Create a Result Handler

Now that the customer has made all their decisions (e.g  which shipping method etc.) and the final payment amount is known, invoke the button handler to call a function (defined in sc_api_applepay.min.js), which handles the session, collects the decrypted data from the device, and returns the following data:

  • The authorized payment token (mobileToken)
  • Optional address fields
  • A completion function.

Define a callback function to receive this data.

3. Frontend to Backend Transfer

From the frontend, send the data gathered by the button handler to your server (backend), (so you can use it to send the /payment request).

While the Apple Pay overlay is open it is preferable that all these operations use async calls to the backend.

4. Initiate a Session

Sending an /openOrder API call has two main functions:

  • Authenticates you as our merchant using your given credentials.
  • Sets up an order in the Nuvei system containing the transaction details, and generates a sessionToken, which is referenced later in the payment flow.

    This call must be performed on your backend server, never on the frontend. The /openOrder call described here requires your password, which should NOT be exposed client-side.

    It is also important to set the order from the server side to prevent front-end user manipulation.

    Before using the Server SDK, make sure to initialize the SDK before any request by including the relevant SDK initialization.

    You can simulate the /openOrder functionality using a Postman script (follow our guide on using this here). Then use this Postman script to run and test the /openOrder method.

Sending an/openOrder Request

Follow the relevant steps:

  • 4.1 For a Regular Payment
  • 4.2 For a Recurring Payment

3DS_HIDDEN_TEXT

  • 4.2 For an Initial Recurring Payment

4.1 For a Regular Payment

For a regular (non-recurring) payment, send an /openOrder request using the data received on your server from the frontend (in the previous step), and include:

  • The mandatory and other relevant input parameters (as described in the /openOrder topic).
  • Include a checksum, which is the SHA256 hash of the following concatenated fields, in this order, with no spaces, and no separators between the fields:
    merchantId, merchantSiteId,clientRequestId, amount, currency, timeStamp, merchantSecretKey

    Example /openOrder Request
    {  
        "merchantId":"<your merchantId goes here>",
        "merchantSiteId":"<your merchantSiteId goes here>",
        "clientUniqueId":"<unique transaction ID in merchant system>",
        "clientRequestId":"<unique request ID in merchant system>",
        "currency":"USD",
        "amount":"200",
        "billingAddress":{
            "email":"john.smith@email.com",
            "country":"US"
        },
        "timeStamp":"<YYYYMMDDHHmmss>",
        "checksum":"<calculated checksum>"
    }
    <?php
    $safecharge = new \SafeCharge\Api\RestClient([
    'environment' => \SafeCharge\Api\Environment::INT,
    'merchantId' => '<your merchantId>',
    'merchantSiteId' => '<your merchantSiteId>',
    'merchantSecretKey' => '<your merchantSecretKey>',
    ]);
    
    $openOrderRequest = $SafeCharge->getPaymentService()->openOrder([
        'clientUniqueId'    => '<unique transaction ID in merchant system>',
        'clientRequestId'   => '<unique request ID in merchant system>',
        'currency'          => 'USD',
        'amount'            => '200',
        'billingAddress' => [
            'country'   => "US",
            "email"     => "john.smith@email.com",
        ],
    ]);
    ?>
    public static void main(String[] args) {
    // for initialization 
    String merchantId = "<your merchantId>";
    String merchantSiteId = "<your merchantSiteId>";
    String merchantKey = "<your merchantKey>";
    safecharge.initialize(merchantId, merchantSiteId, merchantKey, Constants.HashAlgorithm.SHA256);
    
    //for openOrder
    String clientUniqueId = "<unique transaction ID in merchant system>";
    String clientRequestId = "<unique request ID in merchant system>";
    String currency = "USD";
    String amount = "200";
    
    UserAddress billingAddress = new UserAddress();
    billingAddress.setEmail("john.smith@email.com");
    billingAddress.setCountry("US");
    
    Safecharge safecharge = new Safecharge();
    SafechargeResponse response = safecharge.openOrder(clientRequestId,
    clientUniqueId, null, null, null, null, currency, amount,
    null, null, null, null, billingAddress, null, null, null,
    null, null, null, null, null, null, null);
    }
    var safecharge = new Safecharge(
    "<your merchantKey>",
    "<your merchantId>",
    "<your merchantSiteId>",
    "<your server host value>",
    HashAlgorithmType.SHA256
    );
    var response = safecharge.OpenOrder(
     "USD",
     "200",
     clientUniqueId: "<unique transaction ID in merchant system>",
     clientRequestId: "<unique request ID in merchant system>",
     billingAddress: new UserAddress
     {
         Email = "john.smith@email.com",
         Country = "US",
     }
    );
    const safecharge = require('safecharge');
    safecharge.initiate(<merchantId>, <merchantSiteId>, <merchantSecretKey>, <env>);
    safecharge.paymentService.openOrder({
        'clientUniqueId'   : '<unique transaction ID in merchant system>',
        'clientRequestId'  : '<unique request ID in merchant system>',
        'currency'         : 'USD',
        'amount'           : '200'
        'billingAddress': {
            'email': "john.smith@email.com",
            'country': "US"
        },
    }, function (err, result) {
        console.log(err, result)
    });

4.2 For a Recurring Payment

For a recurring payment, perform the steps in the 4.1 For a Regular Payment section, and also include the following parameters in the request:

  • "userTokenId": "<unique customer identifier in merchant system>"
  • For an initial recurring payment include: "isRebilling": "0"
  • For a subsequent recurring payment include: "isRebilling": "1"
Example /openOrder Request for a Recurring Payment
{
  "merchantId": "<your merchantId goes here>",
  "merchantSiteId": "<your merchantSiteId goes here>",
  "clientUniqueId": "<unique transaction ID in merchant system>",
  "clientRequestId": "<unique request ID in merchant system>",
  "userTokenId": "<unique customer identifier in your system>",
  "isRebilling": "<0 for initial recurring payment  or  1 for subsequent recurring payment>",
  "currency": "USD",
  "amount": "200",
  "billingAddress":{
    "email": "john.smith@email.com",
    "country": "US"
  },
  "timeStamp": "<YYYYMMDDHHmmss>",
  "checksum": "<calculated checksum>"
}

3DS_HIDDEN_TEXT

4.2 For an Initial Recurring Payment

For an initial recurring payment, perform the steps in the 4.1 For a Regular Payment section, and also include the following parameters in the request:

  • "userTokenId": "<unique customer identifier in merchant system>"
  • "isRebilling": "0"
Example /openOrder Request for an Initial Recurring Payment
{
  "merchantId": "<your merchantId goes here>",
  "merchantSiteId": "<your merchantSiteId goes here>",
  "clientUniqueId": "<unique transaction ID in merchant system>",
  "clientRequestId": "<unique request ID in merchant system>",
  "userTokenId": "<unique customer identifier in your system>",
  "isRebilling": "0",
  "currency": "USD",
  "amount": "200",
  "billingAddress":{
    "email": "john.smith@email.com",
    "country": "US"
  },
  "timeStamp": "<YYYYMMDDHHmmss>",
  "checksum": "<calculated checksum>"
}
Example /openOrder Response
{
    "sessionToken": "9610a8f6-44cf-4c4f-976a-005da69a2a3b",
    "orderId": "39272",
    "merchantId": "427583496191624621",
    "merchantSiteId": "142033",
    "clientUniqueId": "12345",
    "clientRequestId": "1484759782197",
    "internalRequestId": "866",
    "status": "SUCCESS",
    "errCode": "0",
    "reason": "",
    "version": "1.0"
}

5. Send the Payment Request

On your server, use the data received from the frontend (in the previous step) to send the /payment request according to the steps in the relevant topic:

  • For a “non-recurring” payment, continue with the steps in the Payments topic.
  • For a recurring payment, continue with the steps in the Recurring Payment topic.

3DS_HIDDEN_TEXT

  • For a “non-recurring” 3D Secure payment, continue with the steps in the 3DS Payments with externalToken topic.
  • For an initial recurring payment, continue with the steps in the Initial Recurring Payment topic.

6. Backend to Frontend Transfer

Invoke the button handler to call the completion function to display the transaction result (received from the backend) to the customer, and close the overlay correctly.
The result parameter returned is set as follows:

  • "result": "true" means the transaction was successful.
  • "result": "false" means the transaction failed.
Congratulations! You have successfully completed the integration steps!
You can now test your Apple Pay implementation in the Apple Pay Sandbox environment using the test card details provided.
For details, see the Apple Pay Integration Testing topic.

Appendix

Example JavaScript code for a Dynamic Apple Pay Button

Example of creating a Dynamic Apple Pay Button:

  /* define a button handler */
document.getElementById('apple-pay-button').addEventListener('click', function () {
    /* create initial apple pay overlay parameters */
    let paymentRequest = {
        merchantSiteId: 183051, // use your own merchant site ID provided by Nuvei
        env: 'int', // Nuvei API environment - 'int' (integration) or 'prod' (production - default if omitted)
        applicationData: "RGVtbyBzaXRl",  // use your own 64-bit encoded data
        // merchantCapabilities : ['supports3DS','supportsCredit'] //optional
        // optional overwrite of the default ['supports3DS'] //optional
        // supportedNetworks: ['discover', 'visa', 'masterCard'] //optional
      /*
        optional could be overwritten, default value is 
        ['amex', 'chinaUnionPay', 'privateLabel', 'discover', 'visa', 'masterCard', 'jcb'], 
        you can request only debit cards or only credit cards otherwise all are allowed 
      */
        requiredBillingContactFields: ['postalAddress', 'name', 'phone', 'email'],
        requiredShippingContactFields: ['postalAddress', 'name', 'phone', 'email'],
        shippingType: "shipping", // possible values: "delivery", "storePickup", "servicePickup"
        countryCode: 'GB',
        currencyCode: 'GBP',
        shippingMethods: [{
            label: 'Standard Delivery',
            detail: 'Arrives 2-3 business days',
            amount: '5.83',
            identifier: 'std'
        }, {
            label: 'Ground Shipping',
            detail: 'Arrives 5-7 business days',
            amount: '55.83',
            identifier: 'ground'
        }, {
            label: 'Express Shipping',
            detail: 'Arrives 2-3 business days',
            amount: '155.83',
            identifier: 'express'
        }],
        lineItems: [{
            type: 'final',
            label: 'Merchandise',
            amount: '4.95'
        },
        {
            type: 'final',
            label: 'Standard Delivery',
            amount: '5.83'
        },
        {
            type: 'final',
            label: 'Tax',
            amount: '60.16'
        }],
        total: {
            label: 'Your Company',
            amount: '19.99'
        }
    };
    /* custom function that sends data to server */
    let postTransactionData = function (url, trxData, callback) {
        let xhr = new XMLHttpRequest();
        xhr.open('POST', url, true);
        xhr.setRequestHeader('Content-type', 'application/json; charset=UTF-8');
        xhr.onload = function () {
            if (xhr.readyState === 4) {
                let data = {};
                try {
                    data = JSON.parse(this.responseText);
                } catch (e) {
                }
                callback (data);
            }
        };
        let reject = function () {
            callback({});
        };
        xhr.onerror = reject;
        xhr.timeout = 30000;
        xhr.ontimeout = reject;
        xhr.send(JSON.stringify(trxData));
    };

    /* initialize session by calling sfc.applePay.buildSession, 
    a function defined in the external js file provided by Nuvei */
    let session = sfc.applePay.buildSession(paymentRequest, (result, completion) => {
        /* postTransactionData is a function that calls server with provided data 
        using Nuvei API and callback receives status from server */
        postTransactionData(uploadUrl, result, function (srvResult) {
            // depending on status returned, completion method should be called with true or false
            if (srvResult.transactionStatus && srvResult.transactionStatus === 'APPROVED') {
                completion(true);
            } else {
                completion(false);
            }
        })
        //session.abort();
    });

    /* you can define optional handlers of various events in session,
    for example: onshippingmethodselected, onshippingcontactselected,
    onpaymentmethodselected, oncancel */
    session.onshippingmethodselected = (event) => {
        console.log('merchant – onshippingmethodselected:', event);
        setTimeout(() => {
            session.completeShippingMethodSelection({
                newTotal: {
                    label: 'new amount',
                    amount: '115.94'
                }
            })
        }, 1000);
    };

    session.oncancel = (evt) => {
        console.log('cancelled', evt)
    };

    /* overlay is triggered*/
    session.begin();
});
2022 Nuvei. All rights reserved.