Save Apple Pay with the JavaScript SDK

DocsCurrentLast updated: September 19th 2024, @ 11:07:28 am


Save Apple Pay payment methods so merchants can make recurring payments without the payer being present.

Note: Apple Pay can't be used as a payment method for returning buyers, according to Apple guidelines.

How it works

When a payer on your website agrees to save the Apple Pay payment method, PayPal creates a customer record after the first successful transaction, encrypts the payment method information, and stores it in the vault. The saved payment information can only be accessed by the merchant. The merchant can use this saved payment method to make recurring payments on behalf of the payer.

  1. The payer chooses to save their payment method.
  2. For a first-time payer, PayPal generates a customer ID. Store this in your system for future use.

Know before you code

  • To accept one-time or recurring payments using Apple Pay, you need a business account that is approved by PayPal.
  • You'll need an existing Apple Pay integration.
  • Complete the steps in Get started to get the following sandbox account information from the Developer Dashboard:
    • Sandbox client ID and secret of a REST app.
    • Access token to use the PayPal REST API server.
  • This integration uses the following:

1. Enable Apple Pay

Before your app can save Apple Pay as a payment method, verify that your sandbox business account supports Apple Pay. See the Apple Pay integration guide for more information.

Note: When your integration is ready to go live, read the Go live section below for details about the additional steps needed for Apple Pay onboarding.

This screenshot shows the Apple Pay sandbox settings in the mobile and digital payments section of the PayPal Developer Dashboard. This only applies to direct merchant integrations:

A screenshot showing the Apple Pay sandbox settings in the mobile and digital payments section of the PayPal Developer Dashboard

2. Create an Apple Pay Payment Session

An Apple Pay Payment Session is a payment sheet that PayPal shows to the payer to start a payment.

Request an Apple Pay Payment Session by passing the following request object:

1// Note: the `applepayConfig` object in this request is the response from `paypal.Applepay().config()`.
2const paymentRequest = {
3 countryCode: applepayConfig.countryCode,
4 merchantCapabilities: applepayConfig.merchantCapabilities,
5 supportedNetworks: applepayConfig.supportedNetworks,
6 currencyCode: "USD",
7 requiredShippingContactFields: ["name", "phone", "email", "postalAddress"],
8 requiredBillingContactFields: ["postalAddress"],
9 lineItems: [
10 {
11 label: "Recurring",
12 amount: "100.00",
13 paymentTiming: "recurring",
14 recurringPaymentStartDate: "2023-06-08T18:09:07.501Z"
15 }
16 ],
17 total: {
18 label: "Demo",
19 type: "final",
20 amount: "100.00"
21 }
22};
23const session = new ApplePaySession(4, paymentRequest);

3. Create order and Save Apple Pay

Server-side

Set up your server to call the Create Order v2 API endpoint. The Apple Pay button pressed on the client side determines the payment_source sent in the following sample.

This SDK uses the Orders v2 REST API to save the Apple Pay payment method in the background. Add the attributes needed to save an Apple Pay payment method by using the request from Save Apple Pay for the first time below.

Platform considerations

When your platform saves a payment method, it can be owned by either:

  1. Your platform.
  2. A merchant on your platform.

If you are a platform, pass the the build notation (BN) code of the partner in the PayPal-Partner-Attribution-Id header for server-side calls to the Orders API. PayPal uses this information for reporting and tracking purposes.

For a merchant on your platform, pass the PayPal-Auth-Assertion header as part of calls to the Orders API. This ensures that the owner of the saved payment method is the merchant, not your platform.

Save Apple Pay for the first time

Save the Apple Pay payment method the first time a payer opts in. This request is for payers who meet both of these conditions:

  • Payer hasn't previously stored Apple Pay as a payment method for recurring purchases.
  • Payer consents to store the Apple Pay payment method for future use.

Request

1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer ACCESS-TOKEN" \
4 -H "PayPal-Partner-Attribution-Id: BN-CODE" \
5 -d '{
6 "intent": "CAPTURE",
7 "purchase_units": [{
8 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
9 "amount": {
10 "currency_code": "USD",
11 "value": "100.00"
12 }
13 }],
14 "payment_source": {
15 "apple_pay": {
16 "stored_credential": {
17 "payment_initiator": "CUSTOMER",
18 "payment_type": "RECURRING"
19 },
20 "attributes": {
21 "vault": {
22 "store_in_vault": "ON_SUCCESS"
23 }
24 }
25 }
26 }
27 }

