On this page
No Headings
Last updated: June 18, 2026
Allow customers to save their PayPal Wallet in order to eliminate the need to re-enter payment details on subsequent purchases - leading to a faster checkout experience.
Important: Don't save PayPal as a payment method during purchase. For more information about securely saving payment methods and optimizing the buyer experience, see our Best practices guide.
Customers with a PayPal Wallet can:
Businesses save payment methods if they want customers to:
PayPal encrypts payment method information and stores it in a digital vault for that customer.
The checkout process for returning payers can now be made shorter by using saved payment information.
Set up your sandbox and live business accounts to save payment methods:
To go live, you'll need to be vetted for PayPal Wallet. You can start the vetting process from the Merchant Servicing Dashboard.
Tip: When prompted for data such as a phone number for the sandbox business request, enter any number that fits the required format. Since this is a sandbox request, the data doesn't have to be factual.
Add a button to your app's UI to complete a purchase with PayPal:
PayPalButton.Representable(){
// Create order server-side (see next step)
}Set up your server to call the Orders API. Set the
payment_source to paypal and request vaulting of the
payment source when the transaction completes successfully.
Modify the following request to create an order and initiate a vault for a PayPal payment source:
curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/ \\
-H "Content-Type: application/json"\\
-H "Authorization: Bearer ACCESS-TOKEN"\\
-H "PayPal-Request-Id: REQUEST-ID"\\
-d '{
"intent": "CAPTURE",
"purchase_units": [{
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}],
"payment_source": {
"paypal": {
"attributes": {
"vault": {
"store_in_vault": "ON_SUCCESS",
"usage_type": "MERCHANT",
"customer_type": "CONSUMER"
}
},
}
}
}'Return the id to your client to call the payer approval flow if
the payment_source needs payer approval.
Note: The request to save a PayPal payment source is made
when an order is created with the
payment_source.attributes.vault.store_in_vault property set to
true. Vault details are available only after an order is
authorized or captured.
{
"id": "5O190127TN364715T",
"status": "PAYER_ACTION_REQUIRED",
"payment_source": {
"paypal": {}
},
"links": [
{
"href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
"rel": "self",
"method": "GET"
},
{
"href": "https://www.paypal.com/checkoutnow?token=5O190127TN364715T",
"rel": "payer-action",
"method": "GET"
}
]
}Locate the id property in the Orders API response JSON. This is
the Order ID.
Send orderId to the iOS SDK to allow it to start PayPal Web
Checkout:
func startPayPalVaultDuringPurchase(){
let order =myCreateOrderFunc(amount:10.00,vaultPaymentMethodOnSuccess:true)
let config =CoreConfig(clientID:"CLIENT_ID",environment:.live)
let payPalClient =PayPalWebCheckoutClient(config: config)
payPalClient.delegate= self
let payPalRequest =PayPalWebCheckoutRequest(orderID: order.id,fundingSource:.paypal)
payPalWebCheckoutClient.start(request: payPalRequest)
}
func payPal(
_ payPalClient:PayPalWebCheckoutClient,
didFinishWithResult result:PayPalWebCheckoutResult
){
// After the payer approves, authorize or capture the transaction on your server (see next step)
}
func payPal(
_ payPalClient:PayPalWebCheckoutClient,
didFinishWithError error:CoreSDKError
){
// Handle error
}
func payPalDidCancel(_ payPalClient:PayPalWebCheckoutClient){
// PayPal Checkout cancelled
}After the payer approves, do one of the following on your server:
intent passed to create the order was CAPTUREintent passed to create the order was AUTHORIZEWhen capture or authorization succeeds, a vault.id is created.
curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/authorize \\
-H "Content-Type: application/json"\\
-H "Authorization: Bearer ACCESS-TOKEN"\\
-d '{}'curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/capture \\
-H "Content-Type: application/json"\\
-H "Authorization: Bearer ACCESS-TOKEN"\\
-d '{}'The HTTP response codes HTTP 2xx or HTTP 200 are
returned for a successful request.
The capture is successful if the
purchase_units[0].payments.captures.status is
COMPLETED. You can confirm with the payer that the payment has
been captured.
In the response from the authorize or capture request, the Orders v2 API interacts with the Payment Method Tokens v3 API. The Payment Method Tokens v3 API allows a PayPal Wallet to be saved. The response from the Orders v2 API contains the:
vault.idcustomer.idvault.statuslinks for the payment token of a recently saved PayPal Wallet.{
"id":"5O190127TN364715T",
"status":"COMPLETED",
"payment_source":{
"paypal":{
"attribute":{
"vault":{
"id":"3nqvjt3n",
"customer":{
"id":"208743798"
},
"status":"VAULTED",
"links":[{
"href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/3nqvjt3n",
"rel":"self",
"method":"GET"
},
{
"href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/3nqvjt3n",
"rel":"delete",
"method":"DELETE"
},
{
"href":"https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
"rel":"up",
"method":"GET"
}
]
}
},
"name":{
"given_name":"Firstname",
"surname":"Lastname"
},
"email_address":"[email protected]",
"phone_number":{
"national_number":"2025212022"
},
"account_id":"QYR5Z8XDVJNXQ",
"address":{
"country_code":"US"
},
}
},
"payer":{
"name":{
"given_name":"Firstname",
"surname":"Lastname"
},
"email_address":"[email protected]",
"phone_number":{
"national_number":"2025212022"
},
"payer_id":"QYR5Z8XDVJNXQ",
"address":{
"country_code":"US"
}
}
"purchase_units":[{
"reference_id":"d9f80740-38f0-11e8-b467-0ed5f89f718b",
"payments":{
"captures":[{
"id":"3C679366HH908993F",
"status":"COMPLETED",
"amount":{
"currency_code":"USD",
"value":"100.00"
},
"seller_protection":{
"status":"ELIGIBLE",
"dispute_categories":[
"ITEM_NOT_RECEIVED",
"UNAUTHORIZED_TRANSACTION"
]
},
"final_capture":true,
"seller_receivable_breakdown":{
"gross_amount":{
"currency_code":"USD",
"value":"100.00"
},
"paypal_fee":{
"currency_code":"USD",
"value":"3.00"
},
"net_amount":{
"currency_code":"USD",
"value":"97.00"
}
},
"create_time":"2022-01-01T21:20:49Z",
"update_time":"2022-01-01T21:20:49Z",
"links":[{
"href":"https://api-m.sandbox.paypal.com/v2/payments/captures/3C679366HH908993F",
"rel":"self",
"method":"GET"
},
{
"href":"https://api-m.sandbox.paypal.com/v2/payments/captures/3C679366HH908993F/refund",
"rel":"refund",
"method":"POST"
}
]
}]
}
}],
"links":[{
"href":"https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
"rel":"self",
"method":"GET"
}]
}If the payment has been authorized or captured, the payer does not 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. An example
of the attributes object from this scenario is in the following
sample:
"attributes":{
"vault":{
"status":"APPROVED",
"links":[
{
"href":"https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",
"rel":"up",
"method":"GET"
}
]
}
}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:
{
"id": "WH-72S4353495632143A-68K769747M133873M",
"event_version": "1.0",
"create_time": "2022-08-27T01:25:57.462Z",
"resource_type": "payment_token",
"resource_version": "3.0",
"event_type": "VAULT.PAYMENT-TOKEN.CREATED",
"summary": "A payment token has been created.",
"resource": {
"time_created": "2022-08-26T18:25:57.449PDT",
"links": [
{
"href": "https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/7vrxmrw",
"rel": "self",
"method": "GET",
"encType": "application/json"
},
{
"href": "https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/7vrxmrw",
"rel": "delete",
"method": "DELETE",
"encType": "application/json"
}
],
"id": "3nqvjt3n",
"payment_source": {
"paypal": {
"permit_multiple_payment_tokens": false,
"usage_type": "MERCHANT",
"customer_type": "CONSUMER",
"email_address": "[email protected]",
"payer_id": "VTR4JYK7STE7J"
}
},
"customer": {
"id": "208743798"
}
},
"links": [
{
"href": "https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-72S4353495632143A-68K769747M133873M",
"rel": "self",
"method": "GET"
},
{
"href": "https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-72S4353495632143A-68K769747M133873M/resend",
"rel": "resend",
"method": "POST"
}
]
}In the previous example, the resource.id field is the vault ID.
The resource.customer.id is the PayPal-generated customer ID.
Run the following tests in the PayPal sandbox to ensure you can save PayPal Wallets.
api-m.sandbox.paypal.com to api-m.paypal.com when going live with your integration.payment_source.paypal.attributes.vault for subsequent or recurring transactions.