Apple Pay

With Tilled, you can accommodate all the ways customers wish to pay! Learn how to implement Apple Pay acceptance with ease.

Tilled allows Partners to accept Apple Pay payments, which Customers can use to make payments if they are using a compatible device and browser.

Tilled supports Apple Pay through the Tilled.js PaymentRequest object.


Before you begin, you will need to:

  • Create a domain that meets the following requirements:
  • Create an Apple Developer Account (this will be used when testing Apple Pay on your Website)

These requirements apply to both Sandbox and Production environments. For Sandbox testing, to get started, you can use a service like ngrok or Netlify.

Apple Pay Domain Verification

Apple's Documentation for Apple Pay on the Web instructs you to create a Merchant Identifier, Payment Processing Certificate, and to Register your Domain through them. Tilled takes care of all of this on your behalf when you reach out to our Onboarding Team at [email protected].

Verifying your Domain for Apple Pay

You must register and verify all top-level domains and subdomains where you will display the Apple Pay button. For example, if you were to host a Payment Form that displays the Apple Pay button on and, you will need to complete Domain Verification for both.

In the Sandbox Environment, Domain Verification is not needed, but you will still need to follow the domain requirements here

In the Production environment, to receive your Domain Verification files for Apple Pay, you will need to reach out to the Onboarding Team at [email protected] and provide the following information:

  1. On how many domains do you plan to host the Apple Pay button? - If each Merchant will be using a different domain or subdomain, you will need to include that in your answer if the Merchant will be hosting the Apple Pay button. - You will need to register and verify all top-level domains and subdomains where you will display the Apple Pay button. For example, if you were to host a payment form that displayed the Apple Pay button on and, you would need to complete domain verification for both.

  2. How many merchants are you planning to enable Apple Pay for?

  3. Will you be using your own payment/checkout page (using Tilled.js) or Tilled’s Checkout Sessions?

Once this information is received by our Onboarding Team, we provide you with the files and instructions on hosting them to ensure successful Domain Verification, so that are able to start accepting Payments on your site.

Including Tilled.js

To accept Apple Pay payments through Tilled, you will need to include Tilled.js on your page. Add the following HTML snippet to your web page, preferably in the <head> tag of your web page:

1<script src=""></script>

Initializing Tilled.js

Instantiate an instance of Tilled by providing it with your publishable API key and the Tilled account id of the merchant account to perform the action on behalf of.

1const tilled = new Tilled('pk_…', 'acct_…');

Use new Tilled(publishableKey, tilledAccount, options?) to create an instance of the Tilled object. The Tilled object provides access to the rest of the Tilled.js SDK. Your Tilled publishable API key is required when calling this function, replace the sample API key above with your actual API key. You can retrieve your API key by accessing

Creating the PaymentRequest

In this example, we will be using the div container <div id="native-payment-element"> to inject the PaymentRequest Button (Apple Pay button) if the paymentRequest.canMakePayment(): Promise<boolean> returns as true.

PaymentRequest instances emit several different types of events, we will use tilled.paymentRequest to create a PaymentRequest object.

In Safari, tilled.paymentRequest uses Apple Pay.

