Integrate PayPal payments into your Bubble app using the API Connector to call the PayPal Orders API. This tutorial walks through creating a PayPal developer app, configuring the API Connector with OAuth2 authentication, creating and capturing payment orders, and handling payment confirmation via webhooks — all configured visually in Bubble.
Overview: Integrating PayPal in Bubble via API Connector
PayPal is one of the most widely used payment processors, and integrating it into your Bubble app gives customers an alternative to credit card payments. This tutorial uses the API Connector approach rather than a third-party plugin, giving you direct control over the PayPal Orders API. You will create a PayPal developer app, configure authentication, build the order creation and capture flow, and set up webhooks for payment confirmation.
Prerequisites
- A Bubble account with an app
- A PayPal developer account (developer.paypal.com)
- Basic understanding of Bubble workflows and the API Connector plugin
- A page with a product or service that needs a payment button
Step-by-step guide
Create a PayPal developer app and get credentials
Create a PayPal developer app and get credentials
Go to developer.paypal.com and log in. Navigate to Dashboard → My Apps & Credentials. Make sure you are in the Sandbox tab (not Live). Click 'Create App.' Name it (e.g., 'My Bubble App') and select Merchant as the type. After creation, you will see your Client ID and Secret. Copy both — you will need them in Bubble. The sandbox environment provides test buyer and seller accounts for testing payments without real money. Switch to the Live tab only when you are ready for production.
Pro tip: PayPal sandbox provides default test accounts. Go to Dashboard → Sandbox → Accounts to see them and their credentials for testing.
Expected result: A PayPal app with a Client ID and Secret ready for use in Bubble's API Connector.
Configure the API Connector with PayPal authentication
Configure the API Connector with PayPal authentication
In Bubble, go to the Plugins tab → API Connector → Add another API. Name it 'PayPal.' Set Authentication to 'None / Self-handled' — you will handle OAuth2 manually for more control. Create the first API call named 'Get Access Token.' Set method to POST, URL to https://api-m.sandbox.paypal.com/v1/oauth2/token. Add a Header: Content-Type = application/x-www-form-urlencoded. Add another Header: Authorization = Basic [base64 of ClientID:Secret]. Add a Body parameter: grant_type = client_credentials. Mark the Authorization header as Private. Set 'Use as' to Action. Click Initialize to get the access token response.
1POST https://api-m.sandbox.paypal.com/v1/oauth2/token23Headers:4 Content-Type: application/x-www-form-urlencoded5 Authorization: Basic {base64(ClientID:Secret)}67Body:8 grant_type=client_credentials910Response:11{12 "scope": "...",13 "access_token": "A21AAF...",14 "token_type": "Bearer",15 "app_id": "APP-80W...",16 "expires_in": 3240017}Expected result: The API Connector returns a PayPal access token that you will use for subsequent API calls.
Create a PayPal order via API call
Create a PayPal order via API call
Add a second API call in the PayPal API group named 'Create Order.' Set method to POST, URL to https://api-m.sandbox.paypal.com/v2/checkout/orders. Add Headers: Content-Type = application/json, Authorization = Bearer [access_token] (make this a dynamic parameter). For the Body, add a JSON payload with the order details including the amount and currency. Set 'Use as' to Action. Initialize with sample data. The response includes an order ID and an approval URL — the approval URL is where you redirect the customer to approve the payment on PayPal.
1POST https://api-m.sandbox.paypal.com/v2/checkout/orders23Headers:4 Content-Type: application/json5 Authorization: Bearer <access_token>67Body:8{9 "intent": "CAPTURE",10 "purchase_units": [11 {12 "amount": {13 "currency_code": "USD",14 "value": "29.99"15 },16 "description": "Product purchase"17 }18 ],19 "application_context": {20 "return_url": "https://yourapp.bubbleapps.io/payment-success",21 "cancel_url": "https://yourapp.bubbleapps.io/payment-cancel"22 }23}Expected result: The API returns an order ID and approval links. The 'approve' link is where you redirect the customer.
Build the payment workflow
Build the payment workflow
On your payment page, add a Pay with PayPal button. Create a workflow: When button is clicked → Step 1: Call 'Get Access Token' action. Step 2: Call 'Create Order' action with the access_token from Result of step 1 and the dynamic amount from your product/cart. Step 3: Open an external website action → use the approval URL from Result of step 2 (the link with rel = 'approve'). The customer is redirected to PayPal to approve the payment. After approval, PayPal redirects them back to your return_url with a token parameter in the URL.
Pro tip: Store the PayPal order ID in a Custom State or your Order Data Type before redirecting — you will need it to capture the payment when the customer returns.
Expected result: Clicking the payment button creates a PayPal order and redirects the customer to PayPal for payment approval.
Capture the payment after customer approval
Capture the payment after customer approval
On your payment-success page, add a workflow for the 'Page is loaded' event. Step 1: Get the PayPal token from the URL using 'Get data from page URL → parameter token.' Step 2: Call 'Get Access Token' action. Step 3: Create a third API call named 'Capture Order' — POST to https://api-m.sandbox.paypal.com/v2/checkout/orders/[order_id]/capture with the bearer token. Call this action with the order ID from your stored data and the access token from Step 2. Step 4: If the capture succeeds (status = COMPLETED), update your Order record's status to Paid and show a success message.
Expected result: When the customer returns from PayPal, the payment is captured automatically and the order status updates to Paid.
Set up PayPal webhooks for payment confirmation
Set up PayPal webhooks for payment confirmation
In PayPal Developer Dashboard → My Apps → your app → Webhooks, click 'Add Webhook.' Enter your Bubble backend workflow URL. Select the event CHECKOUT.ORDER.APPROVED. In Bubble, create a Backend workflow called paypal-webhook. The webhook payload contains the order ID and payment status. Add actions to find the matching Order in your database and update its status. This is a safety net — even if the customer closes the browser before the return URL loads, the webhook confirms payment server-side. For complex payment flows with subscriptions or multi-currency support, RapidDev can help architect a robust PayPal integration.
Expected result: PayPal sends webhook notifications to your Bubble backend, ensuring payment confirmation even if the user closes their browser.
Complete working example
1{2 "PayPal API Calls": {3 "1_Get_Access_Token": {4 "method": "POST",5 "url": "https://api-m.sandbox.paypal.com/v1/oauth2/token",6 "headers": {7 "Content-Type": "application/x-www-form-urlencoded",8 "Authorization": "Basic {base64(ClientID:Secret)}"9 },10 "body": "grant_type=client_credentials",11 "use_as": "Action"12 },13 "2_Create_Order": {14 "method": "POST",15 "url": "https://api-m.sandbox.paypal.com/v2/checkout/orders",16 "headers": {17 "Content-Type": "application/json",18 "Authorization": "Bearer <dynamic_access_token>"19 },20 "body": {21 "intent": "CAPTURE",22 "purchase_units": [23 {24 "amount": {25 "currency_code": "USD",26 "value": "<dynamic_amount>"27 },28 "description": "<dynamic_description>"29 }30 ],31 "application_context": {32 "return_url": "https://yourapp.bubbleapps.io/payment-success",33 "cancel_url": "https://yourapp.bubbleapps.io/payment-cancel"34 }35 },36 "use_as": "Action"37 },38 "3_Capture_Order": {39 "method": "POST",40 "url": "https://api-m.sandbox.paypal.com/v2/checkout/orders/<order_id>/capture",41 "headers": {42 "Content-Type": "application/json",43 "Authorization": "Bearer <dynamic_access_token>"44 },45 "body": {},46 "use_as": "Action"47 }48 }49}Common mistakes when integrating PayPal in Bubble
Why it's a problem: Using the Live PayPal API URL during testing
How to avoid: Use sandbox URLs during development. Only switch to api-m.paypal.com (without 'sandbox') when going live.
Why it's a problem: Not marking the Authorization header as Private
How to avoid: Always check the 'Private' checkbox on the Authorization header in the API Connector.
Why it's a problem: Skipping the capture step after customer approval
How to avoid: Always call the Capture Order endpoint on the return URL page to finalize the payment.
Best practices
- Always use sandbox credentials and URLs during development and testing
- Mark all authentication parameters as Private in the API Connector
- Store the PayPal order ID in your database before redirecting to PayPal
- Set up webhooks as a backup for payment confirmation in case the return redirect fails
- Test the full payment flow end-to-end with PayPal sandbox test buyer accounts
- Log all API responses (success and failure) to a database for troubleshooting
- Add clear loading indicators while the PayPal API calls are processing
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to integrate PayPal payments into my Bubble.io app using the API Connector. I need to create orders, redirect customers to PayPal for approval, and capture payments. Can you walk me through the PayPal Orders API setup?
Help me configure the API Connector for PayPal payments. I need three API calls: Get Access Token, Create Order, and Capture Order. Set them up with the correct URLs, headers, and body parameters for the PayPal sandbox environment.
Frequently asked questions
Can I use a PayPal plugin instead of the API Connector?
Yes, there are PayPal plugins on the Bubble marketplace. However, the API Connector approach gives you direct control over the PayPal API, does not depend on a third-party plugin developer, and avoids plugin page-load overhead.
How do I switch from sandbox to live PayPal?
Change the API URL from api-m.sandbox.paypal.com to api-m.paypal.com, and replace your sandbox Client ID and Secret with your Live credentials from the PayPal developer dashboard.
Does PayPal charge transaction fees?
Yes. PayPal charges approximately 2.9% + $0.30 per domestic transaction for standard processing. International transactions have higher fees. Check PayPal's current pricing page for exact rates.
Can I accept PayPal and Stripe in the same Bubble app?
Yes. Offer both options on your payment page — a Pay with PayPal button and a Pay with Card (Stripe) button. Each triggers a different workflow. Store the payment method used on the Order record.
What if the customer cancels on the PayPal approval page?
PayPal redirects them to your cancel_url. On that page, show a message like 'Payment was cancelled' and a button to return to the cart or try again.
How do I handle refunds through PayPal in Bubble?
Create an additional API Connector call to PayPal's Refund endpoint (POST /v2/payments/captures/{capture_id}/refund). Call it from an admin workflow with the capture ID stored during the original payment.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation