Judopay Documentation

Apple Pay™ for Web

For merchants wishing to perform Apple Pay™ Web payments through Judopay, follow our documentation on how to:

  • Achieve an Apple Pay™ Web session from the merchant's webserver

  • Validate the merchant identity

  • Create a successful paymentToken from Apple payment servers

  • Send the payment request to Judopay for processing upstream

Caution

It is assumed you already have a Judopay account. If you do not, sign up for a sandbox account here.

Prerequisites

Make sure you have implemented the following prerequisites:

Direct from Apple:

Examples on how to implement the Apple prerequisites follow within this guide.

  • Active (paid) Apple Developer Account

  • Apple Merchant ID

  • Apple Payment Processing Certificate

  • Apple Verified Merchant Domain

  • Apple Pay™ Merchant Identity Certificate

Direct from Judopay:

  • Judopay Account

  • Judopay APIToken

  • Judopay APISecret

  • Judopay JudoID

Back-end Code Base :

  • These examples use Judopay's PHP-SDK: Version 4.4.0

Merchant Requirement (Apple Requirements):

  • A DNS resolvable public web site

    This will be where the payment will originate

  • A valid - SSL TLS 1.2 protected

  • openssl

Setting up your Apple Account

In order to use Apple Pay™ Web you must have an Apple Pay™ developer (paid) account from Apple.

Sign up for your Apple Pay™ developer account here.

Step 1: Create a Merchant ID

Once you have your Apple Pay™ developer account, the first step is to create a merchant ID.

To create a merchant ID:

Create_Merchant_ID.png

Step

Description

One.png

From the Certificates, Identifiers & Profiles screen, click the + Identifiers button.

Two.png

From the Register New Identifier screen, select Merchant ID.

Three.png

Click Continue.

Four.png

Enter a Description for this ID.

This is a free text field.

Five.png

Enter an Identifier, recommended reverse DNS.

  • For example, if your domain is www.mydomain.com enter the Identifier as: merchant.com.mydomain.www 

Note: Apple will prefix merchant. for you.

Six.png

Click Continue.

Seven.png

To register the ID, click Register.

Eight.png

Your newly created Merchant ID is displayed.

Step 2: Request a Certificate Signing Request

Request an Apple Certificate Signing Request (CSR) from Judopay Developer Support:        

  1. email: developersupport@judopayments.com

  2. Provide the JudoID for this request

Judopay Developer Support will send you a Judopay CSR file, which you will need in the following step.

Step 3: Create an Apple Pay™ Payment Processing Certificate

To create your Apple Pay™ payment processing certificate:

AP_Payment_Processing_Cert.png

Step

Description

One.png

Click on your newly created Merchant ID.

Two.png

Click Create Certificate.

Three.png

Select No.

Four.png

Click Continue.

Five.png

Click Chose File.

Select the Apple CSR file Judopay sent you in Step 2.

Six.png

Click Continue.

Seven.png

Click Download to download the certificate.

Note: Keep A Safe Copy.

  • Send the certificate to Judopay:

    developersupport@judopayments.com

  • Provide the JudoID this is to be applied to.

    Developer support will upload your certificate onto our payment processing gateway.

Eight.png

Verify your certificate and it is green (valid).

Note: This certificate will need to be requested for renewal from you prior to its expiry, otherwise Apple Payments will cease if you have an expired ticket.  

To do this, follow Step 2 to here, prior to any certificate expiry.

Nine.png

Click Save.

Step 4: Create a Valid Web Domain Validation

To create a valid web domain:

domain.png

Step

Description

One.png

From the Certificates, Identifiers & Profiles screen, select your newly created Merchant ID.

Click Add Domain.

Two.png

Enter your publicly accessible domain name.

Note: http:// is not allowed. You must have an SSL encrypted website with minimum TLS 1.2 requirements for Apple to verify you.

Three.png

Click Save.

Four.png

Click Download to download your verification file.

Once you have downloaded the verification file called:

