alt

Important information

There was an update of Unzer TLS/SSL certificates. Learn more

Unzer

Accept Apple Pay with a server-side-only integration

Build your own payment form to add Apple Pay payment to the checkout page

Overview

Using Apple Pay on your page, you need to use the Apple Pay JS API to get the payment authorized by Apple Pay. The payment data provided by Apple Pay are required by the Unzer Payment API to create the applepay payment type and perform transactions with it.

Before you begin

  • Follow the steps in the Get started guide to set up your environment.
  • See the full list of prerequisites for Accepting Apple Pay payments using the Unzer payment system here: Apple Pay Prerequisites
icon
Check the Apple Pay demo page for a detailed description on how to use Apple Pay on the web.

Using Apple Pay

Apple Pay guidelines

Before you can use Apple Pay as a payment method, you must make sure that your website or app comply with all of the guidelines specified by Apple.

Apple Pay version compatibility

You can accept payments using Apple Pay with the Unzer Payment API. Our code examples use version 6 to provide a good mix of compatibility with most of the Apple devices and the data which you can request from a customer to process orders.

Apple Pay - Good to know

Here are some things that you should keep in mind when implementing Apple Pay in your application:

  • The domainName parameter from the merchant validation step must be the same as validated for the Apple developer account.
  • Apple Pay is only available on supported Apple devices. See the full list of supported devices here: Supported devices

Step 1: Add Apple Pay to your project
client side

Create an Apple Pay button

When using Apple Pay as a payment method, you can use a pre-defined Apple Pay button or style yourself.

For the setup of the pre-defined button, see the Apple Pay Reference.

<div class="apple-pay-button apple-pay-button-black" lang="us" onclick="setupApplePaySession()" title="Start Apple Pay" role="link" tabindex="0"></div>
<div onclick="setupApplePaySession()" title="Start Apple Pay" role="link" tabindex="0"></div>

Create an Apple Pay session

In your OnClick handler function setupApplePaySession(), you first need to to create a paymentRequest object containing the transaction details required to set up the Apple Pay session.

var paymentRequest = {
    currencyCode: 'yourCurrencyCode',
    countryCode: 'yourCountryCode',
    requiredShippingContactFields: ['postalAddress'],
    requiredBillingContactFields: ['postalAddress','email', 'name', 'phone'],
    lineItems: [
   {label: 'someSubTotalDescr', amount: someSubTotalAmount }, 
   {label: 'someOtherLabelDescr', amount: someOtherAmount }
  ],
    total: {
    label: 'someLabel',
    amount: someTotalAmount
    },
    supportedNetworks: ['masterCard', 'visa' ],
    merchantCapabilities: [ 'supports3DS' ]
 };
icon
For more information about the ApplePayPaymentRequest, see the Apple Pay Documentation.

Now, you need to create your Apple Pay session and call the begin() method on the created session object to start the merchant validation process.

var session = new ApplePaySession(6, paymentRequest);
session.begin();

You then need to provide custom implementations for the following Apple Pay event handlers:

Event Handler Description
onvalidatemerchant This is a callback function to handle the Apple Pay merchant validation event.

Here you will need to call the backend validation endpoint, passing the validationURL from the event object.

To complete the validation process, you need to call the session.completeMerchantValidation(merchantSession), where merchantSession is the object fetched from the backend.

Also see Apple documentation: Event handler
onpaymentauthorized This event is called when the customer authorized the payment via Touch ID, Face ID or the passcode.

Here you need to create the Unzer payment type resource. You can do this by calling unzerApplePayInstance.createResource(paymentData), where paymentData is read from the encrypted Apple Pay token in the event parameter.

Then you will need to call the backend authorized endpoint in your server-side integration, passing the ID of created, payment type resource.

To complete the authorization process, you need to call session.completePayment passing either STATUS_SUCCESS or STATUS_FAILURE.
icon
For more information about the ApplePaySession and other available event handlers, see the Apple Pay documentation.