Note: When payment_source.apple_pay.attributes.vault.store_in_vault is set to ON_SUCCESS, that means the Apple Pay payment method is saved when the authorization or capture succeeds.

Response

Pass the order.id to the JavaScript SDK. The SDK updates the order with the Apple Pay payment method that the payer selects. PayPal handles any PCI Compliance checks.

The request needs to pass payment_source.attributes.vault.store_in_vault to save the Apple Pay payment method. Details about a saved payment method are available only after an order is authorized or captured.

1{
2 "id": "5O190127TN364715T",
3 "status": "CREATED",
4 "intent": "CAPTURE",
5 "payment_source": {
6 "apple_pay": {
7 "name": "Firstname Lastname",
8 "email_address": "payer@example.com",
9 "phone_number": {
10 "national_number": "15555555555"
11 },
12 "card": {
13 "name": "Firstname Lastname",
14 "last_digits": "4949",
15 "brand": "VISA",
16 "type": "CREDIT",
17 "billing_address": {
18 "address_line_1": "123 Main St.",
19 "admin_area_2": "Anytown",
20 "admin_area_1": "CA",
21 "postal_code": "12345",
22 "country_code": "US"
23 }
24 }
25 },
26 "purchase_units": [{
27 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
28 "amount": {
29 "currency_code": "USD",
30 "value": "100.00"
31 }
32 }],
33 "create_time": "2021-10-28T21:18:49Z",
34 "links": [{
35 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
36 "rel": "self",
37 "method": "GET"
38 },
39 {
40 "href": "https://www.sandbox.paypal.com/checkoutnow?token=5O190127TN364715T",
41 "rel": "approve",
42 "method": "GET"
43 },
44 {
45 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
46 "rel": "update",
47 "method": "PATCH"
48 },
49 {
50 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/capture",
51 "rel": "capture",
52 "method": "POST"
53 }
54 ]
55 }

Save Apple Pay for returning payer

This request is for payers who:

  • Have an Apple Pay payment method already saved to the vault.
  • Want to save another Apple Pay payment method to the vault.

Pass the previously-stored PayPal-generated customer.id as part of this request. Link additional payment_sources to this customer using their customer.id.

Request

1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer ACCESS-TOKEN" \
4 -d '{
5 "intent": "CAPTURE",
6 "purchase_units": [{
7 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
8 "amount": {
9 "currency_code": "USD",
10 "value": "100.00"
11 }
12 }],
13 "payment_source": {
14 "apple_pay": {
15 "stored_credential": {
16 "payment_initiator": "CUSTOMER",
17 "payment_type": "RECURRING"
18 },
19 "attributes": {
20 "customer": {
21 "id": "PayPal-generated customer id"
22 },
23 "vault": {
24 "store_in_vault": "ON_SUCCESS"
25 },
26 }
27 }
28 }
29 }

Response

Pass the order.id to the JavaScript SDK. The SDK updates the order with the Apple Pay payment method that the payer selects. PayPal handles any PCI Compliance checks.

The request needs to pass payment_source.attributes.vault.store_in_vault to save the Apple Pay payment method. Details about a saved payment method are available only after an order is authorized or captured.

1{
2 "id": "5O190127TN364715T",
3 "status": "CREATED",
4 "intent": "CAPTURE",
5 "purchase_units": [{
6 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
7 "amount": {
8 "currency_code": "USD",
9 "value": "100.00"
10 }
11 }],
12 "create_time": "2021-10-28T21:18:49Z",
13 "links": [{
14 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
15 "rel": "self",
16 "method": "GET"
17 },
18 {
19 "href": "https://www.sandbox.paypal.com/checkoutnow?token=5O190127TN364715T",
20 "rel": "approve",
21 "method": "GET"
22 },
23 {
24 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
25 "rel": "update",
26 "method": "PATCH"
27 },
28 {
29 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/capture",
30 "rel": "capture",
31 "method": "POST"
32 }
33 ]
34 }

4. Authorize or capture order and save Apple Pay

Set up your server to call the Authorize or Capture Order APIs:

After the payer approves, the onApprove function is called in the JavaScript SDK. Depending on the intent passed as part of your Create Order call, the server calls the following APIs:

  • Capture Order v2 API endpoint if the intent passed was CAPTURE.
  • Authorize Order v2 API endpoint if the intent passed was AUTHORIZE.
  • Platform integrations need to pass the PayPal-Partner-Attribution-Id header for reporting and tracking purposes.

