Apple Pay Hosted Checkout Sample Code
  1. 1.
    Let's define a helper object with all necessary components:
    1
    const apRequest = {
    2
    buttonOptions: {
    3
    buttonContainer: "ap-container",
    4
    buttonColor: APButtonColor.black,
    5
    buttonType: APButtonType.pay
    6
    },
    7
    totalAmount: null,
    8
    taxAmt: null,
    9
    shippingMethod: null,
    10
    creditType: null,
    11
    getTransactionInfo: function (taxAmt, shippingMethod, creditType) {
    12
    try {
    13
    this.shippingMethod = shippingMethod || this.shippingMethod || {
    14
    "label": "Free Shipping",
    15
    "amount": "0.00",
    16
    "type": "final"
    17
    };
    18
    this.taxAmt = roundToNumber(taxAmt, 4) || this.taxAmt || 0.07;
    19
    this.creditType = creditType || this.creditType;
    20
    const amt = getAmount();
    21
    const lineItems = [
    22
    {
    23
    "label": "Subtotal",
    24
    "type": "final",
    25
    "amount": amt
    26
    },
    27
    this.shippingMethod
    28
    ];
    29
    if (this.creditType === "credit") {
    30
    lineItems.push({
    31
    "label": "Credit Card Fee",
    32
    "amount": roundTo(0.0275*amt, 2),
    33
    "type": "final"
    34
    });
    35
    }
    36
    lineItems.push({
    37
    "label": "Estimated Tax",
    38
    "amount": roundTo(this.taxAmt*amt, 2),
    39
    "type": "final"
    40
    });
    41
    let totalAmt = 0;
    42
    lineItems.forEach((item) => {
    43
    totalAmt += parseFloat(item.amount)||0;
    44
    });
    45
    totalAmt = roundTo(totalAmt, 2);
    46
    this.totalAmount = totalAmt;
    47
    48
    return {
    49
    'lineItems': lineItems,
    50
    total: {
    51
    type: 'final',
    52
    label: 'Total',
    53
    amount: totalAmt,
    54
    }
    55
    };
    56
    } catch (err) {
    57
    console.error("getTransactionInfo error ", exMsg(err));
    58
    }
    59
    },
    60
    onGetTransactionInfo: function () {
    61
    try {
    62
    return this.getTransactionInfo();
    63
    } catch (err) {
    64
    console.error("onGetTransactionInfo error ", exMsg(err));
    65
    }
    66
    },
    67
    onGetShippingMethods: function() {
    68
    return [
    69
    {
    70
    label: 'Free Shipping',
    71
    amount: '0.00',
    72
    identifier: 'free',
    73
    detail: 'Delivers in five business days',
    74
    },
    75
    {
    76
    label: 'Express Shipping',
    77
    amount: '5.00',
    78
    identifier: 'express',
    79
    detail: 'Delivers in two business days',
    80
    },
    81
    ];
    82
    },
    83
    onShippingContactSelected: function(shippingContact) {
    84
    const self = this;
    85
    return new Promise((resolve, reject) => {
    86
    try {
    87
    console.log("shippingContact", JSON.stringify(shippingContact));
    88
    let taxAmt = 0.1;
    89
    const newShippingMethods = [
    90
    {
    91
    label: 'Free Shipping',
    92
    amount: '0.00',
    93
    identifier: 'free',
    94
    detail: 'Delivers in five business days',
    95
    }
    96
    ];
    97
    if (shippingContact && shippingContact.administrativeArea) {
    98
    if (shippingContact.administrativeArea === "NY") {
    99
    taxAmt = 0.0875;
    100
    newShippingMethods.push(
    101
    {
    102
    label: 'Overnight Shipping',
    103
    amount: '10.00',
    104
    identifier: 'overnight',
    105
    detail: 'Delivers in one business days',
    106
    }
    107
    );
    108
    } else if (shippingContact.administrativeArea === "NJ") {
    109
    taxAmt = 0.07;
    110
    newShippingMethods.push(
    111
    {
    112
    label: 'Express Shipping',
    113
    amount: '5.00',
    114
    identifier: 'express',
    115
    detail: 'Delivers in two business days',
    116
    }
    117
    );
    118
    }
    119
    }
    120
    const resp = self.getTransactionInfo(taxAmt, newShippingMethods[0]);
    121
    resp.shippingMethods = newShippingMethods;
    122
    resolve(resp);
    123
    } catch (err) {
    124
    const apErr = {
    125
    code: "-101",
    126
    contactField: "",
    127
    message: exMsg(err)
    128
    }
    129
    console.error("onShippingContactSelected error.", exMsg(err));
    130
    reject({errors: [err]});
    131
    }
    132
    })
    133
    },
    134
    onShippingMethodSelected: function(shippingMethod) {
    135
    const self = this;
    136
    return new Promise(function (resolve, reject) {
    137
    try {
    138
    console.log("shippingMethod", JSON.stringify(shippingMethod));
    139
    const resp = self.getTransactionInfo(null, shippingMethod);
    140
    resolve(resp);
    141
    } catch (err) {
    142
    const apErr = {
    143
    code: "-102",
    144
    contactField: "",
    145
    message: exMsg(err)
    146
    }
    147
    console.error("onShippingMethodSelected error.", exMsg(err));
    148
    reject({errors: [err]});
    149
    }
    150
    })
    151
    },
    152
    onPaymentMethodSelected: function(paymentMethod) {
    153
    const self = this;
    154
    return new Promise((resolve, reject) => {
    155
    try {
    156
    console.log("paymentMethod", JSON.stringify(paymentMethod));
    157
    const resp = self.getTransactionInfo(null, null, paymentMethod.type);
    158
    resolve(resp);
    159
    } catch (err) {
    160
    const apErr = {
    161
    code: "-102",
    162
    contactField: "",
    163
    message: exMsg(err)
    164
    }
    165
    console.error("onPaymentMethodSelected error.", exMsg(err));
    166
    reject({errors: [err]});
    167
    }
    168
    })
    169
    },
    170
    validateApplePayMerchant: function () {
    171
    return new Promise((resolve, reject) => {
    172
    try {
    173
    var xhr = new XMLHttpRequest();
    174
    xhr.open("POST", "https://api.cardknox.com/applepay/validate");
    175
    xhr.onload = function () {
    176
    if (this.status >= 200 && this.status < 300) {
    177
    console.log("validateApplePayMerchant", JSON.stringify(xhr.response));
    178
    resolve(xhr.response);
    179
    } else {
    180
    console.error("validateApplePayMerchant", JSON.stringify(xhr.response), this.status);
    181
    reject({
    182
    status: this.status,
    183
    statusText: xhr.response
    184
    });
    185
    }
    186
    };
    187
    xhr.onerror = function () {
    188
    console.error("validateApplePayMerchant", xhr.statusText, this.status);
    189
    reject({
    190
    status: this.status,
    191
    statusText: xhr.statusText
    192
    });
    193
    };
    194
    xhr.setRequestHeader("Content-Type", "application/json");
    195
    xhr.send();
    196
    } catch (err) {
    197
    setTimeout(function () { console.log("getApplePaySession error: " + exMsg(err)) }, 100);
    198
    }
    199
    });
    200
    },
    201
    onValidateMerchant: function() {
    202
    return new Promise((resolve, reject) => {
    203
    try {
    204
    this.validateApplePayMerchant()
    205
    .then((response) => {
    206
    try {
    207
    console.log(response);
    208
    resolve(response);
    209
    } catch (err) {
    210
    console.error("validateApplePayMerchant exception.", JSON.stringify(err));
    211
    reject(err);
    212
    }
    213
    })
    214
    .catch((err) => {
    215
    console.error("validateApplePayMerchant error.", JSON.stringify(err));
    216
    reject(err);
    217
    });
    218
    } catch (err) {
    219
    console.error("onValidateMerchant error.", JSON.stringify(err));
    220
    reject(err);
    221
    }
    222
    });
    223
    },
    224
    authorize: function(applePayload, totalAmount) {
    225
    return new Promise(function (resolve, reject) {
    226
    var xhr = new XMLHttpRequest();
    227
    xhr.open("POST", "https://<your domain>/<path to handle authorization>");
    228
    xhr.onload = function () {
    229
    if (this.status >= 200 && this.status < 300) {
    230
    resolve(xhr.response);
    231
    } else {
    232
    reject({
    233
    status: this.status,
    234
    statusText: xhr.statusText
    235
    });
    236
    }
    237
    };
    238
    xhr.onerror = function () {
    239
    reject({
    240
    status: this.status,
    241
    statusText: xhr.statusText
    242
    });
    243
    };
    244
    const data = {
    245
    amount: totalAmount,
    246
    payload: applePayload
    247
    };
    248
    xhr.setRequestHeader("Content-Type", "application/json");
    249
    xhr.send(JSON.stringify(data));
    250
    });
    251
    },
    252
    onPaymentAuthorize: function(applePayload) {
    253
    return new Promise((resolve, reject) => {
    254
    try {
    255
    this.authorize(applePayload, this.totalAmount)
    256
    .then((response) => {
    257
    try {
    258
    console.log(response);
    259
    const resp = JSON.parse(response);
    260
    if (!resp)
    261
    throw "Invalid response: "+ response;
    262
    if (resp.xError) {
    263
    throw resp;
    264
    }
    265
    resolve(response);
    266
    } catch (err) {
    267
    throw err;
    268
    // reject(err);
    269
    }
    270
    })
    271
    .catch((err) => {
    272
    console.error("authorizeAPay error.", JSON.stringify(err));
    273
    apRequest.handleAPError(err);
    274
    reject(err);
    275
    });
    276
    } catch (err) {
    277
    console.error("onPaymentAuthorize error.", JSON.stringify(err));
    278
    apRequest.handleAPError(err);
    279
    reject(err);
    280
    }
    281
    });
    282
    },
    283
    onPaymentComplete: function(paymentComplete) {
    284
    if (paymentComplete.response) { //Success
    285
    const resp = JSON.parse(paymentComplete.response);
    286
    if (resp.xRefNum) {
    287
    setTimeout(function(){ console.log("Thank you for your order:("+resp.xRefNum+")")}, 100);
    288
    } else {
    289
    setTimeout(function(){ console.log("Thank you for your order.")}, 100);
    290
    }
    291
    } else if (paymentComplete.error) {
    292
    console.error("onPaymentComplete", exMsg(paymentComplete.error));
    293
    handleAPError(paymentComplete.error);
    294
    }
    295
    },
    296
    handleAPError: function(err) {
    297
    if (err && err.xRefNum) {
    298
    setTimeout(function(){ alert("There was a problem with your order:("+err.xRefNum+")")}, 100);
    299
    } else {
    300
    setTimeout(function(){ alert("There was a problem with your order:"+exMsg(err))}, 100);
    301
    }
    302
    },
    303
    initAP: function() {
    304
    return {
    305
    buttonOptions: this.buttonOptions,
    306
    merchantIdentifier: "<Your Apple Merchant ID>",
    307
    requiredBillingContactFields: ['postalAddress', 'name', 'phone', 'email'],
    308
    requiredShippingContactFields: ['postalAddress', 'name', 'phone', 'email'],
    309
    onGetTransactionInfo: "apRequest.onGetTransactionInfo",
    310
    onGetShippingMethods: "apRequest.onGetShippingMethods",
    311
    onShippingContactSelected: "apRequest.onShippingContactSelected",
    312
    onShippingMethodSelected: "apRequest.onShippingMethodSelected",
    313
    onPaymentMethodSelected: "apRequest.onPaymentMethodSelected",
    314
    onValidateMerchant: "apRequest.onValidateMerchant",
    315
    onPaymentAuthorize: "apRequest.onPaymentAuthorize",
    316
    onPaymentComplete: "apRequest.onPaymentComplete",
    317
    onAPButtonLoaded: "apRequest.apButtonLoaded",
    318
    isDebug: true
    319
    };
    320
    },
    321
    apButtonLoaded: function(resp) {
    322
    if (!resp) return;
    323
    if (resp.status === iStatus.success) {
    324
    showHide(this.buttonOptions.buttonContainer, true);
    325
    showHide("lbAPPayload", true);
    326
    } else if (resp.reason) {
    327
    console.log(resp.reason);
    328
    }
    329
    }
    330
    }
    Copied!
  2. 2.
    Let’s enable Apple Pay for the website:
    1
    document.addEventListener("DOMContentLoaded", function(event) {
    2
    .....
    3
    ckApplePay.enableApplePay({
    4
    initFunction: 'apRequest.initAP',
    5
    amountField: 'amount'
    6
    });
    7
    .....
    8
    }
    Copied!
  3. 3.
    To see the full solution please click here.
Export as PDF
Copy link