Step 2: Create a payment type resource
server side

To create the actual payment, you need to pass the user data to your server back end and request a payment at our Payment API with the following code:

POST https://api.unzer.com/v1/types/applepay

{
  "version": "EC_v1",
  "data": "7jY1W5M61c5Br23lTmP06sZ....",
  "signature": "MIAGCSqGSIb3DQEHAqCAMIAC....",
  "header": {
    "ephemeralPublicKey": "MFkwEwYHKoZIzj0CAQYIKo....",
    "publicKeyHash": "zqO5Y3ldWWm4NnIk....",
    "transactionId": "f9ca8450a285b7fb3d9f9af5...."
  }
}
$unzer = new Unzer('s-priv-xxxxxxxxxx');
$applePay = new Applepay('EC_v1', 'yourApplepayData', 'yourApplepaySignature', 'yourApplepayHeader');
$unzer->createPaymentType($applePay);
Unzer unzer = new Unzer(new HttpClientBasedRestCommunication(), "s-priv-xxxxxxxxxx");
Applepay applePay = new Applepay('EC_v1', 'yourApplepayData', 'yourApplepaySignature', 'yourApplepayHeader');
applePay = unzer.createPaymentType(applePay);

The response looks similar to the following example:

{
  "id" : "s-apl-jxpxorn9poen",
  "method" : "applepay",
  "recurring" : false,
  "geoLocation" : {
    "clientIp" : "clientIp",
    "countryIsoA2" : ""
  },
  "applicationPrimaryAccountNumber" : "applicationPrimaryAccountNumber",
  "applicationExpirationDate" : "09/2022",
  "currencyCode" : "currencyCode",
  "transactionAmount" : "transactionAmount"
}

Provide merchant validation
server side

To accept payments using Apple Pay, you need to be able to process the Apple Pay merchant validation. With this, Apple adds a security layer so that the customer can be sure that the merchant and the shop where they’re shopping at, match.
This is a synchronous call from the ApplePaySession in the Safari browser to the back end. The actual call to the Apple Pay server for the validation can only be done from the back end. You need to add the functionality to validate your merchant to the onvalidatemerchant-event inside the Apple Pay session.
Find more information, see Apple documentation: Merchant validation.

The Unzer SDKs also provides an adapter function to process the merchant validation on the server side for you.

To construct an ApplepaySession object, the following parameters are needed:

Parameter Description
merchantIdentifier Available in the Apple Developer account
displayName The merchant name
domainName The domain name which has been validated in the Apple Developer account
$applepaySession = new ApplepaySession('your.merchantIdentifier', 'ExampleTitle', 'your-domain.com');
$appleAdapter = new ApplepayAdapter();
$appleAdapter->init('/path/to/merchant_id.pem', '/path/to/rsakey.key')

// Get the merchant validation url from the frontend.
$merchantValidationURL = urldecode($_POST['merchantValidationUrl']);

try {
  $validationResponse = $appleAdapter->validateApplePayMerchant(
      $merchantValidationURL,
      $applepaySession
  );
  
  print_r($validationResponse);
} catch (\Exception $e) {
  ...
}
String merchantValidationUrl = getMerchantValidationUrlFromFrontend();
ApplePaySession applePaySession = new ApplePaySession(applePayMerchantIdentifier, applePayDisplayName, domainName);
KeyManagerFactory kmf = getKeyManagerFactory();
TrustManagerFactory tmf = getTrustManagerFactory();
String response = ApplePayAdapterUtil.validateApplePayMerchant(merchantValidationUrl, applePaySession, kmf, tmf);

return response;


//Create TruststoreManagerFactory

private TrustManagerFactory getTrustManagerFactory() {
    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    InputStream is = new ClassPathResource("path/to/file").getInputStream();
    trustStore.load(is, "password".toCharArray());
    is.close();

    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
    trustManagerFactory.init(trustStore);

    return trustManagerFactory;
}