apple-developer-merchantid-domain-association.txt

  • Create a hidden directory off of the root of your public webserver called: .well-known

  • Place the apple-developer-merchantid-domain-association.txt in that location.  

  • Apple’s servers will call this location and check for this file and check the TLS/SSL protection you have on your servers.

    If this fails, you must rectify the reasons as outlined by Apple.       

  • The URL Apple will attempt to pick the key file from.

    Replace www.mydomain.com with the domain name you registered with Apple:  

https://www.mydomain.com/.well-known/apple-developer-merchantid-domain-association.txt

Five.png

Once you have placed the file on your server in the location shown in the above step:

Click Verify for Apple to verify your domain.  

Once that has succeeded you should see Domain Correctly Verified in Certificates, Identifiers & Profiles.

Step 5: Create a Merchant ID Certificate Signing Request

Create a Certificate Signing Request (CSR) for your Merchant ID. This is used by your servers to validate server identity to Apple Pay™ servers.

You should use openssl to create a CSR you can submit to Apple to Sign this ID.

 

  1. In a command prompt, perform the following: openssl req -new -newkey rsa:2048 -nodes -keyout merchantid.key -out merchantid.csr

Caution

Keep the output to these safe, and away from your website.

 

You should see the following:

Generating a 2048 bit RSA private key
.............................................................................................+++
.........+++
writing new private key to 'merchantid.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:

 

  1. Enter the following details when creating your Merchant ID Certificate Signing Request, (see below).

    Note: This is a sample entry from Judopay, you would enter your own details:

Country Name (2 letter code) []: UK
State or Province Name (full name) []:England
Locality Name (eg, city) []: London
Organization Name (eg, company) []: Judopay
Organizational Unit Name (eg, section) []: Development
Common Name (eg, fully qualified host name) []: merchant.com.mydomain.www
Email Address []:developersupport@judopayments.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: yourpassword

Warning

Do not forget the password you enter in the last step.

This will be required to validate your merchant identity with Apple.

 

  1. Replace the above entries with the entries for your organisation.

  2. Ensure your hostname is your merchant domain identifier you entered in Step 1.

    NOT your public website domain name.

To create your Merchant ID Certificate:

CSR_Merchant_ID.png

Step

Description

One.png

Click Create Merchant Certificate.

Two.png

Click Chose File.

Select your merchantid.csr file that you created above.

Three.png

Click Continue.

Four.png

Click Download to download your Merchant ID certificate.

Copy the Certificate downloaded into your directory where you created the CSR file above.

Step 6: Convert Your Certificate

The next step is to convert your certificate for use with the Apple Pay™ Web JS Code.

  1. Create a:

    1. PEM file for the certificate

    2. PEM file (password protected) for the Certificate Key.

From the command line in the directory where you stored your merchant_id.cer file (downloaded from Apple in Step 5: Create a Merchant ID Certificate Signing Request):

  1. Run the following command to create a certificate .pem file: openssl x509 -inform der -in merchant_id.cer -out merchant_id.pem

This will create a merchant_id.pem file, the server's merchant ID certificate that the sample code will use for identification and validation.

The key file you created with your original CSR is already in the correct PEM file format.

  1. Copy and rename it to .pem to be conformant: cp merchantid.key merchant_id_key.pem

You will now have the following:

merchant_id.pem		file (merchant ID certificate)
merchant_id_key.pem    	file (private password protected key file)

Note

If you cat the key and certificate files above you, should see the following:

merchant_id.pem

Note: BEGIN CERTIFICATE and END CERTIFICATE:

Certificate.png

merchant_id_key.pem  

Note: BEGIN PRIVATE KEY / END PRIVATE KEY:

Key.png

 

This certificate and key are vital to your merchant ID validation. They should be stored on your webserver, (outside of the accessible public web document root location). 

Note

You will need this location to use in the sample code, to tell the application where to find the certificate and key file.

Caution

You will need the key password you entered in Step 5 (when configurating the sample code).

Step 7: Setting up the Sample Code

