Integrate PayPal payment processing with support for express checkout, subscriptions, and refund management. Use when implementing PayPal payments, processing online transactions, or building e-commerce checkout flows.
Add this skill
npx mdskills install sickn33/paypal-integrationComprehensive payment integration guide with working code examples across multiple use cases
1---2name: paypal-integration3description: Integrate PayPal payment processing with support for express checkout, subscriptions, and refund management. Use when implementing PayPal payments, processing online transactions, or building e-commerce checkout flows.4---56# PayPal Integration78Master PayPal payment integration including Express Checkout, IPN handling, recurring billing, and refund workflows.910## Do not use this skill when1112- The task is unrelated to paypal integration13- You need a different domain or tool outside this scope1415## Instructions1617- Clarify goals, constraints, and required inputs.18- Apply relevant best practices and validate outcomes.19- Provide actionable steps and verification.20- If detailed examples are required, open `resources/implementation-playbook.md`.2122## Use this skill when2324- Integrating PayPal as a payment option25- Implementing express checkout flows26- Setting up recurring billing with PayPal27- Processing refunds and payment disputes28- Handling PayPal webhooks (IPN)29- Supporting international payments30- Implementing PayPal subscriptions3132## Core Concepts3334### 1. Payment Products35**PayPal Checkout**36- One-time payments37- Express checkout experience38- Guest and PayPal account payments3940**PayPal Subscriptions**41- Recurring billing42- Subscription plans43- Automatic renewals4445**PayPal Payouts**46- Send money to multiple recipients47- Marketplace and platform payments4849### 2. Integration Methods50**Client-Side (JavaScript SDK)**51- Smart Payment Buttons52- Hosted payment flow53- Minimal backend code5455**Server-Side (REST API)**56- Full control over payment flow57- Custom checkout UI58- Advanced features5960### 3. IPN (Instant Payment Notification)61- Webhook-like payment notifications62- Asynchronous payment updates63- Verification required6465## Quick Start6667```javascript68// Frontend - PayPal Smart Buttons69<div id="paypal-button-container"></div>7071<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID¤cy=USD"></script>72<script>73 paypal.Buttons({74 createOrder: function(data, actions) {75 return actions.order.create({76 purchase_units: [{77 amount: {78 value: '25.00'79 }80 }]81 });82 },83 onApprove: function(data, actions) {84 return actions.order.capture().then(function(details) {85 // Payment successful86 console.log('Transaction completed by ' + details.payer.name.given_name);8788 // Send to backend for verification89 fetch('/api/paypal/capture', {90 method: 'POST',91 headers: {'Content-Type': 'application/json'},92 body: JSON.stringify({orderID: data.orderID})93 });94 });95 }96 }).render('#paypal-button-container');97</script>98```99100```python101# Backend - Verify and capture order102from paypalrestsdk import Payment103import paypalrestsdk104105paypalrestsdk.configure({106 "mode": "sandbox", # or "live"107 "client_id": "YOUR_CLIENT_ID",108 "client_secret": "YOUR_CLIENT_SECRET"109})110111def capture_paypal_order(order_id):112 """Capture a PayPal order."""113 payment = Payment.find(order_id)114115 if payment.execute({"payer_id": payment.payer.payer_info.payer_id}):116 # Payment successful117 return {118 'status': 'success',119 'transaction_id': payment.id,120 'amount': payment.transactions[0].amount.total121 }122 else:123 # Payment failed124 return {125 'status': 'failed',126 'error': payment.error127 }128```129130## Express Checkout Implementation131132### Server-Side Order Creation133```python134import requests135import json136137class PayPalClient:138 def __init__(self, client_id, client_secret, mode='sandbox'):139 self.client_id = client_id140 self.client_secret = client_secret141 self.base_url = 'https://api-m.sandbox.paypal.com' if mode == 'sandbox' else 'https://api-m.paypal.com'142 self.access_token = self.get_access_token()143144 def get_access_token(self):145 """Get OAuth access token."""146 url = f"{self.base_url}/v1/oauth2/token"147 headers = {"Accept": "application/json", "Accept-Language": "en_US"}148149 response = requests.post(150 url,151 headers=headers,152 data={"grant_type": "client_credentials"},153 auth=(self.client_id, self.client_secret)154 )155156 return response.json()['access_token']157158 def create_order(self, amount, currency='USD'):159 """Create a PayPal order."""160 url = f"{self.base_url}/v2/checkout/orders"161 headers = {162 "Content-Type": "application/json",163 "Authorization": f"Bearer {self.access_token}"164 }165166 payload = {167 "intent": "CAPTURE",168 "purchase_units": [{169 "amount": {170 "currency_code": currency,171 "value": str(amount)172 }173 }]174 }175176 response = requests.post(url, headers=headers, json=payload)177 return response.json()178179 def capture_order(self, order_id):180 """Capture payment for an order."""181 url = f"{self.base_url}/v2/checkout/orders/{order_id}/capture"182 headers = {183 "Content-Type": "application/json",184 "Authorization": f"Bearer {self.access_token}"185 }186187 response = requests.post(url, headers=headers)188 return response.json()189190 def get_order_details(self, order_id):191 """Get order details."""192 url = f"{self.base_url}/v2/checkout/orders/{order_id}"193 headers = {194 "Authorization": f"Bearer {self.access_token}"195 }196197 response = requests.get(url, headers=headers)198 return response.json()199```200201## IPN (Instant Payment Notification) Handling202203### IPN Verification and Processing204```python205from flask import Flask, request206import requests207from urllib.parse import parse_qs208209app = Flask(__name__)210211@app.route('/ipn', methods=['POST'])212def handle_ipn():213 """Handle PayPal IPN notifications."""214 # Get IPN message215 ipn_data = request.form.to_dict()216217 # Verify IPN with PayPal218 if not verify_ipn(ipn_data):219 return 'IPN verification failed', 400220221 # Process IPN based on transaction type222 payment_status = ipn_data.get('payment_status')223 txn_type = ipn_data.get('txn_type')224225 if payment_status == 'Completed':226 handle_payment_completed(ipn_data)227 elif payment_status == 'Refunded':228 handle_refund(ipn_data)229 elif payment_status == 'Reversed':230 handle_chargeback(ipn_data)231232 return 'IPN processed', 200233234def verify_ipn(ipn_data):235 """Verify IPN message authenticity."""236 # Add 'cmd' parameter237 verify_data = ipn_data.copy()238 verify_data['cmd'] = '_notify-validate'239240 # Send back to PayPal for verification241 paypal_url = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr' # or production URL242243 response = requests.post(paypal_url, data=verify_data)244245 return response.text == 'VERIFIED'246247def handle_payment_completed(ipn_data):248 """Process completed payment."""249 txn_id = ipn_data.get('txn_id')250 payer_email = ipn_data.get('payer_email')251 mc_gross = ipn_data.get('mc_gross')252 item_name = ipn_data.get('item_name')253254 # Check if already processed (prevent duplicates)255 if is_transaction_processed(txn_id):256 return257258 # Update database259 # Send confirmation email260 # Fulfill order261 print(f"Payment completed: {txn_id}, Amount: ${mc_gross}")262263def handle_refund(ipn_data):264 """Handle refund."""265 parent_txn_id = ipn_data.get('parent_txn_id')266 mc_gross = ipn_data.get('mc_gross')267268 # Process refund in your system269 print(f"Refund processed: {parent_txn_id}, Amount: ${mc_gross}")270271def handle_chargeback(ipn_data):272 """Handle payment reversal/chargeback."""273 txn_id = ipn_data.get('txn_id')274 reason_code = ipn_data.get('reason_code')275276 # Handle chargeback277 print(f"Chargeback: {txn_id}, Reason: {reason_code}")278```279280## Subscription/Recurring Billing281282### Create Subscription Plan283```python284def create_subscription_plan(name, amount, interval='MONTH'):285 """Create a subscription plan."""286 client = PayPalClient(CLIENT_ID, CLIENT_SECRET)287288 url = f"{client.base_url}/v1/billing/plans"289 headers = {290 "Content-Type": "application/json",291 "Authorization": f"Bearer {client.access_token}"292 }293294 payload = {295 "product_id": "PRODUCT_ID", # Create product first296 "name": name,297 "billing_cycles": [{298 "frequency": {299 "interval_unit": interval,300 "interval_count": 1301 },302 "tenure_type": "REGULAR",303 "sequence": 1,304 "total_cycles": 0, # Infinite305 "pricing_scheme": {306 "fixed_price": {307 "value": str(amount),308 "currency_code": "USD"309 }310 }311 }],312 "payment_preferences": {313 "auto_bill_outstanding": True,314 "setup_fee": {315 "value": "0",316 "currency_code": "USD"317 },318 "setup_fee_failure_action": "CONTINUE",319 "payment_failure_threshold": 3320 }321 }322323 response = requests.post(url, headers=headers, json=payload)324 return response.json()325326def create_subscription(plan_id, subscriber_email):327 """Create a subscription for a customer."""328 client = PayPalClient(CLIENT_ID, CLIENT_SECRET)329330 url = f"{client.base_url}/v1/billing/subscriptions"331 headers = {332 "Content-Type": "application/json",333 "Authorization": f"Bearer {client.access_token}"334 }335336 payload = {337 "plan_id": plan_id,338 "subscriber": {339 "email_address": subscriber_email340 },341 "application_context": {342 "return_url": "https://yourdomain.com/subscription/success",343 "cancel_url": "https://yourdomain.com/subscription/cancel"344 }345 }346347 response = requests.post(url, headers=headers, json=payload)348 subscription = response.json()349350 # Get approval URL351 for link in subscription.get('links', []):352 if link['rel'] == 'approve':353 return {354 'subscription_id': subscription['id'],355 'approval_url': link['href']356 }357```358359## Refund Workflows360361```python362def create_refund(capture_id, amount=None, note=None):363 """Create a refund for a captured payment."""364 client = PayPalClient(CLIENT_ID, CLIENT_SECRET)365366 url = f"{client.base_url}/v2/payments/captures/{capture_id}/refund"367 headers = {368 "Content-Type": "application/json",369 "Authorization": f"Bearer {client.access_token}"370 }371372 payload = {}373 if amount:374 payload["amount"] = {375 "value": str(amount),376 "currency_code": "USD"377 }378379 if note:380 payload["note_to_payer"] = note381382 response = requests.post(url, headers=headers, json=payload)383 return response.json()384385def get_refund_details(refund_id):386 """Get refund details."""387 client = PayPalClient(CLIENT_ID, CLIENT_SECRET)388389 url = f"{client.base_url}/v2/payments/refunds/{refund_id}"390 headers = {391 "Authorization": f"Bearer {client.access_token}"392 }393394 response = requests.get(url, headers=headers)395 return response.json()396```397398## Error Handling399400```python401class PayPalError(Exception):402 """Custom PayPal error."""403 pass404405def handle_paypal_api_call(api_function):406 """Wrapper for PayPal API calls with error handling."""407 try:408 result = api_function()409 return result410 except requests.exceptions.RequestException as e:411 # Network error412 raise PayPalError(f"Network error: {str(e)}")413 except Exception as e:414 # Other errors415 raise PayPalError(f"PayPal API error: {str(e)}")416417# Usage418try:419 order = handle_paypal_api_call(lambda: client.create_order(25.00))420except PayPalError as e:421 # Handle error appropriately422 log_error(e)423```424425## Testing426427```python428# Use sandbox credentials429SANDBOX_CLIENT_ID = "..."430SANDBOX_SECRET = "..."431432# Test accounts433# Create test buyer and seller accounts at developer.paypal.com434435def test_payment_flow():436 """Test complete payment flow."""437 client = PayPalClient(SANDBOX_CLIENT_ID, SANDBOX_SECRET, mode='sandbox')438439 # Create order440 order = client.create_order(10.00)441 assert 'id' in order442443 # Get approval URL444 approval_url = next((link['href'] for link in order['links'] if link['rel'] == 'approve'), None)445 assert approval_url is not None446447 # After approval (manual step with test account)448 # Capture order449 # captured = client.capture_order(order['id'])450 # assert captured['status'] == 'COMPLETED'451```452453## Resources454455- **references/express-checkout.md**: Express Checkout implementation guide456- **references/ipn-handling.md**: IPN verification and processing457- **references/refund-workflows.md**: Refund handling patterns458- **references/billing-agreements.md**: Recurring billing setup459- **assets/paypal-client.py**: Production PayPal client460- **assets/ipn-processor.py**: IPN webhook processor461- **assets/recurring-billing.py**: Subscription management462463## Best Practices4644651. **Always Verify IPN**: Never trust IPN without verification4662. **Idempotent Processing**: Handle duplicate IPN notifications4673. **Error Handling**: Implement robust error handling4684. **Logging**: Log all transactions and errors4695. **Test Thoroughly**: Use sandbox extensively4706. **Webhook Backup**: Don't rely solely on client-side callbacks4717. **Currency Handling**: Always specify currency explicitly472473## Common Pitfalls474475- **Not Verifying IPN**: Accepting IPN without verification476- **Duplicate Processing**: Not checking for duplicate transactions477- **Wrong Environment**: Mixing sandbox and production URLs/credentials478- **Missing Webhooks**: Not handling all payment states479- **Hardcoded Values**: Not making configurable for different environments480
Full transparency — inspect the skill content before installing.