WePay

Apple Pay for 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.

Summary and Limitations

Payer & 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

Apple Pay does not support collecting funds for charities and fundraisers of any designation - including, but not limted to, 501(c)(3) organizations. Unregistered fundraising is strictly not supported as well.

Platform Integration

Custom checkout (aka tokenization) only. WePay hosted checkout (iframe) is coming soon.

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 for Apple Pay

WePay simplifies the onboarding process as much as possible, but there are some extra steps that a partner must do to get set up.

  1. Partner creates an Apple Developer Account.
  2. 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.
  3. Partner gives WePay the 2 merchant IDs.
  4. 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.
  5. WePay gives the CSRs to the partner (these are not sensitive and can be sent via regular email).
  6. 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.
  7. Apple immediately returns 2 certificates per merchant ID: Apple_pay.cer and Merchant_id.cer
  8. Partner emails these certificates to WePay at applepaycertificates@wepay.com.

Domain Validation for Apple Pay

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
    1. Navigate to the Merchant ID Settings
    2. Click "Add domain" in the Merchant Domains pane
    3. Provide the full domain of the page which will host the Apple Pay button (e.g. checkout.wepay.com)
    4. Click "continue"
  2. If this is the first time you are validating this domain on your Apple Developer Account
    1. Apple will provide a file and specify a location on your website where you must upload the file
    2. Once you have uploaded the file to the specified location, come back to this page on the developer portal, and click "verify"
    3. 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.

Note about domains

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

  1. Platform website code calls the WePay javascript SDK to verify that Apple Pay is possible
  2. Platform website code shows "Pay with Apple Pay" button
  3. Payer chooses "Pay with Apple Pay"
  4. Platform website code triggers WePay javascript, which triggers Apple’s javascript
  5. The Apple Pay payment sheet is shown
    1. Amount must be known at this point, though things like tax and shipping can be added based on choices on the payment sheet.
  6. Payer clicks pay / presses finger on finger print reader
    1. Payment sheet shows a spinning cursor while processing is in progress
    2. iOS users approve on the device itself
    3. MacOS users approve on the device or an Apple Watch.
  7. If successful, WePay creates a credit card ID compatible with /checkout/create and returns it from the javascript to the platform website code
  8. Platform processing from here is the same as any other tokenized credit card:
    1. Website submits token to platform server
    2. Platform server calls /checkout/create with the credit card ID
    3. Amount must match what was set on the payment sheet
  9. 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:

  1. 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.
  2. 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
  • Email

The WePay.wallet.beginTokenization() call performs the following:

  1. Displays the payment sheet directly in Safari on the Mac with the "Processing" label and spinner showing to indicate that the tokenization process is underway. However, if canMakeApplePayPayments() is true but canMakeApplePayPaymentsWithActiveCard() 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.
  2. If payment sheet is shown, a verification check is run on the associated iPhone or Apple Watch for the following:
    1. Powered on
    2. Active data connection available (either cellular or wi-fi)
    3. Unlocked at least one time since last device boot.
  3. 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: "Cameron's iPhone could not be found to confirm this payment."
  4. 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

* Note: 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' or 'final' 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', or 'visa'.
  • Type (String) - The type of payment. The value must be one of 'debit', 'credit', 'prepaid', or 'store'.
  • 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' or 'name'.
  • requiredShippingContactFields (Array) - The shipping information that is required from the user. The value must be one or more of 'postalAddress', 'phone', 'email', or 'name'.
  • 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', or 'servicePickup'. The default value is 'shipping'.
  • 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

$(function() {
	// Point WePay to stage
	WePay.set_endpoint("stage");

	// Use your WePay client and account IDs here.
	var clientId = 12345;
	var accountId = 123456789;

	// This is your Apple-registered merchant identifier
	var merchantId = "example.com.wepay";

	// The canonical name for your store. This may be displayed to the user. 128-character or less UTF-8 string. Do not localize the name.
	var displayName = "WePay Example";

	// Check that Apple Pay is available on this device/OS. This call is synchronous.
	if (WePay.wallet.canMakeApplePayPayments()) {
		// Show Apple Pay button
	}

	// Alternatively, check that Apple Pay is available and the user has saved a card. This performs an async server call to Apple.
	WePay.wallet.canMakeApplePayPaymentsWithActiveCard(applePayMerchantId, function(response) {
		if (response.canMakePayments) {
			// Default to Apple Pay or show Apple Pay button
		}

		if (response.error) {
			// Handle error if needed.
		}
	});

	// If you ship products, you might want to have a variety of shipping method options depending on the shipping contact location.
	var localShippingMethods = [
		{label: 'Standard', detail: 'Standard shipping via USPS.', amount: '1.00', identifier: 'usps_l'},
		{label: 'Expedited', detail: 'Expedited shipping via UPS.', amount: '1.50', identifier: 'ups_expedited_l'},
		{label: 'Overnight', detail: 'Overnight shipping via UPS.', amount: '4.65', identifier: 'ups_overnight_l'}
	];
	var nationalShippingMethods = [
		{label: 'Standard', detail: 'Standard shipping via USPS.', amount: '3.15', identifier: 'usps_n'},
		{label: 'Expedited', detail: 'Expedited shipping via UPS.', amount: '5.25', identifier: 'ups_expedited_n'},
		{label: 'Overnight', detail: 'Overnight shipping via UPS.', amount: '14.60', identifier: 'ups_overnight_n'}
	];
	var internationalShippingMethods = [
		{label: 'International', detail: 'International shipping via USPS.', amount: '12.35', identifier: 'international'}
	];

	// Create the payment request object to use with the payment sheet. Make changes to this payment request object as needed in response
	// to changes on the payment sheet.
	var paymentRequest = {
		countryCode: 'US',
		currencyCode: 'USD',
		displayName: displayName,
		lineItems: [
			{label: 'Subtotal', amount: '10.00'},
			{label: 'Shipping', amount: '1.00'}
			{label: 'Tax', amount: '1.80'},
		],
		requiredBillingContactFields: ['name', 'postalAddress'], // Any combination of these is allowed.
		requiredShippingContactFields: ['name', 'phone', 'postalAddress', 'email'], // Any combination of these is allowed.
		shippingContact: {
			emailAddress: 'prefilled@example.com'
		},
		shippingMethods: localShippingMethods,
		shippingType: ['shipping'], // This value can be one or more of the following: shipping, delivery, storePickup, servicePickup
		total: {label: 'Total', amount: '12.80'} // This amount must always be the combined total of all line items (if lineItems are specified)
	};

	// Helper function to calculate a total from provided line items. This returns a string that is currency formatted.
	function calculateTotalFromLineItems(lineItems) {
		var total, x, item;

		// Initialize the new total as a float.
		total = 0.0;

		for (x in lineItems) {
			item = lineItems[x];
			total += parseFloat(item.amount); // Amounts are strings so we must convert to a float first.
		}

		return "" + total.toFixed(2); // Returns the total as a string with two decimal places.
	}

	var onPaymentMethodSelected = function(paymentMethod) {
		// The user changed their selected payment method. This can be used to update the line items and total if (for example)
		// you wish to charge more for a certain payment method. We aren’t making any changes here, so just pass in the original data
		var result = WePay.wallet.updateAfterPaymentMethodSelected(paymentRequest.total, paymentRequest.lineItems);
		if (result.error) {
			// Handle error if needed.
			WePay.wallet.abort();
		}
	};

	var onShippingMethodSelected = function(shippingMethod) {
		// The user changed their selected shipping method. This is where we update the shipping line item and new total.
		// Make the changes directly to your paymentRequest object from earlier.
		var x, item;
		for (x in paymentRequest.lineItems) {
			item = paymentRequest.lineItems[x];
			if (item.label == 'Shipping') {
				item.amount = shippingMethod.amount;
			}
		}

		paymentRequest.total.amount = calculateTotalFromLineItems(paymentRequest.lineItems);

		// This method takes a status param, which means that you can choose to inform the user that what they selected is invalid.
		var result = WePay.wallet.updateAfterShippingMethodSelected(WePay.wallet.STATUS_SUCCESS, 
									    paymentRequest.total,
									    paymentRequest.lineItems);
		if (result.error) {
			// Handle error if needed.
			WePay.wallet.abort();
		}
	};

	var onShippingContactSelected = function(shippingContact) {
		// The user changed their selected shipping contact. This is where we update the the available shipping methods based 
		// on the user’s location.
		var newShippingMethods, shippingAmount, x, item, result;

		if (shippingContact.countryCode !== ‘us’) {
			// Charge extra for international shipping
			newShippingMethods = internationalShippingMethods;
		}
		else if (shippingContact.administrativeArea !== 'CA') {
			// Charge a little extra for other states.
			newShippingMethods = nationalShippingMethods;
		}
		else {
			// Charge the local shipping rates
			newShippingMethods = localShippingMethods;
		}

		// Update the line item for shipping to the default shipping method (index 0)
		shippingAmount = newShippingMethods[0].amount;

		for (x in paymentRequest.lineItems) {
			item = paymentRequest.lineItems[x];
			if (item.label == 'Shipping') {
				item.amount = shippingAmount;
			}
		}

		// Apply the shipping methods and update the total
		paymentRequest.shippingMethods = newShippingMethods;
		paymentRequest.total.amount = calculateTotalFromLineItems(paymentRequest.lineItems);

		// This method takes a status param, which means that you can choose to inform the user that what they selected is invalid.
		result = WePay.wallet.updateAfterShippingContactSelected(WePay.wallet.STATUS_SUCCESS,
									 paymentRequest.shippingMethods,
									 paymentRequest.total,
									 paymentRequest.lineItems);
		if (result.error) {
			// Handle error if needed.
			WePay.wallet.abort();
		}
	};

	var callback = function(response) {
		// {string} credit_card_id, {object} paymentMethod, and an {object} error (if an error occurred).
		if (response.error) {
			// An error occurred during the Apple Pay tokenization process. Handle the error.
			WePay.wallet.abort();
			return;
		}

		var cardId = response.creditCardId;
		var paymentMethod = response.paymentMethod;
		// Make the call to your server with the card ID to complete the checkout process.
		$.ajax({
			url: "/processPayment",
			data: {
				credit_card_id: cardId
			},
			dataType: 'json',
			type: 'POST',
			success: function(result, status, xhr) {
				// Dismiss the payment sheet with a successful status
				WePay.wallet.completePayment(WePay.wallet.STATUS_SUCCESS);
			},
			error: function(xhr, status, error) {
				// Determine what went wrong and dismiss the payment sheet with the error
				WePay.wallet.completePayment(Wepay.wallet.STATUS_FAILURE);
			}
		});
	};

	// Respond to the Apple Pay button press
	$("#applepay-button").click(function(e) {
		// Begin tokenization with the previously defined parameters
		var result = WePay.wallet.beginTokenization(clientId,
							    accountId,
							    merchantId,
							    paymentRequest,
							    callback,
							    onShippingContactSelected,
							    onShippingMethodSelected,
							    onPaymentMethodSelected);

		if (result.error) {
			// Handle error if needed.
		}
	});
});