//Create KeyManagerFactory
private KeyManagerFactory getKeyManagerFactory() {
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    InputStream is = new ClassPathResource("path/to/file").getInputStream();
    keyStore.load(is, "password".toCharArray());
    is.close();
    
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
    keyManagerFactory.init(keyStore, "password".toCharArray());

    return keyManagerFactory;
}

All the SDKs require the Apple Pay Merchant ID Certificate to be present and provided to the adapter function. See the Apple Pay documentation to learn how to request an Apple Pay Merchant ID Certificate.

In the Java SDK, you also need to provide the Apple Pay certificate keychain in a trust store.

Provide a payment authorized endpoint
server side

After the customer has authorized the payment via the Apple Pay overlay, Safari will return an object with the data you need to transfer to our API in order to authorize or charge a payment via our Payment API. For this, you should provide a backend controller to accept the data from your frontend. This controller should then return the result of the API authorization because Apple Pay uses this to display the result to the customer.

The following example displays how Apple Pay data is handled on the server side:

$jsonData      = json_decode(file_get_contents('php://input'), false);
$applePayAuthorisation= $jsonData->applePayAuthorisation;

// Catch API errors, write the message to your log and show the ClientMessage to the client.
$response = ['transactionStatus' => 'error'];
try {
    // Create an Unzer object using your private key and register a debug handler if you want to.
    $unzer = new Unzer('s-priv-xxxxxxxxxxxxxx');
    $applepay = new Applepay(null, null, null, null);
    $applepay->handleResponse($appleAuthorization);
    $unzer->createPaymentType($applepay);
    
    // -> Here you can place the Charge or Authorize call as shown in Step 3 <-
    // E.g $transaction = $unzer->performeCharge(...);
    // Or  $transaction = $unzer->performAuthorization(...);
    
    $response['transactionStatus'] = 'pending';
    if ($transaction->isSuccess()) {
        $response['transactionStatus'] = 'success';
    }
} catch (UnzerApiException $e) {
    $merchantMessage = $e->getMerchantMessage();
    $clientMessage = $e->getClientMessage();
} catch (RuntimeException $e) {
    $merchantMessage = $e->getMessage();
}
echo json_encode($response);
String applePayAuthorisation = getApplePayAuthorisationFromFrontend();
Unzer unzer = new Unzer(new HttpClientBasedRestCommunication(), privateKey);
ObjectMapper mapper = new ObjectMapper();
boolean authStatus = false;

Applepay applepay = mapper.readValue(applePayAuthorisation, Applepay.class);

try {
    applepay = unzer.createPaymentType(applepay);
    // -> Here you can place the Charge or Authorize call as shown in Step 3 <-
    // E.g Charge charge = unzer.charge(...);
    // Or Authorize authorize = unzer.authorize(...);
    
    // Set the authStatus based on the resulting Status of the Payment-Transaction
    // The Functions charge.getStatus() or authorize.getStatus() will return the Status-Enum (SUCCESS, PENDING, ERROR)
    if(charge.getStatus().equals(AbstractTransaction.Status.SUCCESS))
    {
        authStatus = true;
    }
} catch (Exception ex) {
    log.error(ex.getMessage());
}

return authStatus;

Step 3: Make a payment
server side

Make a charge transaction

Make a charge or authorize transaction with the Applepay resource that you created earlier. With a successful charge transaction, money is transferred from the customer to the merchant and a payment resource is created. In case of the authorize transaction, it can be charged after the authorization is successful.

POST https://dev-api.unzer.com/v1/payments/charges

