Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
Overview
About Stripe payments
Upgrade your integration
Payments analytics
Online payments
OverviewFind your use caseManaged Payments
Use Payment Links
Build a checkout page
Build an advanced integration
Build an in-app integration
Payment methods
Add payment methods
    Overview
    Payment method integration options
    Manage default payment methods in the Dashboard
    Payment method types
    Cards
    Pay with Stripe balance
    Crypto
    Bank debits
    Bank redirects
    Bank transfers
    Credit transfers (Sources)
    Buy now, pay later
    Real-time payments
    Vouchers
    Wallets
      Alipay
      Amazon Pay
      Apple Pay
      Cash App Pay
      Google Pay
      GrabPay
      Link
      MB WAY
      MobilePay
      PayPal
        PayPal button
        Activate PayPal payments
        Accept a payment
        Set up future payments
        Choose settlement preference
        Disputed payments
        Payout reconciliation
        Supported locales
        Import saved PayPal payment methods
      PayPay
      Revolut Pay
      Satispay
      Secure Remote Commerce
      Vipps
      WeChat Pay
    Enable local payment methods by country
    Custom payment methods
Manage payment methods
Faster checkout with Link
Payment interfaces
Payment Links
Checkout
Web Elements
In-app Elements
Payment scenarios
Handle multiple currencies
Custom payment flows
Flexible acquiring
Orchestration
In-person payments
Terminal
Beyond payments
Incorporate your company
Crypto
Financial Connections
Climate
HomePaymentsAdd payment methodsWalletsPayPal

Set up future PayPal payments

Learn how to save PayPal details and charge your customers later.

Set up future PayPal payments to save customer payment details for subscriptions, delayed charges, and streamlined future purchases. Learn how to enable and use recurring payments with PayPal through Stripe.

Enable recurring payments

Stripe automatically enables recurring payments for most users when they activate PayPal payments in the Stripe Dashboard. However, due to PayPal’s policies and regional restrictions, some users might need to enable recurring payments manually. This includes users that set up their accounts before we introduced automatic enablement. To manually enable recurring payments:

  1. Go to your Payment methods settings.

  2. Click PayPal > Enable in the Recurring payments section.

After you enable recurring payments, it appears as pending in the Dashboard. It usually takes up to five business days to get access.

When you’re granted access, recurring payments are available in your PayPal settings. In testing environments, recurring payments are enabled by default.

You can use Setup Intents to collect PayPal payment method details in advance, and determine the final amount or payment date later. Use it to:

  • Save payment methods to a wallet to streamline future purchases
  • Collect surcharges after fulfilling a service
  • Start a free trial for a subscription

Set up Stripe
Server-side

First, you need a Stripe account. Register now.

Use our official libraries for access to the Stripe API from your application:

Command Line
Ruby
# Available as a gem sudo gem install stripe
Gemfile
Ruby
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Create or retrieve a Customer before setup
Server-side

To reuse a PayPal payment method for future payments, it must be attached to a Customer.

You should create a Customer object when your customer creates an account on your business. Associating the ID of the Customer object with your own internal representation of a customer will enable you to retrieve and use the stored payment method details later. If your customer hasn’t created an account, you can still create a Customer object now and associate it with your internal representation of the customer’s account later.

Command Line
cURL
curl -X POST https://api.stripe.com/v1/customers \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"

Create a SetupIntent
Server-side

A SetupIntent is an object that represents your intent and tracks the steps to set up your customer’s payment method for future payments.

Create a SetupIntent on your server with payment_method_types set to paypal and specify the Customer’s id.

Command Line
cURL
curl https://api.stripe.com/v1/setup_intents \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d customer=
{{CUSTOMER_ID}}
\ -d "payment_method_types[]"=paypal \ -d "payment_method_data[type]"=paypal

The SetupIntent object contains a client_secret, a unique key that you need to pass to Stripe on the client side to redirect your buyer to PayPal and authorize the mandate.

Redirect your customer
Client-side

When a customer attempts to set up their PayPal account for future payments, we recommend you use Stripe.js to confirm the SetupIntent. Stripe.js is our foundational JavaScript library for building payment flows. It will automatically handle complexities like the redirect described below, and enables you to easily extend your integration to other payment methods in the future.

Include the Stripe.js script on your checkout page by adding it to the head of your HTML file.

checkout.html
<head> <title>Checkout</title> <script src="https://js.stripe.com/basil/stripe.js"></script> </head>

Create an instance of Stripe.js with the following JavaScript on your checkout page.

// Set your publishable key. Remember to change this to your live publishable key in production! // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
, {} );

To confirm the setup on the client side, pass the client secret of the SetupIntent object that you created in Step 3.

The client secret is different from your API keys that authenticate Stripe API requests. It should still be handled carefully because it can complete the charge. Do not log it, embed it in URLs, or expose it to anyone but the customer.

Confirm PayPal Setup

To authorize you to use their PayPal account for future payments, your customer will be redirected to a PayPal billing agreement page, which they will need to approve before being redirected back to your website. Use stripe.confirmPayPalSetup to handle the redirect away from your page and to complete the setup. Add a return_url to this function to indicate where Stripe should redirect the user to after they approve the billing agreement on PayPal’s website.

