Save PayPal for purchase later with the JavaScript SDK

CurrentLast updated: December 11th 2023, @ 11:19:57 am


Save payment methods to charge payers after a set amount of time. For example, you can offer a free trial and charge payers after the trial expires. Payers don't need to be present when charged. No checkout required.

To save PayPal Wallets, payers need to log in to your site, make a purchase, and remain on your site when transactions take place.

Customers with a PayPal Wallet can:

  • Review PayPal transactions and transaction history
  • Review, add, or remove funding sources
  • Review and cancel recurring payments
  • Hold a balance in their PayPal account
  • Use PayPal to send and receive money
  • Withdraw money to a linked bank account
  • Use PayPal to transact with merchants

Availability

  • Australia
  • Austria
  • Belgium
  • Bulgaria
  • Canada
  • China
  • Cyprus
  • Czech Republic
  • Denmark
  • Estonia
  • Finland
  • France
  • Germany
  • Hungary
  • Ireland
  • Italy
  • Latvia
  • Liechtenstein
  • Lithuania
  • Luxembourg
  • Malta
  • Netherlands
  • Norway
  • Poland
  • Portugal
  • Romania
  • Slovakia
  • Slovenia
  • Spain
  • Sweden
  • United Kingdom
  • United States

Use cases

Businesses save payment methods if they want customers to:

  • Check out without re-entering a payment method
  • Pay after use, for example, ride-sharing and food delivery

Know before you code

  • To save payment methods, you must be able to identify payers uniquely. For example, payers create an account and log in to your site.
  • Complete the steps in Get started to get the following sandbox account information from the Developer Dashboard:
    • Your sandbox account login information
    • Your access token

  • This integration requires a PayPal Developer account.
  • This integration must include a server-side call to exchange a setup token for a payment method token.

How it works

PayPal encrypts payment method information and stores it in a digital vault for that customer.

  1. The payer saves their payment method.
  2. For a first-time payer, PayPal creates a customer ID. Store this within your system for future use.
  3. When the customer returns to your website and is ready to check out, pass their PayPal-generated customer ID to the JavaScript SDK. The customer ID tells the JavaScript SDK to save or reuse a saved payment method.
  4. The payer completes a billing agreement.
  5. The JavaScript SDK populates the checkout page with each saved payment method. Each payment method appears as a one-click button next to other ways to pay.

The checkout process is now shorter because it uses saved payment information.

1. Check eligibility

  1. Go to paypal.com and sign in with your business account.
  2. Go to Account Settings > Payment Preferences > Save PayPal and Venmo payment methods.
  3. In the Save PayPal and Venmo payment methods section, select Get Started.
  4. When you submit profile details, PayPal reviews your eligibility to save PayPal Wallets and Venmo accounts.
  5. After PayPal reviews your eligibility, you'll see a status of Success, Need more information, or Denied.

2. Set up account to save payments

Set up your sandbox and live business accounts to save payment methods:

  1. Log in to the Developer Dashboard.
  2. Under REST API apps, select your app name.
  3. Under Sandbox App Settings > App Feature Options, check Accept payments.
  4. Expand Advanced options. Confirm that Vault is selected.

To go live, you'll need to be vetted to save PayPal Wallets. You can start the vetting process from the Developer Dashboard.

  • Only your sandbox business account is enabled to save payment methods. Your developer account remains unaffected.
  • You'll complete production onboarding when you're ready to go live.

Tip: When prompted for data such as a phone number for a sandbox business request, enter any number that fits the required format. Since this is a sandbox request, the data doesn't have to be real.

3. Generate user ID token for payer

The PayPal OAuth 2.0 API has a has a response_type parameter. Set the response_type to id_token to retrieve a unique ID token for a payer.

  1. First-time payer
  2. Returning payer

A payer wants to save a payment method for the first time. Modify the following code to generate an id_token for the payer:

Sample server-side user ID token request

1curl -s -X POST 'https://api-m.sandbox.paypal.com/v1/oauth2/token' \
2 -u 'CLIENT-ID:CLIENT-SECRET' \
3 -H 'Content-Type: application/x-www-form-urlencoded' \
4 -d 'grant_type=client_credentials' \
5 -d 'response_type=id_token'

Modify the code

Copy the code sample and modify it as follows:

  • Change CLIENT-ID to your client ID.
  • Change CLIENT-SECRET to your client secret.