Request

Authorize order request

1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/authorize \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer ACCESS-TOKEN" \
4 -H "PayPal-Partner-Attribution-Id: BN-CODE" \
5 -d '{}'

Capture order request

1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/capture \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer ACCESS-TOKEN" \
4 -H "PayPal-Partner-Attribution-Id: BN-CODE" \
5 -d '{}'

Response

1{
2 "id": "5O190127TN364715T",
3 "intent": "CAPTURE",
4 "status": "COMPLETED",
5 "payment_source": {
6 "apple_pay": {
7 "name": "Firstname Lastname",
8 "email_address": "payer@example.com",
9 "phone_number": {
10 "national_number": "15555555555"
11 },
12 "card": {
13 "name": "Firstname Lastname",
14 "last_digits": "4949",
15 "brand": "VISA",
16 "type": "CREDIT",
17 "billing_address": {
18 "address_line_1": "123 Main St.",
19 "admin_area_2": "Anytown",
20 "admin_area_1": "CA",
21 "postal_code": "12345",
22 "country_code": "US"
23 },
24 },
25 "attributes": {
26 "vault": {
27 "id": "nkq2y9g",
28 "customer": {
29 "id": "695922590"
30 },
31 "status": "VAULTED",
32 "links": [{
33 "href": "https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/nkq2y9g",
34 "rel": "self",
35 "method": "GET"
36 },
37 {
38 "href": "https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/nkq2y9g",
39 "rel": "delete",
40 "method": "DELETE"
41 },
42 {
43 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
44 "rel": "up",
45 "method": "GET"
46 }
47 ]
48 }
49 }
50 }
51 },
52 "purchase_units": [{
53 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
54 "payments": {
55 "captures": [{
56 "id": "3C679366HH908993F",
57 "status": "COMPLETED",
58 "amount": {
59 "currency_code": "USD",
60 "value": "100.00"
61 },
62 "seller_protection": {
63 "status": "NOT_ELIGIBLE"
64 },
65 "final_capture": true,
66 "seller_receivable_breakdown": {
67 "gross_amount": {
68 "currency_code": "USD",
69 "value": "100.00"
70 },
71 "paypal_fee": {
72 "currency_code": "USD",
73 "value": "3.00"
74 },
75 "net_amount": {
76 "currency_code": "USD",
77 "value": "97.00"
78 }
79 },
80 "create_time": "2022-01-01T21:20:49Z",
81 "update_time": "2022-01-01T21:20:49Z",
82 "processor_response": {
83 "avs_code": "Y",
84 "cvv_code": "M",
85 "response_code": "0000"
86 },
87 "links": [{
88 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/3C679366HH908993F",
89 "rel": "self",
90 "method": "GET"
91 },
92 {
93 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/3C679366HH908993F/refund",
94 "rel": "refund",
95 "method": "POST"
96 }
97 ]
98 }]
99 }
100 }],
101 "links": [{
102 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
103 "rel": "self",
104 "method": "GET"
105 }]
106}

The response to the authorize or capture request shows that the Orders v2 API calls the Payment Method Tokens v3 API to save the payment method.

This response passes the relevant information with the vault.id when the vault.status is VAULTED. Use this vault.id for future payments.

Check Orders API response

When a payer chooses to save Apple Pay for recurring purchases and the payment has been authorized or captured, the payer doesn't need to be present to save a payment_source. To keep checkout times as short as possible, the Orders API responds as soon as payment is captured.

If the attributes.vault.status returned after payment is "APPROVED", you won't have a vault.id yet. "APPROVED" means the payment is approved to be saved.

Payment methods are saved with a vault.id if the response returned is "VAULTED". An example of an "APPROVED" status is in the following sample:

1"attributes": {
2 "vault": {
3 "status": "APPROVED",
4 "links": [{
5 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
6 "rel": "up",
7 "method": "GET"
8 }]
9 }
10}

The Payment Method Tokens API still saves the payment source even after the Orders API returns its response and sends a webhook after the payment source is saved.

In order to retrieve a vault_id when an APPROVED status is returned, you'll need to subscribe to the VAULT.PAYMENT-TOKEN.CREATED webhook.