See prerequisite: Judopay PHP-SDK.

The sample code consists of 4 files:  

  1. ApplePay.php

    Sample Apple Pay Button | Display and UI Handler.

  2. apple_pay_com.php

    Sample Apple Pay Session | Merchant Validation.

  3. apple_pay_conf.php

    Sample Apple Pay Configuration File.

  4. MakeApplePayment.php

    Sample Code To Send Apple Pay Transaction To Judopay.  

Caution

Before you start you must ensure you have installed version 4.4.0 of Judopay's PHP-SDK.

  1. Create a composer.json file in your document root directory with the following content:

{
  "require": {
    "judopay/judopay-sdk": "4.4.0"
  }
}

 

  1. Then install this version of the Judo-PHP SDK by running: $ composer install

    This should install SDK version 4.4.0 in the vendor subdirectory.

    (This will be used in the MakeApplePayment.php sample code).

 

Copy Sample Code Files  

  • Copy the four sample code files into you document root directory on your webserver.

  • The vendor directory must be in this directory, as the this is where the sample code expects it to be.

    Should you move these, you will need to adjust the inclusions in the code to point to the locations you move files to.

 

ApplePay.php – Customisation      

  • Per the Apple Pay™ Website Documentation, you can adjust the styles of the Apple Pay™ Button following the styling options.

  • This should be in accordance with Apple's Style Guidelines and is outside the scope of this document.

    Style Guidance is the responsibility of the merchant under Apple's guidelines:

<style>
#applePay {  
	width: 100%;  
	height: 50px;  
	display: none;   
	border-radius: 5px;    
	margin-left: auto;
	margin-right: auto;
	margin-top: 20px;
	background-image: -webkit-named-image(apple-pay-logo-white); 
	background-position: 50% 50%;
	background-color: black;
	background-size: 60%; 
	background-repeat: no-repeat;  
}
</style>

 

There are no Judopay specific customisations, or variables that need setting in this page, however in this example you should pay attention to the sample response (transaction) code and handle that accordingly.  

In this sample, this page receives the Judopay result and displays a javascript alert with the content. You should customise this to accommodate the results you receive depending on how the transaction was processed accordingly.

The function you should modify is:

