Apple Pay
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.
Requirements
Before you begin, you will need to:
-
Create a domain that meets the following requirements: - HTTPS secured (TLS 1.2 or later) [↪Source] - A valid SSL Certificate [↪Source]
-
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
Verifying your Domain for Apple Pay
-
Download Tilled's Apple Domain Verification File and host it on the domain at the path:
/.well-known/apple-developer-merchantid-domain-association
.- Example:
https://example.com/.well-known/apple-developer-merchantid-domain-association
- Example:
-
After the Domain Verification File has been added, you will utilize Tilled's API to Create an Apple Domain.
Example: POST /v1/apple-pay-domains Request
$ curl -X POST 'https://sandbox-api.tilled.com/v1/apple-pay-domains' \
-H 'tilled-account: {{MERCHANT_ACCOUNT_ID}}' \
-H 'tilled-api-key: {{SECRET_KEY}}' \
-H 'Content-Type: application/json' \
--data-raw '{"hostname": "https://example.com"}'
Example: POST /v1/apple-pay-domains Response
{
"updated_at": "2019-08-24T14:15:22Z",
"created_at": "2019-08-24T14:15:22Z",
"id": "string",
"hostname": "string",
"account_id": "string"
}
- After successful Domain Verification, you are now able to start accepting Payments on your site.
Including and Configuring Tilled on your Webpage
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:
<script src="https://js.tilled.com/v2"></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.
const 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 https://app.tilled.com/api-keys.
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
const paymentRequest = tilled.paymentRequest({
total: {
label: 'Tilled tee',
amount: paymentIntent.amount,
},
requestPayerName: true,
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.
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
.
var prButton = form.createField('paymentRequestButton', {
paymentRequest: paymentRequest,
});
paymentRequest.canMakePayment().then((result) => {
if (result) {
// Inject paymentRequestButton Form Field to the DOM
prButton.inject('#native-payment-element');
}
});
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
It's important to note that 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 Field
s in the DOM.
This method returns a Promise
which will resolve with a Payment Intent
object.
paymentRequest.on('paymentmethod', (ev) => {
let paymentMethod = ev.paymentMethod;
tilled
.confirmPayment(paymentIntentClientSecret, {
payment_method: paymentMethod.id,
})
.then(
(paymentIntent) => {
// The payment intent confirmation occurred, but the
// actual charge may still have failed. Check
if (
paymentIntent.status === 'succeeded' ||
paymentIntent.status === 'processing'
) {
ev.complete('success');
alert('Successul payment');
} else {
ev.complete('fail');
const errMsg = paymentIntent.last_payment_error?.message;
alert('Payment failed: ' + errMsg);
}
},
(err) => {
ev.complete('fail');
},
);
});
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:
-
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 Tilled’s Apple Domain Verification File on the domain at the path:
/.well-known/apple-developer-merchantid-domain-association
-
Enroll in the Apple Developer Program if you haven't already.
-
Sign in to your Sandbox Tester Account on a Compatible Device you would like to test out your integration on.
- Once you are signed in, you will add a Test Card Number to your Apple Pay Wallet using one of the Test Cards provided by Apple.
Examples
See our Apple Pay Examples below:
Apple Pay | PaymentRequest Example
/**
* Example assumptions:
* The paymentRequestButton field has a div defined in the DOM
* <div id="native-payment-element"></div>
*
*/
const form = tilled.form({
payment_method_type: 'card',
});
const paymentRequest = tilled.paymentRequest({
total: {
label: 'Tilled tee',
amount: secretData.amount,
},
});
const prButton = form.createField('paymentRequestButton', {
paymentRequest: paymentRequest,
});
paymentRequest.canMakePayment().then((result) => {
if (result) {
prButton.inject('#native-payment-element');
} else {
document.getElementById('native-payment-element').style.display =
'none';
}
});
paymentRequest.on('paymentmethod', (ev) => {
let paymentMethod = ev.paymentMethod;
tilled
.confirmPayment(paymentIntentClientSecret, {
payment_method: paymentMethod.id,
})
.then(
(paymentIntent) => {
// The payment intent confirmation occurred, but the
// actual charge may still have failed. Check
if (
paymentIntent.status === 'succeeded' ||
paymentIntent.status === 'processing'
) {
ev.complete('success');
alert('Successul payment');
} else {
ev.complete('fail');
const errMsg = paymentIntent.last_payment_error?.message;
alert('Payment failed: ' + errMsg);
}
},
(err) => {
ev.complete('fail');
},
);
});