Collect Apple Pay
In this guide, we will set up PublicSquare Elements SDKs to capture Apple Pay in a frontend application and securely authorize and store the Apple Pay data while avoiding PCI requirements.
Getting Started
To get started, you will need a PublicSquare Account.
Get your Publishable Key
Next you will need your Publishable Key
. Go to your Developers section and click Reveal
for your Publishable Key
and copy the value.
Domain Verification
Domain verification is a key step in getting Apple Pay up and running on your site. It is a required step for development and production servers, to confirm that you own the domain where Apple Pay will be implemented, preventing unauthorized use and maintaining the integrity of the payment system.
- Download and serve the domain association file (CSR) on your server at
https://<YOUR_DOMAIN>/.well-known/apple-developer-merchantid-domain-association
. - Add the public domain to your tenant using the merchant portal or the API
Apple requires the website to be served via HTTPS, which can be tricky during the development phase. Tunneling may represent a good option to preview local projects through a working HTTPS connection. Cloudflare tunnel may be worth checking out.
Configuring PublicSquare Elements
PublicSquare Elements are available for the following technologies. Click below for detailed instructions on how to install and configure them.
Creating an Apple Pay session
To initiate the Apple Pay payment modal, an Apple Pay session must be created.
Configure Apple Pay
First, let's add the Apple Pay button and initiate the Apple Pay session.
- JavaScript
- React
<div ref={buttonContainerRef}></div>
import { PublicSquare } from "@publicsquare/elements-js";
declare global {
var ApplePaySession: any;
}
let publicsquare;
async function init() {
publicsquare = await new PublicSquare().init('<PUBLISHABLE_API_KEY>');
// Step 1: Render the Apple Pay button
publicsquare.applePay.renderButton(buttonContainerRef.current!, {
id: 'apple-pay-btn',
onClick: onSubmitApplePay
});
function onSubmitApplePay() {
if (!ApplePaySession) {
return;
}
// Step 2: Create an Apple Pay session
const session = createApplePaySession();
// Step 3: Validate the CSR hosted at the your website
session.onvalidatemerchant = async () => {
const merchantSession = await validateMerchant();
session.completeMerchantValidation(merchantSession);
};
session.begin();
}
function createApplePaySession() {
return new ApplePaySession(3, {
countryCode: 'US',
currencyCode: 'USD',
merchantCapabilities: ['supports3DS'],
supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
total: {
label: 'Demo (Card is not charged)',
type: 'final',
amount: '1.99',
});
}
async function validateMerchant() {
try {
return await publicsquare?.applePay.createSession({
display_name: 'eCommerce Merchant Store',
domain: window.location.host,
});
} catch (error) {
console.error('Error validating merchant:', error);
throw error;
}
}
}
await init();
import {
PublicSquareProvider, usePublicSquare
} from '@publicsquare/elements-react'
import ApplePayButtonElement from '@publicsquare/elements-react/elements/ApplePayButtonElement';
declare global {
interface Window {
ApplePaySession: any;
}
}
async function onSubmitApplePay() {
if (!window.ApplePaySession) {
return;
}
// Step 2: Create an Apple Pay session
const session = createApplePaySession();
// Step 3: Validate the CSR hosted at the your website
session.onvalidatemerchant = async () => {
const merchantSession = await validateMerchant();
session.completeMerchantValidation(merchantSession);
};
session.begin();
}
function createApplePaySession() {
return new window.ApplePaySession(3, {
countryCode: 'US',
currencyCode: 'USD',
merchantCapabilities: ['supports3DS'],
supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
total: {
label: 'Demo (Card is not charged)',
type: 'final',
amount: '1.99',
},
});
}
async function validateMerchant() {
try {
return await publicsquare?.applePay.createSession({
display_name: 'PublicSquare Payments Demo',
domain: window.location.host,
});
} catch (error) {
console.error('Error validating merchant:', error);
throw error;
}
}
export default function App() {
const { publicsquare } = usePublicSquare();
return (
<PublicSquareProvider apiKey={apiKey}>
<div style={{ display: 'flex' }}>
<!-- Step 1: Render the Apple Pay button -->
<ApplePayButtonElement
id="apple-pay-element"
onClick={onSubmitApplePay}
/>
</div>
</PublicSquareProvider>
);
}
Adding the code above will render an Apple Pay
button on your site with an onClick
event which will start an Apple Pay session.
The createApplePaySession
function creates a new Apple Pay session with information about the payment.
The validateMerchant
function calls Public Square to initiate the Apple Pay session by checking the presence of the Apple Pay CSR configured during the Domain Verification step. This returns an Apple Pay session instance which is valid for 30 seconds.
Tokenization and Storing Apple Pay
After the customer has authorized the payment, your application will need to call our create
method from the SDK with the encrypted Apple Pay token to create an Apple Pay payment method in your account.
To do this, we will handle the session.onpaymentauthorized
event to call Public Square, passing the Apple Pay payment data:
- JavaScript
- React
import { PublicSquare } from "@publicsquare/elements-js"
declare global {
var ApplePaySession: any;
}
let publicsquare;
async function init() {
publicsquare = await new PublicSquare().init('<PUBLISHABLE_API_KEY>');
publicsquare.applePay.renderButton(buttonContainerRef.current!, {
id: 'apple-pay-btn',
onClick: onSubmitApplePay
});
function onSubmitApplePay() {
if (!ApplePaySession) {
return;
}
const session = createApplePaySession();
session.onvalidatemerchant = async () =>{ ... };
session.onpaymentauthorized = async (event: any) => {
try {
// Create an Apple Pay payment method from the encrypted payment token
const paymentMethod = await createApplePayPaymentMethod(event);
// Present green check to the user before the timeout (30 seconds)
session.completePayment(ApplePaySession.STATUS_SUCCESS);
// Send the payment method to the backend for payment processing
await chargePayment(paymentMethod.id);
} catch (e) {
console.error(e);
session.completePayment(ApplePaySession.STATUS_FAILURE);
}
};
session.begin();
}
function createApplePaySession() { ... }
async function validateMerchant() { ... }
async function createApplePayPaymentMethod(event: any) {
if (publicsquare) {
try {
const response = await publicsquare.applePay.create({
apple_payment_data: event.payment.token,
});
if (response) {
return response;
}
} catch (error) {
console.log(error);
}
}
}
}
await init();
import {
PublicSquareProvider, usePublicSquare
} from '@publicsquare/elements-react'
import ApplePayButtonElement from '@publicsquare/elements-react/elements/ApplePayButtonElement';
declare global {
interface Window {
ApplePaySession: any;
}
}
async function onSubmitApplePay() {
if (!window.ApplePaySession) {
return;
}
const session = createApplePaySession();
session.onvalidatemerchant = async () => { ... };
session.onpaymentauthorized = async (event: any) => {
try {
// Create an Apple Pay payment method from the encrypted payment token
const paymentMethod = await createApplePayPaymentMethod(event);
// Present green check to the user before the timeout (30 seconds)
session.completePayment(window.ApplePaySession.STATUS_SUCCESS);
// Send the payment method to the backend for payment processing
await chargePayment(paymentMethod.id);
} catch (e) {
console.error(e);
session.completePayment(window.ApplePaySession.STATUS_FAILURE);
}
};
session.begin();
}
function createApplePaySession() { ... }
async function validateMerchant() { ... }
async function createApplePayPaymentMethod(event: any) {
if (publicsquare) {
try {
const response = await publicsquare.applePay.create({
apple_payment_data: event.payment.token,
});
if (response) {
return response;
}
} catch (error) {
console.log(error);
}
}
}
export default function App() {
const { publicsquare } = usePublicSquare();
return (
<PublicSquareProvider apiKey={apiKey}>
<div style={{ display: 'flex' }}>
<ApplePayButtonElement
id="apple-pay-element"
onClick={onSubmitApplePay}
/>
</div>
</PublicSquareProvider>
);
}
The created Apple Pay
object contains the non-sensitive information about the Apple Pay:
{
"id": "appl_Aw3U2eESBnq6DoYEFn8qaSMrA",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"customer_id": "cus_7Ay5mcUXAxwrN6wQEQUVEHBCJ",
"token_type": "dpan",
"last4": "4242",
"exp_month": "12",
"exp_year": "2025",
"brand": "visa",
"billing_details": {
"address_line_1": "111 Colorado Ave.",
"address_line_2": "Apt 403",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
},
"expires_at": "2024-06-31T01:02:29.212Z",
"created_at": "2024-06-30T01:02:29.212Z",
"modified_at": "2024-06-30T01:02:29.212Z"
}
You can safely store the Apple Pay payment method id
value in your database to use it to process a payment or associate it with a customer.
You can optionally pass in a customer_id
to associate with an existing Created Customer and billing_details
to remove the requirement to pass them when Creating a Payment.
Conclusion
Following this guide, you have successfully collected a customer's Apple Pay. To use this Apple Pay payment method, proceed with the Process Apple Pay Payments guide.