client.js
// Redirects away from the client const {error} = await stripe.confirmPayPalSetup( '{{SETUP_INTENT_CLIENT_SECRET}}', { return_url: 'https://example.com/setup/complete', mandate_data: { customer_acceptance: { type: 'online', online: { infer_from_client: true } } }, } ); if (error) { // Inform the customer that there was an error. }

You can find the Payment Method payer ID and Billing Agreement ID on the resulting Mandate under the payment_method_details property. You can also find the buyer’s email and payer ID in the paypal property on the PaymentMethod.

FieldValue
payer_emailThe email address of the payer on their PayPal account.
payer_idA unique ID of the payer’s PayPal account.
billing_agreement_idThe PayPal Billing Agreement ID (BAID). This is an ID generated by PayPal which represents the mandate between the business and the customer.

Monitor webhooks
Server-side

Use a method such as webhooks to confirm the billing agreement was authorized successfully by your customer, instead of relying on your customer to return to the payment status page. When a customer successfully authorizes the billing agreement, the SetupIntent emits the setup_intent.succeeded webhook event. If a customer doesn’t successfully authorize the billing agreement, the SetupIntent will emit the setup_intent.setup_failed webhook event and returns to a status of requires_payment_method. When a customer revokes the billing agreement from their PayPal account, the mandate.updated is emitted.

Charge off-session payments with a saved PayPal payment method
Server-side

When you’re ready to charge your customer off-session, use the Customer and PaymentMethod IDs to create a PaymentIntent.

To find a paypal instrument to charge, list the PaymentMethods associated with your Customer.

Command Line
cURL
curl -G https://api.stripe.com/v1/payment_methods \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d customer={{CUSTOMER_ID}} \ -d type=paypal

When you have the Customer and PaymentMethod IDs, create a PaymentIntent with the amount and currency of the payment. Set a few other parameters to make the off-session payment:

  • Set off_session to true to indicate that the customer is not in your checkout flow during this payment attempt. This causes the PaymentIntent to throw an error if authentication is required.
  • Set the value of the PaymentIntent’s confirm property to true, which causes confirmation to occur immediately when the PaymentIntent is created.
  • Set payment_method to the ID of the PaymentMethod and customer to the ID of the Customer.
Command Line
cURL
curl https://api.stripe.com/v1/payment_intents \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d amount=1099 \ -d currency=eur \ -d customer={{CUSTOMER_ID}} \ -d "payment_method_types[]"=paypal \ -d payment_method={{PAYMENT_METHOD_ID}} \ -d off_session=true \ -d confirm=true

Charge on-session payments with a saved PayPal payment method
Client-side

When you’re ready to charge your customer on-session, use the Customer and PaymentMethod IDs to create a PaymentIntent.

To find a paypal instrument to charge, list the PaymentMethods associated with your Customer.

Command Line
cURL
curl -G https://api.stripe.com/v1/payment_methods \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d customer={{CUSTOMER_ID}} \ -d type=paypal

When you have the Customer and PaymentMethod IDs, create a PaymentIntent with the amount and currency of the payment:

Command Line
cURL
curl https://api.stripe.com/v1/payment_intents \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d amount=1099 \ -d currency=eur \ -d customer={{CUSTOMER_ID}} \ -d "payment_method_types[]"=paypal \ -d payment_method={{PAYMENT_METHOD_ID}}

Using Stripe.js SDK, call the confirmPayPalPayment function to execute the created PaymentIntent:

client.js
// Confirms the on-session payment const {error} = await stripe.confirmPayPalPayment( '{{PAYMENT_INTENT_CLIENT_SECRET}}', {payment_method: '{{PAYMENT_METHOD_ID}}'} // Note: return_url is not required here because the PayPal payment method was // previously set up using either a SetupIntent or a PaymentIntent with setup_future_usage ); if (error) { // Inform the customer that there was an error. }

Note: The return_url parameter is conditionally required for confirmPayPalPayment:

  • It is not required when using a PayPal payment method that was previously set up with a SetupIntent or a PaymentIntent with setup_future_usage.
  • It is required for all other cases, including when creating a new PayPal payment method on-session.

User-initiated payment method cancellation
Server-side

A customer can cancel the subscription (Billing Agreement) through their PayPal account. When they do so, Stripe emits a mandate.updated webhook. All subsequent Payment Intents using the saved Payment Method will fail until you change to a Payment Method with active mandates. When payments fail for Subscriptions, the status changes to the Subscription status configured in your automatic collection settings. Notify the customer of failure and charge them with a different payment method.

OptionalSet up future PayPal payments and capture a payment
Server-side

OptionalHandle the PayPal redirect manually
Server-side

OptionalHandle risk library integration for on-session payments manually
Server-side

OptionalRemove a saved PayPal account
Server-side

Was this page helpful?
YesNo
Need help? Contact Support.
Join our early access program.
Check out our changelog.
Questions? Contact Sales.
LLM? Read llms.txt.
Powered by Markdoc