A successful request returns fields including an access_token, id_token, and the number of seconds the access_token token is valid.

The id_token:

  • Uniquely identifies each payer.
  • Expires in a few minutes because it's meant to be used during checkout. Generate new tokens if the current tokens expire.

Tip: Each buyer session is unique. Set up your server to generate a new client token each time payment fields render on your page.

4. Pass user ID token to JavaScript SDK

Pass the id_token into the JavaScript SDK through the data-user-id-token.

1<script src="https://www.paypal.com/sdk/js?client-id=CLIENT-ID" data-user-id-token="ID-TOKEN"></script>

Modify the code

Copy the code sample and modify it as follows:

  • Change CLIENT-ID to your client ID.
  • Change ID-TOKEN to the id_token from the previous step.

5. Add PayPal button

Include client-side callbacks to:

  • Manage interactions with APIs
  • Manage payer approval flows
  • Handle any events that lead to cancellation or error during payer approval

1<div id="your-div-id"></div>
2<script>
3 window.paypal.Buttons({
4 createVaultSetupToken: async () => {},
5 onApprove: async ({ vaultSetupToken }) => {},
6 onError: (error) => {}
7 }).render("#your-div-id");
8</script>

Modify the code

Copy the code sample and modify it as follows:

  1. Replace your-div-id with a div id of your choice.
  2. Replace #your-div-id with the div id you created.

6. Create setup token

You request a setup token from your server. Pass the setup token from your server to the SDK with the createVaultSetupToken callback.

The createVaultSetupToken callback:

  • Calls the server endpoint you created to generate and retrieve the setup token.
  • Makes a request to your server endpoint.

Then, your server uses its access token to create and return the setup token to the client.

Any errors that occur while creating a setup token show up in the onError callback provided to the card fields component.

Supported callback

CallbackReturnsDescription
createVaultSetupTokenSetup token (string)The merchant's server must receive this callback. Create a setup token for cards from the merchant server. The SDK then saves the payment method and updates the setup token with payment method details.

Client-side code sample

1window.paypal.Buttons({
2 createVaultSetupToken: async () => {
3 // Call your server API to generate a setup token
4 // and return it here as a string
5 const result = await fetch("https://example.com/create/setup/token")
6 return result.token
7 }
8})

Modify the code

Copy the code sample and modify it as follows:

  1. Change ACCESS-TOKEN to your sandbox app's access token.
  2. Change REQUEST-ID to a set of unique alphanumeric characters such as a time stamp.
  3. Set the usage_type under payment_source.paypal to be MERCHANT.
  4. In the createVaultSetupToken, call the endpoint on your server to create a setup token with the Payment Method Tokens API. createVaultSetupToken returns the setup token as a string.

Server-side code sample

Set up your server to call the Payment Method Tokens API. The button that the payer selects determines the payment_source sent in the following sample.

This SDK uses the Payment Method Tokens API to save payment methods in the background. Use the following request to add attributes needed to save a PayPal Wallet:

Note: The return_url and cancel_url values are required, but can have filler values such as in the following sample.

1curl -v -k -X POST 'https://api-m.sandbox.paypal.com/v3/vault/setup-tokens' \
2 -H 'Content-Type: application/json' \
3 -H 'Authorization: Bearer ACCESS-TOKEN' \
4 -H 'PayPal-Request-Id: REQUEST-ID' \
5 -d '{
6 "payment_source": {
7 "paypal": {
8 "usage_type": "MERCHANT",
9 "experience_context": {
10 "return_url": "https://example.com/returnUrl",
11 "cancel_url": "https://example.com/cancelUrl"
12 }
13 }
14 }
15 }'

Response

Return the id to your client to call for the payer approval flow if the payment_source needs payer approval.

