PayPal Setup Guide
This guide walks you through setting up PayPal as a payment provider in your UIGen application.
Prerequisites
- A PayPal Business account
- Access to the PayPal Developer Dashboard
- Your UIGen application with payment configuration
Step 1: Create PayPal App
- Go to the PayPal Developer Dashboard
- Log in with your PayPal Business account
- Navigate to Apps & Credentials
- Click Create App
- Enter your app name (e.g., "My UIGen App")
- Select Merchant as the app type
- Click Create App
Step 2: Get API Credentials
Sandbox Credentials (for testing)
- In your app dashboard, ensure Sandbox is selected
- Copy your Client ID (starts with
A...) - Click Show under Secret and copy the Client Secret
- Save these credentials securely
Live Credentials (for production)
- Switch to Live mode in the dashboard
- Copy your Live Client ID
- Click Show under Secret and copy the Live Client Secret
- Save these credentials securely
Step 3: Configure Webhooks
- In your app dashboard, scroll to Webhooks
- Click Add Webhook
- Enter your webhook URL:
https://your-api.com/webhooks/paypal - Select the following event types:
PAYMENT.SALE.COMPLETEDBILLING.SUBSCRIPTION.CREATEDBILLING.SUBSCRIPTION.UPDATEDBILLING.SUBSCRIPTION.CANCELLEDBILLING.SUBSCRIPTION.SUSPENDEDBILLING.SUBSCRIPTION.EXPIRED
- Click Save
- Copy the Webhook ID (you'll need this for verification)
Step 4: Add Configuration to UIGen
Add PayPal configuration to your OpenAPI spec:
info:
title: My API
version: 1.0.0
x-uigen-payments:
providers:
- provider: paypal
clientId: ${PAYPAL_CLIENT_ID}
clientSecret: ${PAYPAL_CLIENT_SECRET}
webhookSecret: ${PAYPAL_WEBHOOK_ID}
mode: sandbox # or 'live' for production
currency: usd
enabled: true
products:
- id: pro-monthly
name: Professional
type: subscription
price: 2900
interval: month
features:
- Unlimited access
- Priority support
Step 5: Set Environment Variables
Create or update your .env file:
# PayPal Configuration
PAYPAL_CLIENT_ID=your-client-id-here
PAYPAL_CLIENT_SECRET=your-client-secret-here
PAYPAL_WEBHOOK_ID=your-webhook-id-here
For production, use your live credentials:
# PayPal Production Configuration
PAYPAL_CLIENT_ID=your-live-client-id-here
PAYPAL_CLIENT_SECRET=your-live-client-secret-here
PAYPAL_WEBHOOK_ID=your-live-webhook-id-here
Step 6: Create Subscription Plans
PayPal requires you to create subscription plans in the dashboard:
- Go to Products & Services > Subscriptions
- Click Create Plan
- Fill in plan details:
- Plan name: Professional
- Plan ID:
pro-monthly(must match your config) - Billing cycle: Monthly
- Price: $29.00
- Click Save
- Copy the Plan ID and update your UIGen configuration
Step 7: Implement Webhook Handler
Create a webhook endpoint in your backend to handle PayPal events:
FastAPI Example
from fastapi import APIRouter, Request, HTTPException
import os
import json
from paypalrestsdk import WebhookEvent
router = APIRouter(prefix="/webhooks", tags=["webhooks"])
@router.post("/paypal")
async def paypal_webhook(request: Request):
payload = await request.body()
headers = dict(request.headers)
# Verify webhook signature
webhook_id = os.getenv('PAYPAL_WEBHOOK_ID')
try:
# PayPal webhook verification
event = json.loads(payload)
event_type = event.get('event_type')
# Handle different event types
if event_type == 'PAYMENT.SALE.COMPLETED':
sale = event['resource']
# Grant access to user
await grant_access(sale['custom_id'], sale['id'])
elif event_type == 'BILLING.SUBSCRIPTION.CREATED':
subscription = event['resource']
# Activate subscription
await activate_subscription(subscription['custom_id'], subscription['id'])
elif event_type == 'BILLING.SUBSCRIPTION.CANCELLED':
subscription = event['resource']
# Revoke access
await revoke_access(subscription['custom_id'])
return {"status": "success"}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
Express.js Example
const express = require('express');
const paypal = require('@paypal/checkout-server-sdk');
const router = express.Router();
router.post('/webhooks/paypal', express.json(), async (req, res) => {
const webhookId = process.env.PAYPAL_WEBHOOK_ID;
const event = req.body;
try {
// Verify webhook (implement verification logic)
// Handle event types
switch (event.event_type) {
case 'PAYMENT.SALE.COMPLETED':
const sale = event.resource;
// Grant access
await grantAccess(sale.custom_id, sale.id);
break;
case 'BILLING.SUBSCRIPTION.CREATED':
const subscription = event.resource;
// Activate subscription
await activateSubscription(subscription.custom_id, subscription.id);
break;
case 'BILLING.SUBSCRIPTION.CANCELLED':
const cancelledSub = event.resource;
// Revoke access
await revokeAccess(cancelledSub.custom_id);
break;
}
res.json({ received: true });
} catch (error) {
res.status(400).send(`Webhook Error: ${error.message}`);
}
});
module.exports = router;
Step 8: Test Your Integration
Using PayPal Sandbox
- Ensure your environment variables use sandbox credentials
- Set
mode: sandboxin your configuration - Run your application:
uigen serve openapi.yaml - Navigate to your pricing page
- Click a payment button
- Log in with a PayPal sandbox test account
- Complete the payment flow
- Verify your webhook receives the event
Create Test Accounts
- Go to PayPal Sandbox Accounts
- Click Create Account
- Select Personal (for buyer) or Business (for seller)
- Fill in details and create
- Use these accounts for testing
Test Account Credentials
PayPal provides default test accounts:
- Buyer:
sb-buyer@personal.example.com - Seller:
sb-seller@business.example.com
Check your dashboard for the passwords.
Step 9: Go Live
When ready for production:
- Complete PayPal's business verification process
- Switch to Live mode in the PayPal dashboard
- Get your live API credentials
- Update environment variables with live credentials
- Update configuration:
mode: live - Create live webhook endpoint
- Create live subscription plans
- Test with real PayPal accounts
Configuration Reference
Provider Configuration
{
provider: 'paypal',
clientId: string, // PayPal Client ID
clientSecret: string, // PayPal Client Secret
webhookSecret: string, // PayPal Webhook ID
mode: 'sandbox' | 'live',
currency: string, // Default: 'usd'
enabled: boolean // Default: true
}
Supported Currencies
PayPal supports 25+ currencies including:
- USD (US Dollar)
- EUR (Euro)
- GBP (British Pound)
- CAD (Canadian Dollar)
- AUD (Australian Dollar)
- JPY (Japanese Yen)
See PayPal Currency Codes for the complete list.
Supported Payment Types
- ✅ One-time payments - Single purchases
- ✅ Subscriptions - Recurring billing
- ❌ Usage-based - Not supported by PayPal
Troubleshooting
Issue: "Invalid client credentials"
Solution:
- Verify your Client ID and Client Secret are correct
- Ensure you're using the right credentials for your mode (sandbox vs live)
- Check that environment variables are set correctly
Issue: Webhook not receiving events
Solution:
- Verify webhook URL is publicly accessible
- Check that webhook ID is correct
- Ensure selected event types include the ones you need
- Check your server logs for incoming requests
Issue: Subscription plan not found
Solution:
- Verify the plan ID in your config matches the plan ID in PayPal
- Ensure the plan is active in PayPal dashboard
- Check that you're using the right mode (sandbox vs live)
Issue: Payment button redirects to error page
Solution:
- Check browser console for errors
- Verify API credentials are valid
- Ensure the product ID exists in PayPal
- Check that the currency is supported
Best Practices
1. Use Sandbox for Development
Always test with sandbox credentials before going live:
mode: sandbox
clientId: ${PAYPAL_SANDBOX_CLIENT_ID}
2. Implement Proper Error Handling
<PaymentButton
productId="pro-monthly"
onError={(error) => {
console.error('Payment failed:', error);
// Show user-friendly error message
}}
/>
3. Verify Webhooks
Always verify webhook signatures to prevent fraud:
def verify_paypal_webhook(payload, headers, webhook_id):
# Implement PayPal webhook verification
# See: https://developer.paypal.com/docs/api/webhooks/v1/
pass
4. Handle All Subscription States
SUBSCRIPTION_STATES = {
'ACTIVE': 'active',
'SUSPENDED': 'suspended',
'CANCELLED': 'cancelled',
'EXPIRED': 'expired'
}
5. Store Subscription IDs
Always store PayPal subscription IDs in your database for future reference:
class User:
paypal_subscription_id: str
subscription_status: str
subscription_plan: str
Resources
- PayPal Developer Documentation
- PayPal Subscriptions API
- PayPal Webhooks Guide
- PayPal Sandbox Testing
- UIGen Payment Security
Next Steps
- Implement Webhooks - Handle payment events
- Security Best Practices - Secure your integration
- Payment Overview - Learn about other providers