PaymentRequest Example

 1const paymentRequest = tilled.paymentRequest({
 2	total: {
 3		label: "Tilled tee",
 4		amount: paymentIntent.amount,
 5	},
 6	style: {
 7		type: "donate",
 8		theme: "black",
 9	},
10	requestPayerName: true,
11	requestPayerEmail: true,

When creating a PaymentRequest for Apple Pay, we highly recommend you collect the name as this also results in the collection of the billing address for Apple Pay, which can be used to perform address verification. A customer name can be collected by setting the requestPayerName option to true.

To view all PaymentRequest options properties, you can read more here.

Neither ApplePay nor PaymentRequest are unique payment method types. Payment methods created by a PaymentRequest will have a type of card.

Displaying The Apple Pay Button

To ensure that only customers who have an Apple Pay Wallet with an active card attached see the Apple Pay button, you will utilize paymentRequest.canMakePayment(): Promise<boolean> . This returns a Promise that resolves true if an enabled wallet is ready to pay. If no wallet is available, it resolves with false;

The example below injects paymentRequestButton (Apple Pay button) to the div container <div id="native-payment-element"> if paymentRequest.canMakePayment(): Promise<boolean> resolves true.

 1var prButton = form.createField('paymentRequestButton', {
 2  paymentRequest: paymentRequest,
 5paymentRequest.canMakePayment().then((result) => {
 6  if (result) {
 7    // Inject paymentRequestButton Form Field to the DOM
 8    prButton.inject('#native-payment-element');
 9  }

PaymentMethod Creation

Tilled.js automatically creates a payment method after the customer is done interacting with the browser’s payment interface. To access the created payment method, listen for this event by utilizing paymentRequest.on('paymentmethod', handler): void

Payment methods created through Apple Pay will have a "type" of "card" and a validity period of 5 minutes.

For further details on PaymentMethod Creation, please refer to the Tilled.js documentation here.

Creating and Confirming The PaymentIntent

Before displaying your checkout form and confirming the payment, your backend server will need to make an API call to Tilled to create a Payment Intent with the payment amount. You will pass the intent’s client_secret to your front end. Use the tilled.confirmPayment(client_secret, { payment_method }) method to process the payment with the newly created Payment Method.

tilled.confirmPayment(clientSecret: string, params): Promise<PaymentIntent> confirms a Payment Intent and, optionally, creates a Payment Method from the Form Fields in the DOM.

This method returns a Promise which will resolve with a Payment Intent object.

 1paymentRequest.on('paymentmethod', (ev) => {
 2  let paymentMethod = ev.paymentMethod;
 3  tilled
 4    .confirmPayment(paymentIntentClientSecret, {
 5      payment_method:,
 6    })
 7    .then(
 8      (paymentIntent) => {
 9        // The payment intent confirmation occurred, but the
10        // actual charge may still have failed. Check
11        if (
12          paymentIntent.status === 'succeeded' ||
13          paymentIntent.status === 'processing'
14        ) {
15          ev.complete('success');
16          alert('Successful payment');
17        } else {
18          ev.complete('fail');
19          const errMsg = paymentIntent.last_payment_error?.message;
20          alert('Payment failed: ' + errMsg);
21        }
22      },
23      (err) => {
24        ev.complete('fail');
25      },
26    );

Testing your Apple Pay integration

Apple allows developers to test Apple Pay before or after implementation by using their Apple Developer Account to create a Sandbox Tester Account. To start testing your Apple Pay Integration you will need to do the following:

  1. Make sure that your domain:

    • Is HTTPS secured (TLS 1.2 or later) [↪Source]
    • Has a valid SSL Certificate [↪Source]
    • Has been verified utilizing Tilled's API and is actively hosting Domain Verification file on the domain at the path: /.well-known/apple-developer-merchantid-domain-association
  2. Enroll in the Apple Developer Program if you haven't already.

  3. Create a Sandbox Tester Account

  4. Sign in to your Sandbox Tester Account on a Compatible Device you would like to test out your integration on.


See our Apple Pay Examples below:

Apple Pay | PaymentRequest Example

 2 * Example assumptions:
 3 * The paymentRequestButton field has a div defined in the DOM
 4 * <div id="native-payment-element"></div>
 5 *
 6 */
 7const form = tilled.form({
 8  payment_method_type: 'card',
11const paymentRequest = tilled.paymentRequest({
12  total: {
13    label: 'Tilled tee',
14    amount: secretData.amount,
15  },
18const prButton = form.createField('paymentRequestButton', {
19  paymentRequest: paymentRequest,
22paymentRequest.canMakePayment().then((result) => {
23  if (result) {
24    prButton.inject('#native-payment-element');
25  } else {
26    document.getElementById('native-payment-element').style.display =
27      'none';
28  }
31paymentRequest.on('paymentmethod', (ev) => {
32  let paymentMethod = ev.paymentMethod;
33  tilled
34    .confirmPayment(paymentIntentClientSecret, {
35      payment_method:,
36    })
37    .then(
38      (paymentIntent) => {
39        // The payment intent confirmation occurred, but the
40        // actual charge may still have failed. Check
41        if (
42          paymentIntent.status === 'succeeded' ||
43          paymentIntent.status === 'processing'
44        ) {
45          ev.complete('success');
46          alert('Successful payment');
47        } else {
48          ev.complete('fail');
49          const errMsg = paymentIntent.last_payment_error?.message;
50          alert('Payment failed: ' + errMsg);
51        }
52      },
53      (err) => {
54        ev.complete('fail');
55      },
56    );