1{
2 "id": "4G4976650J0948357",
3 "customer": {
4 "id": "customer_4029352050"
5 },
6 "status": "PAYER_ACTION_REQUIRED",
7 "payment_source": {
8 "paypal": {
9 "description": "Description for PayPal to be shown to PayPal payer",
10 "usage_pattern": "IMMEDIATE",
11 "shipping": {
12 "name": {
13 "full_name": "Firstname Lastname"
14 },
15 "address": {
16 "address_line_1": "123 Main Street",
17 "address_line_2": "Unit A",
18 "admin_area_2": "Anytown",
19 "admin_area_1": "CA",
20 "postal_code": "12345",
21 "country_code": "US"
22 }
23 },
24 "permit_multiple_payment_tokens": false,
25 "usage_type": "MERCHANT",
26 "customer_type": "CONSUMER"
27 }
28 },
29 "links": [
30 {
31 "href": "https://api-m.sandbox.paypal.com/v3/vault/setup-tokens/4G4976650J0948357",
32 "rel": "self",
33 "method": "GET",
34 "encType": "application/json"
35 },
36 {
37 "href": "https://sandbox.paypal.com/agreements/approve?approval_session_id=4G4976650J0948357",
38 "rel": "approve",
39 "method": "GET",
40 "encType": "application/json"
41 }
42 ]
43 }

Note: This setup token is generated with an empty payment_source. The Buttons script uses this token to securely update the setup token with payment details.

Modify the code

  1. Change ACCESS-TOKEN to your sandbox app's access token.
  2. Change REQUEST-ID to a set of unique alphanumeric characters such as a time stamp.
  3. In the createVaultSetupToken, call the endpoint on your server to create a setup token with the Payment Method Tokens API. createVaultSetupToken returns the setup token as a string.

Payer approval

If payer approval is required, the client SDK calls the payer approval flow. The approval flow takes the payer through PayPal Checkout.

7. Create payment token

You can store a Merchant Customer ID aligned with your system to simplify the mapping of customer information within your system and PayPal when creating a payment token. This is an optional field that will return the value shared in the response.

Use an approved setup token to save the payer's payment method to the vault. Then, copy the sample request code to generate a payment token:

Supported callback

CallbackReturnsDescription
onApprove{ vaultSetupToken: string }The merchant gets the updated vaultSetupToken when the payment method is saved. The merchant must store the vaultSetupToken token in their system.

Client-side sample request

Modify the following request to match your server endpoint and payload:

1window.paypal.Buttons({
2 onApprove: ({ vaultSetupToken }) => {
3 // Send the vaultSetupToken to your server
4 // for your server to generate a payment token
5 return fetch("example.com/create/payment/token", {
6 body: JSON.stringify({ vaultSetupToken })
7 })
8 },
9})

Sample API request

1curl -v -k -X POST 'https://api-m.sandbox.paypal.com/v3/vault/payment-tokens' \
2 -H 'Content-Type: application/json' \
3 -H 'Authorization: Bearer ACCESS-TOKEN' \
4 -H 'PayPal-Request-Id: REQUEST-ID' \
5 -d '{
6 "payment_source": {
7 "token": {
8 "id": "4G4976650J0948357",
9 "type": "SETUP_TOKEN"
10 }
11 }
12 }'

Modify the code

Copy the code sample and modify it as follows:

  1. Change ACCESS-TOKEN to your sandbox access token.
  2. Change REQUEST-ID to a unique alphanumeric set of characters such as a time stamp.
  3. Use token as the payment source and complete the rest of the source object for your use case and business.
  4. Use your setup token ID to pass in the payment source parameter and type as the SETUP_TOKEN.

Step result

A successful request results in the following:

  • An HTTP response code of 200 or 201. Returns 200 for an idempotent request.
  • ID of the payment token and associated payment method information.
  • HATEOAS links:
RelMethodDescription
deleteDELETEMake a DELETE request to delete the payment token.
selfGETMake a GET request to this link to retrieve data about the saved payment method.

Sample API response

1{
2 "id": "jwgvx42",
3 "customer": {
4 "id": "customer_4029352050"
5 },
6 "payment_source": {
7 "paypal": {
8 "description": "Description for PayPal to be shown to PayPal payer",
9 "usage_pattern": "IMMEDIATE",
10 "shipping": {
11 "name": {
12 "full_name": "Firstname Lastname"
13 },
14 "address": {
15 "address_line_1": "123 Main St",
16 "address_line_2": "Unit A",
17 "admin_area_2": "Anytown",
18 "admin_area_1": "CA",
19 "postal_code": "12345",
20 "country_code": "US"
21 }
22 },
23 "permit_multiple_payment_tokens": false,
24 "usage_type": "MERCHANT",
25 "customer_type": "CONSUMER",
26 "email_address": "payer@example.com",
27 "payer_id": "AJM9JTWQJCFTA"
28 }
29 },
30 "links": [
31 {
32 "rel": "self",
33 "href": "https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/jwgvx42",
34 "method": "GET",
35 "encType": "application/json"
36 },
37 {
38 "rel": "delete",
39 "href": "https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/jwgvx42",
40 "method": "DELETE",
41 "encType": "application/json"
42 }
43 ]
44 }

