Accept cards with Apple Pay

Moov allows you to accept card payments with Apple Pay. This guide covers how you can start accepting Apple Pay on the web using the open standard Payment Request API.

Prerequisite

Before getting started, please check that your website follows Apple' guidelines and that your server is set up accordingly.

  1. Apple Pay website guidelines
  2. Apple Pay server Requirements
    • All pages that include Apple Pay must be served over HTTPS
    • Your domain must have a valid SSL certificate
    • Your server must support the Transport Layer Security (TLS) protocol version 1.2 or later, and one of the cipher suites listed

Step 1: Register your domains

Any domains that will be used to accept payments must first be registered and verified with Apple. You can do this through the Moov Dashboard. Domains must be registered for each individual merchant account i.e., the destination of the Moov transfer.

  1. Within an account, navigate to the settings tab. Select settings and you will find an Apple Pay section where you can add your domains.

Find settings

  1. To register a domain, you will need to verify your domain. Download the file and host it at the following path for each domain you are registering. Ensure the file is in place before clicking Add a domain.

Add a domain

  1. You will now see a list of the domains you’ve added. You can come back to this page to remove or add domains.

List of domains

Step 2: Add Apple Pay button

With the browser-native Payment Request API, there are no additional libraries that you need to download since everything is supported within Safari. You can also use the Apple Pay JS API.

Add a button element to your webpage to display the Apple Pay buy button. You can specify the Apple Pay button style, type, and localization using attributes. Use CSS to set other properties, such as the size and corner radius.

See the Apple Pay documentation for more details on customizing buttons using CSS.

Here’s sample code for adding a black Buy with Apple Pay button, using the default size and corner radius:

1
2
3
4
5
6
7
8
9
<button class="apple-pay-button"></button>
<style>
  .apple-pay-button {
    -webkit-appearance: -apple-pay-button;
    border-radius: .5rem;
    height: 2.75rem;
    cursor: pointer;
  }
</style>

You can use the canMakePayment() method to check if the device supports Apple Pay:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const supportsApplePay = new PaymentRequest(
  [{ supportedMethods: "https://apple.com/apple-pay" }],
  details
).canMakePayment();

// Supports Apple Pay?
if (await supportsApplePay) {
  // show Apple Pay logo, for instance
  return;
}

Step 3: Set up the Payment Request API for Apple Pay

After adding the button, you can set up methods, details, and options in the Payment Request API.

Methods

In Methods, indicate Apple Pay as a payment method by using:

  • “https://apple.com/apple-pay”
  • the Moov Account ID you have certified for Apple Pay
  • the capabilities
  • networks supported

For more details, read the W3 documentation on Methods.

Details

In Details, you can specify transaction details. For example, the transaction’s amount, shipping options, display items, and other modifiers.

For more details, read the W3 documentation on Details.

Options

In Options, you can include any specific customer details or shipping information.

For more details, read the W3 documentation on Options.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Sets up methods, details, and options for Payment Request API
const methods = [
  {
    supportedMethods: "https://apple.com/apple-pay",
    data: {
      version: 3,
      merchantIdentifier: "merchants-moov-account-id",
      merchantCapabilities: ["supports3DS", "supportsCredit", "supportsDebit"],
      supportedNetworks: ["amex", "discover", "masterCard", "visa"],
      countryCode: "US",
    },
  }
];

// Details about the purchase
const details = {
  total: {
    label: "Typically the merchant name",
    amount: { value: "1.00", currency: "USD" },
  }
};

const options = {
  requestPayerName: true,
  requestPayerEmail: true,
  requestPayerPhone: false
};

Step 4: Detect if Apple Pay is available & create a payment request

The Apple Pay button should only be displayed if your user is using a supported device. You can check if the browser will support ApplePaySession with the call below:

1
2
3
if (window.PaymentRequest) {
  // If available, show Apple Pay button
}

Another option is to use Apple’s JS library canMakePaymentsWithActiveCard method to check if the device supports Apple Pay and the user has an active card in their wallet. In the request below, you should use the merchant’s Moov account ID as the merchantIdentifier.

1
2
3
4
5
6
7
8
9
if (window.ApplePaySession) {
  let merchantIdentifier = 'merchants-moov-account-id';
  let promise = ApplePaySession.canMakePaymentsWithActiveCard(merchantIdentifier);
  promise.then((canMakePayments) => {
    if (canMakePayments) {
        // Display Apple Pay button here.
    }
  });
}

Now that you have verified eligibility and added the button, you are ready to create a payment request with the previously-defined options when the button is clicked:

1
const paymentRequest = new PaymentRequest(methods, details, options);