The Payment Method Tokens API sends a webhook after the payment source is saved. An example of the VAULT.PAYMENT-TOKEN.CREATED webhook payload is shown in the following sample:

1{
2 "id":"WH-1KN88282901968003-82E75604WM969463F",
3 "event_version":"1.0",
4 "create_time":"2022-08-15T14:13:48.978Z",
5 "resource_type":"payment_token",
6 "resource_version":"3.0",
7 "event_type":"VAULT.PAYMENT-TOKEN.CREATED",
8 "summary":"A payment token has been created.",
9 "resource":{
10 "time_created":"2022-08-15T07:13:48.964PDT",
11 "links":[
12 {
13 "href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/9n6724m",
14 "rel":"self",
15 "method":"GET",
16 "encType":"application/json"
17 },
18 {
19 "href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/9n6724m",
20 "rel":"delete",
21 "method":"DELETE",
22 "encType":"application/json"
23 }
24 ],
25 "id":"nkq2y9g",
26 "payment_source":{
27 "card":{
28 "last_digits":"1111",
29 "brand":"VISA",
30 "expiry":"2027-02",
31 "billing_address":{
32 "address_line_1":"123 Main St.",
33 "admin_area_2":"Anytown",
34 "admin_area_1":"CA",
35 "postal_code":"12345",
36 "country_code":"US"
37 }
38 }
39 },
40 "customer":{
41 "id":"695922590"
42 }
43 },
44 "links":[
45 {
46 "href":"https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1KN88282901968003-82E75604WM969463F",
47 "rel":"self",
48 "method":"GET"
49 },
50 {
51 "href":"https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1KN88282901968003-82E75604WM969463F/resend",
52 "rel":"resend",
53 "method":"POST"
54 }
55 ]
56 }

In the previous example, the resource.id field is the vault ID. The resource.customer.id is the PayPal-generated customer ID.

See also

5. Delete saved payment method token

To delete a saved payment method token, call the Delete Payment Token endpoint of the Payment Method Tokens v3 API:

1curl -v -X DELETE https://api-m.sandbox.paypal.com//v3/vault/payment-tokens/ nkq2y9g \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer ACCESS-TOKEN" \
4 -d '{}'

6. Pay with a saved payment method

Set up your checkout page to show a returning customer their saved Apple Pay payment method. Make a call to the Capture Payment for Order endpoint of the Orders v2 API and pass the apple_pay.vault_id.

To use a saved payment method:

  1. Use the List All Payment Tokens endpoint of the Payment Method Tokens v3 API to retrieve all the payment methods saved for the customer.
  2. Use the vault_id associated with the payment method the customer selected in the input of the Capture Payment for Order endpoint of the Orders v2 API.
  3. Log in to the sandbox with your merchant account and verify the transaction.

Note: The Javascript SDK has no direct support to show saved payments.

Merchant-initiated transactions

For merchants or partners who want to process a recurring payment for a customer with an Apple Pay payment method already saved:

1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer ACCESS-TOKEN" \
4 -d '{
5 "intent": "CAPTURE",
6 "purchase_units": [{
7 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
8 "amount": {
9 "currency_code": "USD",
10 "value": "100.00"
11 }
12 }],
13 "payment_source": {
14 "apple_pay": {
15 "stored_credential": {
16 "payment_initiator": "MERCHANT",
17 "payment_type": "RECURRING",
18 "usage": "SUBSEQUENT",
19 },
20 "vault_id": "nkq2y9g"
21 }
22 }
23 }

7. Test your integration

Test in the PayPal sandbox to ensure that saving payment methods works correctly.

Save payment method

  1. On your checkout page, enter your card information and select the option to save your card. You can use test card numbers for testing.
  2. Capture the payment.
  3. Log in to sandbox with your merchant account and verify the transaction.

Test cards for Apple Pay

Refer to Apple's sandbox testing page to learn more about using test cards for Apple Pay.

8. Next steps

9. Go live

  1. Go to paypal.com and sign in with your business account.
  2. Go to Account Settings > Payment Method > Enable Apple Pay.
  3. In the Apple Pay payment methods section, select Get Started.
  4. After you submit the details on the Profile collection, your status will change to "Your eligibility to save customer Apple Pay payment methods is under review". It might be approved instantly as well.
  5. Based on information provided in the profile collection of the Business Account, you might see a status like Denied, Success, or Need more information. Once the information is vetted, you get a Success status.