8. Integrate back end

The following sample shows a complete back-end integration to save PayPal for purchase later:

1import "dotenv/config";
2import express from "express";
3const { PORT = 8888 } = process.env;
4const app = express();
5app.set("view engine", "ejs");
6app.use(express.static("public"));
7// Create setup token
8app.post("/create/setup/token", async (req, res) => {
9 try {
10 // Use your access token to securely generate a setup token
11 // with an empty payment_source
12 const vaultResponse = await fetch("https://api-m.sandbox.paypal.com/v3/vault/setup-tokens", {
13 method: "POST",
14 body: JSON.stringify({ payment_source: { paypal: {}} }),
15 headers: {
16 Authorization: 'Bearer ${ACCESS-TOKEN}'',
17 "PayPal-Request-Id": Date.now(),
18 }
19 })
20 // Return the reponse to the client
21 res.json(vaultResponse);
22 } catch (err) {
23 res.status(500).send(err.message);
24 }
25})
26// Create payment token from a setup token
27app.post("/create/payment/token/", async (req, res) => {
28 try {
29 const paymentTokenResult = await fetch(
30 "https://api-m.sandbox.paypal.com/v3/vault/payment-tokens",
31 {
32 method: "POST",
33 body: {
34 payment_source: {
35 token: {
36 id: req.body.vaultSetupToken,
37 type: "SETUP_TOKEN"
38 }
39 }
40 },
41 headers: {
42 Authorization: 'Bearer ${ACCESS-TOKEN}',
43 "PayPal-Request-Id": Date.now(),
44 }
45 })
46 const paymentMethodToken = paymentTokenResult.id
47 const customerId = paymentTokenResult.customer.id
48 await save(paymentMethodToken, customerId)
49 res.json(captureData);
50 } catch (err) {
51 res.status(500).send(err.message);
52 }
53})
54const save = async function(paymentMethodToken, customerId) {
55 // Specify where to save the payment method token
56}
57app.listen(PORT, () => {
58 console.log('Server listening at http://localhost:${PORT}/');
59})

9. Integrate front end

The following sample shows how a full script to save PayPal might appear in HTML:

1<div id="paypal-buttons-container"></div>
2<script src="https://www.paypal.com/sdk/js?client-id=CLIENT-ID&merchant-id=MERCHANT-ID" data-user-id-token="ID-TOKEN"></script>
3<script>
4 window.paypal.Buttons({
5 createVaultSetupToken: async () => {
6 // Call your server API to generate a setup token
7 // and return it here as a string
8 const result = await fetch("example.com/create/setup/token", { method: "POST" })
9 return result.token
10 },
11 onApprove: async ({ vaultSetupToken }) => {
12 return fetch("example.com/create/payment/token", { body: JSON.stringify({ vaultSetupToken }) })
13 },
14 onError: (error) => {
15 console.log("An error occurred: ", error)
16 }
17 }).render("#paypal-buttons-container");
18</script>

10. Test your integration

  1. Render a PayPal Button with callbacks defined.
  2. Select the button and complete the pop-up flow to approve saving the PayPal Wallet.
  3. On your server, save the vaultSetupToken and the PayPal-generated customer.id. Associate these tokens with the designated payer.
  4. Make a call on your server to swap your setup token for a payment token from the Payment Method Tokens API.
  5. Save or use an existing customer.id depending on whether the payer is a first-time payer or returning payer:
    1. For a first-time payer, save the PayPal-generated customer.id. The customer.id identifies the payer and their saved payment methods.
    2. For a returning payer, use the PayPal-generated customer.id to swap the setup-token for a payment-token.
  6. Save the payment-token for future use.

Optional: Show saved payment methods

We recommend creating a page on your site where payers can see their saved payment methods as in the following example:

A website showing a payment methods page. The page shows the payer saved a PayPal Wallet and a credit card. The PayPal Wallet option is highlighted

Next step

Go live with your integration.