function sendPaymentToken(paymentToken) {
	xhr.onload = function (){
	logit(this.responseText);
	alert("Server Response \n"+this.responseText);
	// Handle the response Result here >>>>>>>>		};
}

This is where the transaction result is returned to.

You should apply code logic to check the result for a:

  • valid payment

  • failed payment

  • server exception, or

  • error

Example 5. Example receipt of a valid payment:
{
  "receiptId": "615165638083731456",
  "yourPaymentReference": "44148e1",
  "type": "Payment",
  "createdAt": "2020-08-24T13:48:37.3126+01:00",
  "result": "Success",
  "message": "AuthCode: 941615",
  "judoId": 100183086,
  "merchantName": "example merchant name",
  "appearsOnStatementAs": "APL*/statementname",
  "originalAmount": "1.00",
  "netAmount": "1.00",
  "amount": "1.00",
  "currency": "GBP",
  "cardDetails": {
    "cardLastfour": "9999",
    "endDate": "1223",
    "cardToken": "v2eryp4Jh8Xhm7FpQTFbXN8sphJwIny3",
    "cardType": 1,
    "cardScheme": "Visa",
    "cardFunding": "Credit",
    "cardCategory": "",
    "cardQualifier": 0,
    "cardCountry": "FR",
    "bank": "Credit Industriel Et Commercial"
  },
  "consumer": {
    "consumerToken": "Py1Gj6PB7YKAylSZ",
    "yourConsumerReference": "d7a3906"
  },
  "riskScore": 0,
  "threeDSecure": {
    "attempted": true,
    "result": "PASSED"
  },
  "externalBankResponseCode": "",
  "billingAddress": {}
}


Parameter

Description

receiptId

Unique 18 digit reference for the transaction.

yourPaymentReference

Unique payment reference you provided, or generated if not provided.

type

Type of transaction:

  • Payment

  • Pre-Auth

  • Collection

  • Refund

  • Void

createdAt

Date and Time stamp of the transaction.

result

Result of the transaction:

  • Success

  • Declined

  • Failed

message

Further details of the result, for example:

  • Auth Code

  • reason for failure

judoId

The judoId the transaction was associated with.

merchantName

Merchant Name.

appearsOnStatementAs

As will appear on the consumer's statement.

originalAmount

Original amount of the transaction.

netAmount

Net amount of the transaction.

currency

Transaction currency.

cardDetails

Array of card details.

cardLastfour

Last 4 Digits of the consumer's card.

endDate

Expiry date of the consumer's card.

cardToken

Unique card token for this card.

Note: This can be used to make token payments in the future.

cardType

Card Type.

cardScheme

Card Scheme.

cardFunding

Card Funding Scheme.

cardCategory

Card Category.

cardQualifier

Card Qualifier.

cardCountry

Card Country.

bank

Bank for the Card.

consumer

Consumer Array.

consumerToken

Unique consumer token to be used in conjunction with cardToken to make future payments.

yourConsumerReference

Unique consumer reference you provided in the originating transaction.

riskScore

Risk Score:

  • 0 = Low

  • 100 = High

threeDSecure

3D Secure Array.

attempted

If 3D Secure was attempted.

Boolean.

result

Result of the 3D Secure attempt.

externalBankResponseCode

Any other External Response Codes.

billingAddress

Billing Address.

(If provided in the originating transaction).

apple_pay_com.php       

Warning

This file should not be modified.

It is responsible for validating the merchant with Apple, and sending a valid apple session to the ApplePay.php file.

This uses the apple_pay_conf.php configuration file to obtain the information (certificate and key data) required to be able to validate the Apple Pay™ Web merchant with Apple and obtain a valid session.

apple_pay_conf.php       

Warning

This file MUST be modified to change the following lines: (You should ensure that these paths are outside of your webserver paths and are accessible (read only) to the webserver when it tries to load them).

  • Note: Your merchantID -  certificate.pem ( merchant_id.pem ) file you copied in Step 6: Convert Your Certificate.

    define('PRODUCTION_CERTIFICATE_KEY', '/path/to/your/ merchant_id.pem’);  

  • Note: Your merchantID -  key.pem ( merchant_id_key.pem  )  file you copied in Step 6: Convert Your Certificate.

    define('PRODUCTION_CERTIFICATE_PATH', '/path/to/your/merchant_id_key.pem');    

 

You can also turn DEBUG logging OFF | ON by this parameter. (With DEBUG ON – Recommended, the application will log extensively to the console). 

  • DEBUGGING ON:  

    define('DEBUG', 'true');  

  • DEBUGGING OFF

    define('DEBUG', 'false');

MakeApplePayment.php – Configuration       

The file that:

  • Transforms the Apple Pay™ payload

  • Converts it to a payload for Judopay to handle the transaction

  • Submits the transaction to Judopay

  • Returns the response back to the calling ApplePay.php    

Amend the following line items and insert your JudoID, APIToken and APISecret:  

Note

Remove any from your JudoID.

For example if you have a JudoID formatted as 100-300-235, use 100300235 instead.

 

$judoID="<yourJudoID>";
$apiToken="<yourAPIToken>";
$apiSecret="<yourAPISecret>";
$useProduction=false;

No other customisation in this sample is required.  

 

Caution

If you switch to useProduction=true remember to use the:

Live Production APIToken + Live Production APISecret.

Apple Pay™ will only work on the live environment with live cards. Using live cards in the sandbox environment will generate an error.

Apple Pay™ Main UI Handler

Caution

Source Code – Be careful not to adjust or lose formatting when copying the code from this file.

ApplePay.php

  • Main UI Handler

  • Establishes Browser | Device Compatibility before showing the Apple Pay Button:

AP_Button.png

 

Handles the returned Session and sends Transaction to Transaction Handler

<?php
   require_once ('./apple_pay_conf.php');
   require './vendor/autoload.php';
?>
<!DOCTYPE html>
<html lang="en-GB">
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>ApplePay Test</title>
      <style>
         #applePay {
         width: 100%;
         height: 50px;
         display: none;
         border-radius: 5px;
         margin-left: auto;
         margin-right: auto;
         margin-top: 20px;
         background-image: -webkit-named-image(apple-pay-logo-white);
         background-position: 50% 50%;
         background-color: black;
         background-size: 60%;
         background-repeat: no-repeat;
         }
      </style>
   </head>
   <body>
      <div>
         <button type="button" id="applePay"></button>
         <p style="display:none" id="got_notactive">ApplePay is possible on this browser, but not currently activated.</p>
         <p style="display:none" id="notgot">ApplePay is not available on this browser</p>
         <p style="display:none" id="success">Test transaction completed, thanks.</p>
      </div>
      <script type = "text/javascript">
          var debug = <?=DEBUG?>;
      if (window.ApplePaySession) {
          var merchantIdentifier = '<?=PRODUCTION_MERCHANTIDENTIFIER?>';
          var promise = ApplePaySession.canMakePaymentsWithActiveCard(merchantIdentifier);
          promise.then(function(canMakePayments) {
              if (canMakePayments) {
                  document.getElementById("applePay").style.display = "block";
                  logit('hi, I can do ApplePay');
              } else {
                  document.getElementById("got_notactive").style.display = "block";
                  logit('ApplePay is possible on this browser, but not currently activated.');
              }
          });
      } else {
          logit('ApplePay is not available on this browser');
          document.getElementById("notgot").style.display = "block";
      }
      document.getElementById("applePay").onclick = function(evt) {
          var runningAmount = 1.00;
          var runningPP = 0;
          getShippingCosts('domestic_std', true);
          var runningTotal = function() {
              return runningAmount + runningPP;
          }
          var shippingOption = "";
          var subTotalDescr = "Test Goodies";

          function getShippingOptions(shippingCountry) {
              logit('getShippingOptions: ' + shippingCountry);
              if (shippingCountry.toUpperCase() == "<?=PRODUCTION_COUNTRYCODE?>") {
                  shippingOption = [{
                      label: 'Standard Shipping',
                      amount: getShippingCosts('domestic_std', true),
                      detail: '3-5 days',
                      identifier: 'domestic_std'
                  }, {
                      label: 'Expedited Shipping',
                      amount: getShippingCosts('domestic_exp', false),
                      detail: '1-3 days',
                      identifier: 'domestic_exp'
                  }];
              } else {
                  shippingOption = [{
                      label: 'International Shipping',
                      amount: getShippingCosts('international', true),
                      detail: '5-10 days',
                      identifier: 'international'
                  }];
              }
          }

          function getShippingCosts(shippingIdentifier, updateRunningPP) {
              var shippingCost = 0;
              switch (shippingIdentifier) {
                  case 'domestic_std':
                      shippingCost = 0;
                      break;
                  case 'domestic_exp':
                      shippingCost = 0;
                      break;
                  case 'international':
                      shippingCost = 0;
                      break;
                  default:
                      shippingCost = 0;
              }
              if (updateRunningPP == true) {
                  runningPP = shippingCost;
              }
              logit('getShippingCosts: ' + shippingIdentifier + " - " + shippingCost + "|" + runningPP);
              return shippingCost;
          }
          var paymentRequest = {
              currencyCode: '<?=PRODUCTION_CURRENCYCODE?>',
              countryCode: '<?=PRODUCTION_COUNTRYCODE?>',
              requiredShippingContactFields: ['postalAddress'],
              //requiredShippingContactFields: ['postalAddress','email', 'name', 'phone'],
              //requiredBillingContactFields: ['postalAddress','email', 'name', 'phone'],
              lineItems: [{
                  label: subTotalDescr,
                  amount: runningAmount
              }, {
                  label: 'P&P',
                  amount: runningPP
              }],
              total: {
                  label: '<?=PRODUCTION_DISPLAYNAME?>',
                  amount: runningTotal()
              },
              supportedNetworks: ['amex', 'masterCard', 'visa'],
              merchantCapabilities: ['supports3DS', 'supportsCredit', 'supportsDebit']
          };
          var session = new ApplePaySession(1, paymentRequest);
          // Merchant Validation
          session.onvalidatemerchant = function(event) {
              logit(event);
              var promise = performValidation(event.validationURL);
              promise.then(function(merchantSession) {
                  session.completeMerchantValidation(merchantSession);
              });
          }

          function performValidation(valURL) {
              return new Promise(function(resolve, reject) {
                  var xhr = new XMLHttpRequest();
                  xhr.onload = function() {
                      var data = JSON.parse(this.responseText);
                      logit(data);
                      resolve(data);
                  };
                  xhr.onerror = reject;
                  xhr.open('GET', 'apple_pay_comm.php?u=' + valURL);
                  xhr.send();
              });
          }
          session.onshippingcontactselected = function(event) {
              logit('starting session.onshippingcontactselected');
              logit('NB: At this stage, apple only reveals the Country, Locality and 4 characters of the PostCode to protect the privacy of what is only a *prospective* customer at this point. This is enough for you to determine shipping costs, but not the full address of the customer.');
              logit(event);
              getShippingOptions(event.shippingContact.countryCode);
              var status = ApplePaySession.STATUS_SUCCESS;
              var newShippingMethods = shippingOption;
              var newTotal = {
                  type: 'final',
                  label: '<?=PRODUCTION_DISPLAYNAME?>',
                  amount: runningTotal()
              };
              var newLineItems = [{
                  type: 'final',
                  label: subTotalDescr,
                  amount: runningAmount
              }, {
                  type: 'final',
                  label: 'P&P',
                  amount: runningPP
              }];
              session.completeShippingContactSelection(status, newShippingMethods, newTotal, newLineItems);
          }
          session.onshippingmethodselected = function(event) {
              logit('starting session.onshippingmethodselected');
              logit(event);
              getShippingCosts(event.shippingMethod.identifier, true);
              var status = ApplePaySession.STATUS_SUCCESS;
              var newTotal = {
                  type: 'final',
                  label: '<?=PRODUCTION_DISPLAYNAME?>',
                  amount: runningTotal()
              };
              var newLineItems = [{
                  type: 'final',
                  label: subTotalDescr,
                  amount: runningAmount
              }, {
                  type: 'final',
                  label: 'P&P',
                  amount: runningPP
              }];
              session.completeShippingMethodSelection(status, newTotal, newLineItems);
          }
          session.onpaymentmethodselected = function(event) {
              logit('starting session.onpaymentmethodselected');
              logit(event);
              var newTotal = {
                  type: 'final',
                  label: '<?=PRODUCTION_DISPLAYNAME?>',
                  amount: runningTotal()
              };
              var newLineItems = [{
                  type: 'final',
                  label: subTotalDescr,
                  amount: runningAmount
              }, {
                  type: 'final',
                  label: 'P&P',
                  amount: runningPP
              }];
              session.completePaymentMethodSelection(newTotal, newLineItems);
          }
          session.onpaymentauthorized = function(event) {
              logit('starting session.onpaymentauthorized');
              logit('NB: This is the first stage when you get the *full shipping address* of the customer, in the event.payment.shippingContact object');
              logit(event);
              var promise = sendPaymentToken(event.payment.token);
              promise.then(function(success) {
                  var status;
                  if (success) {
                      status = ApplePaySession.STATUS_SUCCESS;
                      document.getElementById("applePay").style.display = "none";
                      document.getElementById("success").style.display = "block";
                  } else {
                      status = ApplePaySession.STATUS_FAILURE;
                  }
                  logit("result of sendPaymentToken() function =  " + success);
                  session.completePayment(status);
              });
          }

          function sendPaymentToken(paymentToken) {
              return new Promise(function(resolve, reject) {
                  paymentToken["amount"] = runningTotal();
                  const xhr = new XMLHttpRequest();
                  xhr.onload = function() {
                      if (this.readyState == 4 && this.status == 200) {
                          logit(this.responseText);
                          try {
                          let result = JSON.parse(this.responseText)
                          logit("result =  " + result);
                          if (result != undefined && result.result == "Success") {
                              logit("Payment Success, your receiptId = " + result.receiptId);
                              resolve(true);
                          } else {
                              logit("Payment Failure, something went wrong please try again");
                              resolve(false);
                          }
                        } catch {
                              logit("Payment Failure, something went wrong please try again");
                              resolve(false); 
                        }
                      }
                  };
                  xhr.open("POST", "MakeApplePayment.php", true);
                  xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                  xhr.send(JSON.stringify(paymentToken));
              });
          }
          session.oncancel = function(event) {
              logit('starting session.cancel');
              logit(event);
          }
          session.begin();
      };

      function logit(data) {
          if (debug == true) {
              console.log(data);
          }
      }; 
  	</script>
   </body>
</html>

Merchant Validator and Apple Pay™ Session Creator

Caution

Source Code – Be careful not to adjust or lose formatting when copying the code from this file.

apple_pay_comm.php

Merchant Validator and Apple Pay™ Session Creator:

<?php
$validation_url = $_GET['u'];

if( "https" == parse_url($validation_url, PHP_URL_SCHEME) && substr( parse_url($validation_url, PHP_URL_HOST), -10 )  == ".apple.com" ){

require_once ('./apple_pay_conf.php');

// create a new cURL resource
$ch = curl_init();

$data = '{"merchantIdentifier":"'.PRODUCTION_MERCHANTIDENTIFIER.'", "domainName":"'.PRODUCTION_DOMAINNAME.'", "displayName":"'.PRODUCTION_DISPLAYNAME.'"}';

curl_setopt($ch, CURLOPT_URL, $validation_url);
curl_setopt($ch, CURLOPT_SSLCERT, PRODUCTION_CERTIFICATE_PATH);
curl_setopt($ch, CURLOPT_SSLKEY, PRODUCTION_CERTIFICATE_KEY);
curl_setopt($ch, CURLOPT_SSLKEYPASSWD, PRODUCTION_CERTIFICATE_KEY_PASS);
//curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
//curl_setopt($ch, CURLOPT_SSLVERSION, 'CURL_SSLVERSION_TLSv1_2');
//curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'rsa_aes_128_gcm_sha_256,ecdhe_rsa_aes_128_gcm_sha_256');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

if(curl_exec($ch) === false)
{
echo '{"curlError":"' . curl_error($ch) . '"}';
}

// close cURL resource, and free up system resources
curl_close($ch);

}
?>

Apple Pay™ Configuration File

Caution

Source Code – Be careful not to adjust or lose formatting when copying the code from this file.

apple_pay_conf.php

Apple Pay Configuration File: For use by apple_pay_comm.php:

<?php
// update these with the real location of your two .pem files. keep them above/outside your webroot folder
//define('PRODUCTION_CERTIFICATE_KEY', '/your/path/to/applepay_includes/ApplePay.key.pem');
//define('PRODUCTION_CERTIFICATE_PATH', '/your/path/to/applepay_includes/ApplePay.crt.pem');

define('PRODUCTION_CERTIFICATE_PATH','/path/to/your/merchant_id.pem');
define('PRODUCTION_CERTIFICATE_KEY','/path/to/your/merchant_id_key.pem');

// This is the password you were asked to create in terminal when you extracted ApplePay.key.pem
define('PRODUCTION_CERTIFICATE_KEY_PASS', 'yourpassword’);

define('PRODUCTION_MERCHANTIDENTIFIER', openssl_x509_parse( file_get_contents( PRODUCTION_CERTIFICATE_PATH ))['subject']['UID'] ); //if you have a recent version of PHP, you can leave this line as-is. http://uk.php.net/openssl_x509_parse will parse your certificate and retrieve the relevant line of text from it e.g. merchant.com.name, merchant.com.mydomain or merchant.com.mydomain.shop
// if the above line isn't working for you for some reason, comment it out and uncomment the next line instead, entering in your merchant identifier you created in your apple developer account
// define('PRODUCTION_MERCHANTIDENTIFIER', 'merchant.com.name');

define('PRODUCTION_DOMAINNAME', $_SERVER["HTTP_HOST"]); //you can leave this line as-is too, it will take the domain from the server you run it on e.g. shop.mydomain.com or mydomain.com
// if the line above isn't working for you, replace it with the one below, updating it for your own domain name
// define('PRODUCTION_DOMAINNAME', 'mydomain.com');


define('PRODUCTION_CURRENCYCODE', 'GBP');	// https://en.wikipedia.org/wiki/ISO_4217
define('PRODUCTION_COUNTRYCODE', 'GB');		// https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
define('PRODUCTION_DISPLAYNAME', 'Apple Pay Test');

define('DEBUG', 'true');

?>

Judo Payment Handler

Caution

Source Code – Be careful not to adjust or lose formatting when copying the code from this file.

MakeApplePayment.php

  • Judo Payment Handler sends the Apple Pay™ payload to Judopay for upstream processing.

  • Returns Transaction Result or Error:

<?php
header('Access-Control-Allow-Origin: *');
require './vendor/autoload.php';

$judoID = "<yourJudoID>";
$apiToken = "<yourAPIToken>";
$apiSecret = "<yourAPISecret>";
$useProduction = false;

$paymentToken = file_get_contents('php://input');
$jsonToken = json_decode($paymentToken);

$pkObj = array(
    "token" => array(
        "paymentInstrumentName" => $jsonToken
            ->paymentMethod->displayName,
        "paymentNetwork" => $jsonToken
            ->paymentMethod->network,
        "paymentData" => array(
            "version" => $jsonToken
                ->paymentData->version,
            "data" => $jsonToken
                ->paymentData->data,
            "signature" => $jsonToken
                ->paymentData->signature,
            "header" => array(
                "ephemeralPublicKey" => $jsonToken
                    ->paymentData
                    ->header->ephemeralPublicKey,
                "publicKeyHash" => $jsonToken
                    ->paymentData
                    ->header->publicKeyHash,
                "transactionId" => $jsonToken
                    ->paymentData
                    ->header->transactionId,
            ) ,
        ) ,
    ) ,
    "billingAddress" => null,
    "shippingAddress" => null,
);

$judopay = new Judopay(array(
    'apiToken' => $apiToken,
    'apiSecret' => $apiSecret,
    'judoId' => $judoID,
    'useProduction' => $useProduction
));

// Although amount is passed over fromt the token from the client UI, this should
// be checked against a session value to ensure the correct amount is being passed for payment.
// Below code is just passing the amount as trusted, which you should not do in production.
// Consumer References you should use your own identifiable references, below is just a random generator
// Payment Reference here is a randomly generated reference.

$applePayPayment = $judopay->getModel('ApplePayment');

$applePayPayment->setAttributeValues(array(
    'judoId' => $judoID,
    'currency' => 'GBP',
    'yourPaymentReference' => substr(md5(rand()) , 0, 7) ,
    'yourConsumerReference' => substr(md5(rand()) , 0, 7) ,
    'amount' => $jsonToken->amount,
    'pkPayment' => $pkObj
));

try
{
    $response = $applePayPayment->create();
    echo json_encode($response);

}
catch(\Judopay\Exception\ValidationError $e)
{
    echo $e->getSummary();
}
catch(\Judopay\Exception\ApiException $e)
{
    echo $e->getSummary();
}
catch(\Exception $e)
{
    echo $e->getMessage();
}
?>