Overview
The PayPal API provides two endpoints for processing payments:- Create Order - Initialize a PayPal order
- Capture Order - Capture payment after customer approval
PayPal payments require a two-step process: first create an order, then capture it after the customer approves the payment through PayPal’s interface.
POST /api/paypal/create-order
Create a new PayPal order for processing subscription payments. This endpoint validates the plan and pricing, then returns a PayPal order ID for customer approval.Rate Limiting
- Limit: 10 requests per IP
- Window: 15 minutes
- Purpose: Prevent order creation spam
Security Features
- Server-side price validation (prevents tampering)
- Plan and duration validation
- Input sanitization
- PayPal OAuth authentication
Request Body
Plan identifier (max 50 characters)Must be one of:
plan-1 (Basic), plan-2 (Standard), plan-3 (Premium)Example: "plan-2"Subscription duration in months (1-12 range)Must be one of:
1, 2, 3, 6, or 12Example: 6Payment amount in USD (1-10000 range)Must exactly match the plan’s price for the selected duration. The server validates this to prevent price manipulation (tolerance: 0.01).Example:
70Response
PayPal order IDUse this ID to:
- Redirect customer to PayPal for approval
- Capture the payment after approval
"7XX12345XX123456X"Example Request
Example Response
200 OK
Error Responses
POST /api/paypal/capture-order
Capture a PayPal order after the customer has approved the payment. This finalizes the transaction and charges the customer.Rate Limiting
- No rate limit - Captures are expected to follow creations
Request Body
PayPal order ID to captureThis is the ID returned from
/api/paypal/create-orderExample: "7XX12345XX123456X"Response
Captured order ID (same as input)
Order status after captureTypically:
"COMPLETED"Example Request
Example Response
200 OK
Error Responses
PayPal Order Structure
The order created by/api/paypal/create-order has the following structure:
Always set to
"CAPTURE" for immediate payment captureArray containing payment details
amount.currency_code: Always"USD"amount.value: Formatted price (e.g.,"70.00")description: Human-readable description with plan and duration
Authentication
Both endpoints use PayPal OAuth for authentication:Implementation Details
Create Order: Implemented in
/src/app/api/paypal/create-order/route.ts:29Capture Order: Implemented in /src/app/api/paypal/capture-order/route.ts:25Both endpoints use:- HTTP Client:
axios - Base URL:
PAYPAL_BASE_URL(sandbox or production) - Authentication: OAuth 2.0 with client credentials
- Security: Rate limiting (create only), input sanitization, price validation
Complete Payment Flow
- Client: Call
/api/paypal/create-orderwith plan details - Server: Validate plan, months, and amount
- Server: Authenticate with PayPal OAuth
- Server: Create PayPal order
- Server: Return order ID
- Client: Redirect user to PayPal approval URL
- Customer: Approve payment on PayPal
- PayPal: Redirect back to your site with order ID
- Client: Call
/api/paypal/capture-orderwith order ID - Server: Capture the payment
- Server: Return captured order status
- Client: Call
/api/orderswith captured order ID aspaymentReceiptId - Server: Create subscription order
- Client: Show success confirmation
Example: Full Integration
Testing
Test Scenarios
| Scenario | Expected Result |
|---|---|
| Valid plan and price | Returns order ID |
| Invalid plan ID | 400 error: “Plan inválido.” |
| Wrong amount | 400 error: “Monto inválido.” |
| Invalid duration | 400 error: “Duración inválida.” |
| Capture unapproved order | 500 error with PayPal details |
| Capture twice | 500 error: already captured |
Environment Variables
Required environment variables:PayPal Response Logging
The create-order endpoint logs PayPal responses:See Also
- Orders API - Create orders after payment capture
- Stripe API - Alternative payment method
- API Overview - General API information
- PayPal Orders API - Official PayPal documentation
