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 API to create the applepay
payment type and perform transactions with it.
Before you begin
Before you begin- Check the basic integration requirements.
- Familiarize yourself with the general Server-side-only integration guide.
- 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
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 API. Our code examples use Apple Pay on the Web Version 6 to provide a good mix of compatibility with most of the Apple devices and the data that you can request from a customer to process orders.
Apple Pay - Good to know
Some of the things that you should consider 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 projectclient 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.
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.
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. The merchant session can be requested from this endpoint: https://api.unzer.com/api-reference/index.html#tag/Apple-Pay/operation/initiateApplePayPaymentSession. See the prerequisites to verify your domain first.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 . |
For more details on Apple Pay payment type creation, see API reference.
Step 2: Create a payment type resourceserver side
To create the actual payment, you need to pass the user data to your server back end and request a payment at our Unzer 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 validationserver 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 endpointserver 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 Unzer 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 paymentserver 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 paymentserver side
Step 3: 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 resultclient side
Step 4: Display the payment result [client side]Use the information from the Check status of the payment step to display the 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 paymentserver side
For more details on managing Apple Pay payments, such as refunding them, see Manage Apple Pay payments.
Notifications
NotificationsWe 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
Error handlingAll 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
Test & go liveYou 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.