Sample Objects

	//LineItem:
	var lineItem = {
		type: "final",
		label: "Subtotal",
		amount: "1234.56"
	};

	//PaymentContact:
	var contact = {
		emailAddress: "test@email.com",
		phoneNumber: "1234567890",
		familyName: "Lastname",
		givenName: "Firstname",
		addressLines: ["123 California Street", "#100"],
		locality: "Redwood City",
		postalCode: "94061",
		administrativeArea: "CA",
		country: "United States",
		countryCode: "us"
	};

	//ShippingItem:
	var shippingItem = {
		label: "Next Day Air",
		detail: "Arrives in 1-2 business days.",
		amount: "25.00",
		identifier: "next_day_air"
	};

	//PaymentMethod
	var paymentMethod = {
		displayName: "MasterCard 1471",
		paymentNetwork: "MasterCard",
		type: "credit"
	};

	//PaymentRequest
	var paymentRequest = {
		billingContact: contact,
		countryCode: "us",
		currencyCode: "USD",
		lineItems: [lineItem, {label: "shipping", amount: "25.00", type: "final"}],
		requiredBillingContactFields: ["phone", "name"],
		requiredShippingContactFields: ["postalAddress", "name"],
		shippingContact: contact,
		shippingMethods: [shippingItem],
		shippingType: ["shipping"],
		total: {label: "Total", amount: "1259.56"}
	};


	//AvailabilityResponse
	var response = {
		canMakePayments: false,
		error: "InvalidAccessError", // This error occurs when using Apple Pay over http (instead of https)
		error_description: "The object does not support the operation or argument."
	};

	//PaymentResponse
	var response = {
		creditCardId: 1234567,
		transactionIdentifier: "a83abeCu134dai125ab",
		paymentMethod: paymentMethod,
		billingContact: billingContact,
		shippingContact: shippingContact,
	};