Body:
{
  "amount" : "49.99",
  "currency" : "EUR",
  "returnUrl": "http://example.org",
  "resources" : {
    "typeId" : "s-apl-xxxxxxxxxxxx"
  }
}
$unzer = new Unzer('s-priv-xxxxxxxxxx');
$applePay = $unzer->fetchPaymentType('s-apl-xxxxxxxxxxx');
$charge = $applePay->charge(49.99, 'EUR', 'https://www.my-shop-url.de/returnhandler');
Unzer unzer = new Unzer("s-priv-xxxxxxxxxx");
Charge charge = unzer.charge(BigDecimal.valueOf(49.99), Currency.getInstance("EUR"), "s-apl-wqmqea8qkpqy", new URL("https://www.my-shop-url.de/returnhandler"));

The response looks similar to the following example:

{
    "id": "s-chg-1",
    "isSuccess": true,
    "isPending": false,
    "isError": false,
    "redirectUrl": "",
    "message": {
        "code": "COR.000.100.112",
        "merchant": "Request successfully processed in 'Merchant in Connector Test Mode'",
        "customer": "Your payments have been successfully processed in sandbox mode."
    },
    "amount": "49.9900",
    "currency": "EUR",
    "returnUrl": "http://example.org",
    "date": "2021-05-14 16:01:24",
    "resources": {
        "paymentId": "s-pay-xxxxxxx",
        "traceId": "c6dc23c6fe91a3e1129da83ebd29deb0",
        "typeId": "s-apl-xxxxxxxxxxxx"
    },
    "paymentReference": "",
    "processing": {
        "uniqueId": "31HA07BC810C911B825D119A51F5A57C",
        "shortId": "4849.3448.4721",
        "traceId": "c6dc23c6fe91a3e1129da83ebd29deb0"
    }
}

Step 4: Check status of the payment
server side

Once the customer is redirected to the returnUrl, you can fetch the payment details from the API, by using the resources.paymentId from the charge response above to handle the payment according to its status. If the status of the payment is completed , the payment process has been finished successfully and can be considered as paid. Check all possible payment states here.

GET https://api.unzer.com/v1/payments/{payment_ID}
{
    "id": "s-pay-222305",
    "state": {
        "id": 1,
        "name": "completed"
    },
    "amount": {
        "total": "49.9900",
        "charged": "49.9900",
        "canceled": "0.0000",
        "remaining": "0.0000"
    },
    "currency": "EUR",
    "orderId": "",
    "invoiceId": "",
    "resources": {
        "customerId": "",
        "paymentId": "s-pay-222305",
        "basketId": "",
        "metadataId": "",
        "payPageId": "",
        "traceId": "70ddf3152a798c554d9751a6d77812ae",
        "typeId": "s-apl-wqmqea8qkpqy"
    },
    "transactions": [
        {
            "date": "2021-05-10 00:51:03",
            "type": "charge",
            "status": "success",
            "url": "https://api.unzer.com/v1/payments/s-pay-222305/charges/s-chg-1",
            "amount": "49.9900"
        }
    ]
}

Step 5: Display the payment result
client side

Use the information from the Check status of the payment step to show payment result to your customer.
This can be the success or error page of your shop. If something went wrong you can use the client message from the API response and show it to the customer.

Manage payment
server side

For more details on managing Apple Pay payments, see Manage Apple Pay payments.

Notifications

We recommend subscribing to the payment event to receive notifications about any changes to the payment resource. As soon as the event is triggered you should fetch the payment and update the order status in your shop according to its status.

  {
    "event":"payment.pending",
    "publicKey":"s-pub-xxxxxxxxxx",
    "retrieveUrl":"https://api.unzer.com/v1/payments/s-pay-774",
    "paymentId":"s-pay-774"
  }

For more details on implementing webhooks to receive notifications, see Notifications page.

Error handling

All requests to the API can result in an error that should be handled. Refer to the Error handling guide to learn more about Unzer API (and other) errors and handling them.

Test & go live

You should always test your integration before going live. First perform test transactions using test data. Next, check against Integration checklist and Go-live checklist to make sure the integration is complete and you’re ready to go live.

See also