Apple Pay on the Web
Apple Pay can now be used as a payment method within websites without requiring an iOS mobile application. This guide explains what WePay partners need to know to support Apple Pay on the Web.
Tip
Request Apple Pay integration information or consult with your Account Manager prior to beginning this integration.
Summary and Limitations
Payer and Device
- Any device that supports Apple Pay today (e.g. for in-app) will work with Apple Pay on the Web.
- iOS 10 or MacOS Sierra (v10.12) only (available early fall 2016).
- Safari only. Also supported in any iOS app using the newer SFSafariViewController.
- Payers must have a supported bank card loaded on their Apple Watch, or iPhone. Optionally, the partner can let the payer set up a card during the payment flow.
- If paying via a Mac, payers must have an iOS device enabled for Apple Pay physically “nearby”. The iOS device can be Apple Watch or iPhone with connectivity to the cloud and set up for iCloud.
Merchant
- Platforms that facilitate fundraising for causes and platforms that enable registered nonprofits to raise funds are not eligible to enable Apple Pay.
- Merchants accepting Apple Pay are subject to the Apple Pay terms.
- The above mentioned Apple Pay terms require that websites comply with the Apple Pay HI Guidelines.
Platform Integration
Custom checkout (tokenization) only. WePay hosted checkout (iframe) is not supported.
Transactions
- Apple Pay becomes a tokenized payment method, much like a credit card.
- A tokenized Apple Pay can be used for a single payment, or for a series of payments that the payer agrees to up front (e.g. a subscription). Apple Pay payment methods cannot be used for unrelated subsequent payments (“card on file”).
Note
Credit card IDs used within the Apple Pay flow are tied to the specific card the payer chose at the time the Apple Pay payment sheet was shown. If that underlying card expires or is shut down for any reason, the corresponding credit card ID will fail, but there will not be any way to know in advance. Account Updater will not update these cards.
Geographies
Merchants must be in the United States.
Processing Fees
- Apple Pay is treated like any other card not present payment. Fees will be a partner’s standard or negotiated card-not-present rate.
- App fees must be payee or payee-from-app - the amount that the payer pays must be known and final up front.
Platform Setup
WePay simplifies the onboarding process as much as possible, but there are some extra steps that a partner must do to get set up.
- Partner creates an Apple Developer Account.
- Partner creates their Apple merchant ID from the Apple Developer Portal. This is found under Certificates, Identifiers, and Profiles. Partners should create two merchant IDs, one for use with WePay’s stage environment and one for production.
- Partner gives WePay the 2 merchant IDs.
- WePay generates 2 Certificate Signing Requests (CSRs) per merchant ID (so a total of 4 if both merchant IDs are provided). Payment processing CSR is used for payment processing encryption. Apple Pay Merchant Identity CSR is used for merchant validation.
- WePay gives the CSRs to the partner (these are not sensitive and can be sent via regular email).
- Partner returns to their Apple Developer Account and submits the CSRs to Apple. Navigate to the Merchant ID Settings on the Apple Developer Portal. Take note of which CSRs correspond to the two merchant IDs.
- Apple immediately returns 2 certificates per merchant ID: Apple_pay.cer and Merchant_id.cer
- Partner emails these certificates to WePay at applepaycertificates@wepay.com.
Certificate Renewal
Note
The certificates generated during the Platform Setup stage typically expire in 2 years. Your platform should work with WePay to renew its certificates and prevent a disruption of payment processing. We recommend doing this 15-30 days before certificate expiration.
-
WePay generates two Certificate Signing Requests (CSRs) per merchant ID (a total of four if both stage and production merchant IDs are provided). The payment processing CSR is used for payment processing encryption while the Apple Pay Merchant Identity CSR is used for merchant validation.
-
WePay sends the CSRs to your platform (these are not sensitive and can be sent via regular email).
-
Your platform returns to its Apple Developer Account and submits the CSRs to Apple. Navigate to the Merchant ID Settings in the Apple Developer Portal and observe which CSRs correspond to the two merchant IDs.
Warning
After submitting the certificates to Apple, do not take any action to activate or revoke certificates. That should be done in a later step. Premature activation/revocation will result in disruption of payment processing.
- Apple immediately returns two certificates per merchant ID: Apple_pay.cer and Merchant_id.cer
- Your platform should email these certificates to WePay at applepaycertificates@wepay.com.
- WePay uploads these certificates into its system, and notifies your platform.
- Your platform returns to its Apple Developer Account to:
- Activate the new payment processing certificates. This will automatically revoke the old payment processing certificates.
- Revoke the old merchant identity certificates.
Domain Validation
Apple requires partners to prove ownership of the domain that will host the Apple Pay button. Partners will also have to ensure that they load WePay’s JavaScript SDK from the same domain that they provide to Apple.
1. Partner returns to their Apple Developer Account
- Navigate to the Merchant ID Settings
- Click "Add domain" in the Merchant Domains pane
- Provide the full domain of the page which will host the Apple Pay button (e.g. checkout.wepay.com)
- Click "continue"
2. If this is the first time you are validating this domain on your Apple Developer Account
- Apple will provide a file and specify a location on your website where you must upload the file
- Once you have uploaded the file to the specified location, come back to this page on the developer portal, and click "verify"
- The Status field should change to "verified"
3. Apple will automatically change the Status for your domain as “verified” if you have previously verified this domain on your Apple Developer Account.
Caution
The same domain can be used with multiple merchant IDs, including both stage and production. Merchants with their own website and domain cannot iframe in a platform’s Apple Pay checkout flow, as then the domain would not be the one registered with Apple.
Platform Integration With WePay
Processing Summary - platform perspective
- Platform website code calls the WePay JavaScript SDK to verify that Apple Pay is possible
- Platform website code shows "Pay with Apple Pay" button
- Payer chooses "Pay with Apple Pay"
- Platform website code triggers WePay JavaScript, which triggers Apple’s JavaScript
- The Apple Pay payment sheet is shown
- Amount must be known at this point, though things like tax and shipping can be added based on choices on the payment sheet.
- Payer clicks pay / presses finger on finger print reader
- Payment sheet shows a spinning cursor while processing is in progress
- iOS users approve on the device itself
- MacOS users approve on the device or an Apple Watch.
- If successful, WePay creates a credit card ID compatible with /checkout/create and returns it from the JavaScript to the platform website code
- Platform processing from here is the same as any other tokenized credit card:
- Website submits token to platform server
- Platform server calls /checkout/create with the credit card ID
- Amount must match what was set on the payment sheet
- Partner tells WePay JavaScript that checkout is successful (or not) - will dismiss the payment sheet
The following sections provide more details on these steps.
Verifying payers are ready for Apple Pay
The WePay JavaScript SDK will provide two calls to choose from:
WePay.wallet.canMakeApplePayPayments()
- This call performs the Lite Test which verifies the Mac has logged into an iCloud account that is associated with an iPhone or Apple Watch capable of using Apple Pay.
WePay.wallet.canMakeApplePayPaymentsWithActiveCard()
- This call performs the Full Test which verifies that the Mac has logged into an iCloud account that is associated with an iPhone or Apple Watch set up with Apple Pay and a stored card.
Partners can choose:
- Lite Test: The Pay with Apple Pay flow will automatically invite payers to setup Apple Pay if not already set up.
- Full Test: The Apple Pay flow will only show if payers are already set up for it
The Lite Test checks for the following
- Appropriate device
- Appropriate OS
- Device is setup for iCloud
- Device is capable of using iPhone
The Full Test checks for the following:
- Appropriate device
- Appropriate OS
- Device is setup for iCloud
- Device is setup for Apple Pay with a stored card
Initiating Payment via Apple Pay
To initiate an Apple Pay payment, the platform browser code calls WePay.wallet.beginTokenization()
in the WePay JavaScript SDK. To make this call, the platform must capture the amount. In addition, there are options that can be set such as contact email but the payer can also make changes on the payment sheet such as the following:
- Shipping options
- Shipping address which can drive tax decisions
The WePay.wallet.beginTokenization()
call performs the following:
- Displays the payment sheet directly in Safari on the Mac or iPhone with the "Processing" label and spinner showing to indicate that the verification
process is underway. However, if
canMakeApplePayPayments()
is true butcanMakeApplePayPaymentsWithActiveCard()
is false, instead of showing the payment sheet, a popup dialog appears which prompts the user to setup a card. Clicking "Set up now" dismisses the dialog, and the associated device prompts the user to add a card. - If payment sheet is shown, a verification check is run on the associated iPhone or Apple Watch for the following:
- Powered on
- Active data connection available (either cellular or wi-fi)
- Unlocked at least one time since last device boot.
- If the device does not meet any of the verification checks in step 2, the payment sheet will be dismissed and the browser will present a dialog message: "Bill's iPhone could not be found to confirm this payment."
- If all the verification checks pass in step 2, then merchant validation is automatically performed. If the merchant validation passes, then a credit card ID is returned.
Partner Expectations while the Payment Sheet is Showing
The payer can change shipping and payment method options as well as add/edit their email address on the payment sheet
If the payer makes changes to payment method, shipping contact or shipping method, WePay’s JavaScript SDK will inform the platform browser code of the update. The platform browser code can then change the total amount in response and update through the WePay JavaScript SDK. The user will then see an updated payment sheet.
These steps can happen any number of times before the payer approves payment.
The 3 update calls are the following:
WePay.wallet.updateAfterShippingContactSelected()
WePay.wallet.updateAfterShippingMethodSelected()
WePay.wallet.updateAfterPaymentMethodsSelected()
Payment Sheet Outcomes
When satisfied, the payer approves the payment using their iPhone, or Apple watch (even if initiating the transaction on a Mac OS device.) WePay’s JavaScript SDK hides all of the complexities of getting the payment information from Apple and tokenizing it, and returns a standard credit card ID to the platform website code.
There are various reasons why the payment sheet can return an error:
- The user cancels the transaction
- A timeout (perhaps there wasn’t a device available)
If any of these occur, the platform website code needs to restart the payment sheet using the beginTokenization()
call. (There is no need to re-verify that a device is ready to do ApplePay.)
Finalizing from Server with /checkout/create
From this point on, the platform browser and server code process a credit card ID the same as for a credit card.
- Browser code sends the ID to the platform server, with any other details collected from the payer
- Platform server calls WePay with /checkout/create
Note:
- The amount must match what was finally shown on the payment sheet
- Application fee settings, if used at all, must be payee or payee-from-app
The final step is to dismiss the payment sheet. Best practice is to do this after the payment is successfully authorized, thus waiting until /checkout/create succeeds. Dismissing the payment sheet is done by calling WePay.wallet.completePayment()
from the WePay JavaScript SDK.
Payer Email Information
WePay requires a payer email address. Partners can decide how to collect it:
- Partner’s own UX: ideal when the platform naturally already has or collects the payer’s email prior to the point where the Apple Pay button would be clicked.
- Via the payment sheet: The payment sheet will prompt the user for the payer’s email address. In some cases, it will be pre-filled from prior usage, info on the phone, etc. based on Apple’s rules.
Partners can decide to use either path, or both.
Email is supplied by partner | Email is not supplied by partner | |
---|---|---|
Email is collected via payment sheet | Payer will see email on payment sheet - prefilled by partner but can be edited | Payer will see email on payment sheet - may be prefilled by device or may be blank - payer must fill in if blank |
Email is not collected via payment sheet | Payer will not see email on payment sheet - partner supplied email will be used as is | Not allowed - if email is not supplied by partner, the SDK will automatically ask for email via payment sheet. |
To enable partner-supplied email: provide a ShippingContact object (with at least the emailAddress attribute defined) on the shippingContact attribute of the paymentRequest parameter.
To collect / edit email via the payment sheet: provide at least ‘email’ in the requiredShippingContactFields attribute of the paymentRequest parameter.
See the JavaScript SDK details below for more info.
Note
At present, an Apple Pay limitation will cause the payment sheet to ask for the email as a shipping contact. We realize this may not make sense for some partners. We are hoping to resolve this in a future release with Apple.
Transaction Rules
The intent is that payers approve each transaction, or a plausible series of related transactions that were understood at the time of the initial transaction.
Examples that are acceptable:
- Individual transactions: a complete payment sheet, new credit card ID, and a corresponding /checkout/create
- Recurring: these are considered acceptable:
- Paying $X/month, e.g. a gym membership
- Paying a varying amount each month for the same basic service, e.g. a phone bill
- Paying a set amount each time for a specific good or service, but on an irregular basis (e.g. tennis lessons)
For these recurring-type use cases, using the credit card ID for additional calls to /checkout/create is acceptable, and works like it does with credit cards.
Examples that are not acceptable:
- Obtaining a credit card ID via Apple Pay for unknown future purchases - “card on file”.
- Obtaining a credit card ID via Apple Pay for a specific, 1-time purchase, then using it later in a new /checkout/create for an unrelated purchase.
Testing
Stage Environment
WePay’s policies don’t allow partners to use production cards on our staging environment. The only way to test is by using Apple’s sandbox test accounts. The testing details for the stage environment are listed below:
- WePay and partners can create as many test accounts as they want using iTunes Connect
- A tester must log into a test account on their iPhone (using iCloud), and add a test card to their Apple Pay wallet
- Test cards are listed on Apple’s website at https://developer.apple.com/support/apple-pay-sandbox/
- The website must be using WePay’s stage environment, and their stage merchant id
- If the tester taps the Apple Pay button on any website, Apple will show the payment sheet in test mode
- The payer can go through the payment flow
- WePay will return a credit card ID
- Partners can send the credit card ID to their server and call /checkout/create on stage (https://stage.wepay.com/)
- Partners can use WePay’s existing online processing magic numbers for simulated results
Warning
Please do not use your Apple production accounts in the stage environment.
Production Environment
In order to test on the WePay production environment before Apple Pay officially goes live, please work with your WePay technical contact who will coordinate with Apple on the proper setup.
After Apple Pay goes live, a production account can be used to make real transactions on production. Please be aware that WePay does not support test scenarios once production is live, so partners will not be able to simulate errors/successes in production.
Use of Embedded Browsers
iOS apps can show web content in an embedded browser. Imagine a user is in an embedded browser and navigates to a partner’s site, and ultimately wants to checkout with Apple Pay.
- If the app was built with the newer SFSafariViewController, then Apple Pay will be supported
- If the app was built with the older embedded browser, then Apple Pay will not be supported
WePay JavaScript SDK Calls for Apple Pay
Several calls require the Apple Pay merchant ID. Use the same merchant IDs that you used while setting up Apple Pay with WePay.
Lite Test for Apple Pay Availability
This call operates synchronously, and will return with a boolean.
WePay.wallet.canMakeApplePayPayments()
Full Test for Apple Pay Availability
This call operates asynchronously, and will respond via a callback with an AvailabilityResponse object. WePay.wallet.canMakeApplePayPaymentsWithActiveCard(merchantId, callBack)
- merchantId (string): the ApplePay merchant identifier
- callBack (function): the callback function that accepts an AvailabilityResponse object.
Begin an Apple Pay Transaction
This method will open the Apple Pay payment sheet. WePay.wallet.beginTokenization(clientId, accountId, merchantId, paymentRequest, callback, onShippingContactSelected, onShippingMethodSelected, onPaymentMethodSelected)
- clientId (number): the WePay client ID
- accountId (number): the WePay account ID
- merchantId (string): the Apple Pay merchant ID
- paymentRequest (object): A PaymentRequest object containing the info required to initialize an Apple Pay payment sheet.
- callback (function): the callback function that accepts a PaymentResponse object.
If the platform optionally wants to be notified when the payer makes updates to the payment method, shipping contact, or shipping method, then supply the corresponding callbacks below.
- onShippingContactSelected(shippingContact): The callback function that accepts a {PaymentContact} object as a parameter. If provided, this function should finish by calling
WePay.wallet.updateAfterShippingContactSelected()
. - onShippingMethodSelected(shippingMethod): The callback function that accepts a {ShippingItem} object as a parameter. If provided, this function should finish by calling
WePay.wallet.updateAfterShippingMethodSelected()
. - onPaymentMethodSelected (paymentMethod): The callback function that accepts a {PaymentMethod} object as a parameter. If provided, this function should finish by calling
WePay.wallet.updateAfterPaymentMethodSelected()
.
Each callback must accept an object. After any updates, these must call the functions below to update the payment sheet.
Updating the Payment Sheet
If your website code made use of the payment sheet update callbacks in the previous section, they must use these functions to actually update the payment sheet:
WePay.wallet.updateAfterPaymentMethodSelected (newTotal, newLineItems)
- newTotal (object): a LineItem object representing the new adjusted total. Amount must be greater than zero.
- newLineItems (array): An array of LineItem objects representing all other costs or discounts
WePay.wallet.updateAfterShippingContactSelected (status, newShippingMethods, newTotal, newLineItems)
- status (number): The status code of the update.
- newShippingMethods (array): An array of ShippingItem objects representing shipping options, if any.
- newTotal (object): a LineItem object representing the new adjusted total. Amount must be greater than zero.
- newLineItems(array): An array of LineItem objects representing all other costs or discounts.
WePay.wallet.updateAfterShippingMethodSelected (status, newTotal, newLineItems)
- status (number): The status code of the update details.
- newTotal (object): a LineItem object representing the new adjusted total. Amount must be greater than zero.
- newLineItems(array): An array of LineItem objects representing all other costs or discounts.
Dismissing the Payment Sheet
Once a transaction is successfully processed via the platform’s (and WePay’s) server, use this to dismiss the payment sheet.
WePay.wallet.completePayment (status)
- status (number): The status code of the transaction.
Dismissing the Payment Request
Use this to abort the payment request and dismiss the payment sheet.
WePay.wallet.abort()
Supporting Objects
LineItem
- amount (String) - The amount for the item in decimal currency notation. For example, an amount of $1.25 should be
1.25
. This number must follow the regular expression-?[0-9]+(\.[0-9][0-9])?
- label (String) - The label for the item.
- type (String) - The type for the item. Must be
pending
orfinal
if provided.
ShippingItem
- label (String) - The label for the shipping item.
- amount (String) - The amount for the line item in decimal currency notation. For example, an amount of $1.25 should be
1.25
. The value must be a positive number that follows the regular expression?[0-9]+(\.[0-9][0-9])?
- detail (String) - Any additional shipping information to be displayed in the Apple Pay sheet.
- identifier (String) - A client-defined identifier.
PaymentMethod
- displayName (String) - The display name for the network.
- paymentNetwork (String) - The name of the network. The value must be one or more of
amex
,discover
,masterCard
, orvisa
. - Type (String) - The type of payment. The value must be one of
debit
,credit
,prepaid
, orstore
. - paymentPass (Object) - The payment pass object associated with the payment.
PaymentContact
- emailAddress (String) - An email address for the contact.
- phoneNumber (String) - A phone number for the contact.
- familyName (String) - The contact’s family name.
- givenName (String) - The contact’s given name.
- addressLines (Array(String)) - The address for the contact.
- locality (String) - The city for the contact.
- postalCode (String) - The zip code, where applicable, for the contact.
- administrativeArea (String) - The state for the contact.
- country (String) - The colloquial country name for the contact.
- countryCode (String) - The contact’s ISO country code.
PaymentRequest
- billingContact (PaymentContact) - Pre-filled billing contact information for the user.
- countryCode (String) - Required. The merchant’s two-letter ISO 3166 country code.
- currencyCode (String) - Required. The three-letter ISO 4217 currency code for the payment.
- displayName (String) - Required. The website’s display name to display in the Apple Pay payment sheet.
- lineItems (Array(LineItem)) - A set of items that explain recurring payments and additional charges.
- requiredBillingContactFields (Array) - The billing information that is required from the user. The value must be one or more of
postalAddress
orname
. - requiredShippingContactFields (Array) - The shipping information that is required from the user. The value must be one or more of
postalAddress
,phone
,email
, orname
. - shippingContact (PaymentContact) - Shipping contact information for the user. If prefilling the user’s email, supply it here.
- shippingMethods (Array(ShippingItem)) - The shipping method options for the shipment.
- shippingType (Array) - How the items are to be shipped. This property is optional. If specified, it must be one or more of
shipping
,delivery
,storePickup
, orservicePickup
. The default value isshipping
. - total (LineItem) - Required. The total amount LineItem for the payment.
Response Objects
AvailabilityResponse
- canMakePayments (Boolean) - Whether or not payments can be made.
- error (String) - Name of the error. Only exists if an error occurred. The above attribute will not be present in case of an error.
- error_description (String) - The error description. Only exists if error exists.
PaymentResponse
- creditCardId (Number) - The ‘token’ for the payment. For use with a checkout/create call.
- billingContact (PaymentContact) - the billing contact information of the payer.
- paymentMethod (PaymentMethod) - The payment method that was chosen for this payment.
- shippingContact (PaymentContact) - The shipping contact information of the payer (if requested).
- state (String) - The state of the card (generally, ‘new’)
- transactionIdentifier (String) - Unique identifier associated with this Apple Pay payment.
- error (String) - Name of the error. Only exists if an error occurred. The above attributes will not be present in case of an error.
- error_description (String) - The error description. Only exists if error exists.
Status Codes
- WePay.wallet.STATUS_SUCCESS
- WePay.wallet.STATUS_FAILURE
- WePay.wallet.STATUS_INVALID_BILLING_POSTAL_ADDRESS
- WePay.wallet.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS
- WePay.wallet.STATUS_INVALID_SHIPPING_CONTACT
Sample Code
Sample JavaScript for Apple Pay integration.
- JavaScript
Sample Objects
Sample objects for Apple Pay integration.
- JavaScript