Step 5: Create and validate an Apple Pay merchant session

Once the payment request has been created, it’s time to create and validate an Apple Pay merchant session using the Moov API endpoint or Moov.js method shown below:

1
2
3
4
moov.accounts.applePay.sessions.create({ 
  accountID: 'merchants-moov-account-id', 
  applePaySessionConfig: { displayName: 'string' }
});

This request accepts the account ID and display name of the merchant that will be accepting the payment. The response is a promise that includes the opaque merchantSession response from Apple to be used to resolve the onmerchantvalidation step.

  • accountID - Moov account ID of the merchant i.e., the destination of the transfer
  • displayName - Merchant name for display in the Apple Pay payment sheet e.g., “Whole Body Fitness”
tip
The displayName from the merchant session may be displayed as the merchant name in Apple’s native Wallet app. On the actual card statement, the statementDescriptor or dynamicDescriptor will be displayed with the same logic as other card payments.

The next step is to link an Apple Pay token to the payer’s Moov account using the Moov API endpoint or Moov.js method shown below. The request accepts the account ID of the payer as well as the opaque paymentResponse from Apple.

1
2
3
4
moov.accounts.applePay.tokens.create({ 
  accountID: 'payers-moov-account-id', 
  applePayToken: paymentResponse.details
});

Step 7: Create transfer & dismiss payment sheet

The response payload from linking a token includes a paymentMethodID that is used as the source for the transfer in Moov’s create transfer endpoint. There is no Moov.js method for creating a transfer.

Besides the apple-pay source payment method type, Apple Pay transfers are created the same as other card payments. To learn more about card payments with Moov, read our card acceptance use case guide.

1
2
3
4
5
// Pseudo-code: instruct your server to make the transfer
const moovTransferResponse = await fetch(`/pay`, {
  method: 'post',
  body: JSON.stringify({ paymentMethodID: paymentMethodID })
});

Use the x-wait-for header on the transfer request to receive a synchronous response from the card network to close out the payment sheet.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let status;
if (moovTransferResponse.source.cardDetails.status === 'confirmed') {
  status = 'success';
} else {
  status = 'fail';
}
// Completes the payment request process and closes the payment sheet
try {
  paymentResponse.complete(status);
  // Payment sheet is dismissed
} catch (error) {
  console.error(error);
}

Seeing it altogether

Here’s a sample that synthesizes the steps above all in one place:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Sets up methods, details, and options for Payment Request API
const methods = [
  {
    supportedMethods: "https://apple.com/apple-pay",
    data: {
      version: 3,
      merchantIdentifier: "merchants-moov-account-id",
      merchantCapabilities: ["supports3DS", "supportsCredit", "supportsDebit"],
      supportedNetworks: ["amex", "discover", "masterCard", "visa"],
      countryCode: "US",
    },
  }
];

const details = {
  total: {
    label: "Typically the merchant name",
    amount: { value: "1.00", currency: "USD" },
  }
};

const options = {
  requestPayerName: true,
  requestPayerEmail: true,
  requestPayerPhone: false
};

// Assumes a button click handler
async function handleApplePayClick(event) {
  event.preventDefault();
  try {
    // Uses native Payment Request API and passes the options we configured above
    const paymentRequest = new PaymentRequest(methods, details, options);

    // Event is fired as soon as the payment sheet is opened
    paymentRequest.onmerchantvalidation = (event) => {
      // Note: token with scopes to include this merchant account
      const merchantSession = await moov.accounts.applePay.sessions.create({ accountID: 'merchant-uuid', applePaySessionConfig: { displayName: 'Merchant name' }});
      event.complete(merchantSession);
    };

    // Display the payment sheet via Payment Request API
    const paymentResponse = await paymentRequest.show();
    /* Note: token with scopes should include this payer account
      moov.accounts.applePay.tokens.create() will return a promise of the token, including. the paymentMethodID
    */
    const { paymentMethodID } = await moov.accounts.applePay.tokens.create({ accountID: 'payer-uuid', applePayToken: paymentResponse.details });

    // Pseudo-code: instruct your server to make the transfer. X-Wait-For header is needed to get response.
    const moovTransferResponse = await fetch(`/pay`, {
      method: 'post',
      body: JSON.stringify({ paymentMethodID: paymentMethodID })
    });

    let status;
    if (moovTransferResponse.source.cardDetails.status === 'confirmed') {
      status = 'success';
    } else {
      status = 'fail';
    }

    // Completes the payment request process and closes the payment sheet
    paymentResponse.complete(status);
    // Payment sheet is dismissed
  } catch (error) {
    console.error(error);
  }
}

For more information, refer to Apple’s documentation.