<< All versions
Skill v1.0.1
currentAutomated scan100/100rmyndharis/antigravity-skills/paypal-integration
2 files
──Details
PublishedAugust 16, 2026 at 07:00 PM
Content Hashsha256:0a621d349fabadba...
Git SHA3eff4af253b3
Bump Typepatch
──Files
Files (1 file, 13.5 KB)
SKILL.md13.5 KBactive
SKILL.md · 480 lines · 13.5 KB
version: "1.0.1" name: paypal-integration description: 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.
PayPal Integration
Master PayPal payment integration including Express Checkout, IPN handling, recurring billing, and refund workflows.
Do not use this skill when
- The task is unrelated to paypal integration
- You need a different domain or tool outside this scope
Instructions
- Clarify goals, constraints, and required inputs.
- Apply relevant best practices and validate outcomes.
- Provide actionable steps and verification.
Use this skill when
- Integrating PayPal as a payment option
- Implementing express checkout flows
- Setting up recurring billing with PayPal
- Processing refunds and payment disputes
- Handling PayPal webhooks (IPN)
- Supporting international payments
- Implementing PayPal subscriptions
Core Concepts
1. Payment Products
PayPal Checkout
- One-time payments
- Express checkout experience
- Guest and PayPal account payments
PayPal Subscriptions
- Recurring billing
- Subscription plans
- Automatic renewals
PayPal Payouts
- Send money to multiple recipients
- Marketplace and platform payments
2. Integration Methods
Client-Side (JavaScript SDK)
- Smart Payment Buttons
- Hosted payment flow
- Minimal backend code
Server-Side (REST API)
- Full control over payment flow
- Custom checkout UI
- Advanced features
3. IPN (Instant Payment Notification)
- Webhook-like payment notifications
- Asynchronous payment updates
- Verification required
Quick Start
javascript
// Frontend - PayPal Smart Buttons<div id="paypal-button-container"></div><script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID¤cy=USD"></script><script>paypal.Buttons({createOrder: function(data, actions) {return actions.order.create({purchase_units: [{amount: {value: '25.00'}}]});},onApprove: function(data, actions) {return actions.order.capture().then(function(details) {// Payment successfulconsole.log('Transaction completed by ' + details.payer.name.given_name);// Send to backend for verificationfetch('/api/paypal/capture', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({orderID: data.orderID})});});}}).render('#paypal-button-container');</script>
python
# Backend - Verify and capture orderfrom paypalrestsdk import Paymentimport paypalrestsdkpaypalrestsdk.configure({"mode": "sandbox", # or "live""client_id": "YOUR_CLIENT_ID","client_secret": "YOUR_CLIENT_SECRET"})def capture_paypal_order(order_id):"""Capture a PayPal order."""payment = Payment.find(order_id)if payment.execute({"payer_id": payment.payer.payer_info.payer_id}):# Payment successfulreturn {'status': 'success','transaction_id': payment.id,'amount': payment.transactions[0].amount.total}else:# Payment failedreturn {'status': 'failed','error': payment.error}
Express Checkout Implementation
Server-Side Order Creation
python
import requestsimport jsonclass PayPalClient:def __init__(self, client_id, client_secret, mode='sandbox'):self.client_id = client_idself.client_secret = client_secretself.base_url = 'https://api-m.sandbox.paypal.com' if mode == 'sandbox' else 'https://api-m.paypal.com'self.access_token = self.get_access_token()def get_access_token(self):"""Get OAuth access token."""url = f"{self.base_url}/v1/oauth2/token"headers = {"Accept": "application/json", "Accept-Language": "en_US"}response = requests.post(url,headers=headers,data={"grant_type": "client_credentials"},auth=(self.client_id, self.client_secret))return response.json()['access_token']def create_order(self, amount, currency='USD'):"""Create a PayPal order."""url = f"{self.base_url}/v2/checkout/orders"headers = {"Content-Type": "application/json","Authorization": f"Bearer {self.access_token}"}payload = {"intent": "CAPTURE","purchase_units": [{"amount": {"currency_code": currency,"value": str(amount)}}]}response = requests.post(url, headers=headers, json=payload)return response.json()def capture_order(self, order_id):"""Capture payment for an order."""url = f"{self.base_url}/v2/checkout/orders/{order_id}/capture"headers = {"Content-Type": "application/json","Authorization": f"Bearer {self.access_token}"}response = requests.post(url, headers=headers)return response.json()def get_order_details(self, order_id):"""Get order details."""url = f"{self.base_url}/v2/checkout/orders/{order_id}"headers = {"Authorization": f"Bearer {self.access_token}"}response = requests.get(url, headers=headers)return response.json()
IPN (Instant Payment Notification) Handling
IPN Verification and Processing
python
from flask import Flask, requestimport requestsfrom urllib.parse import parse_qsapp = Flask(__name__)@app.route('/ipn', methods=['POST'])def handle_ipn():"""Handle PayPal IPN notifications."""# Get IPN messageipn_data = request.form.to_dict()# Verify IPN with PayPalif not verify_ipn(ipn_data):return 'IPN verification failed', 400# Process IPN based on transaction typepayment_status = ipn_data.get('payment_status')txn_type = ipn_data.get('txn_type')if payment_status == 'Completed':handle_payment_completed(ipn_data)elif payment_status == 'Refunded':handle_refund(ipn_data)elif payment_status == 'Reversed':handle_chargeback(ipn_data)return 'IPN processed', 200def verify_ipn(ipn_data):"""Verify IPN message authenticity."""# Add 'cmd' parameterverify_data = ipn_data.copy()verify_data['cmd'] = '_notify-validate'# Send back to PayPal for verificationpaypal_url = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr' # or production URLresponse = requests.post(paypal_url, data=verify_data)return response.text == 'VERIFIED'def handle_payment_completed(ipn_data):"""Process completed payment."""txn_id = ipn_data.get('txn_id')payer_email = ipn_data.get('payer_email')mc_gross = ipn_data.get('mc_gross')item_name = ipn_data.get('item_name')# Check if already processed (prevent duplicates)if is_transaction_processed(txn_id):return# Update database# Send confirmation email# Fulfill orderprint(f"Payment completed: {txn_id}, Amount: ${mc_gross}")def handle_refund(ipn_data):"""Handle refund."""parent_txn_id = ipn_data.get('parent_txn_id')mc_gross = ipn_data.get('mc_gross')# Process refund in your systemprint(f"Refund processed: {parent_txn_id}, Amount: ${mc_gross}")def handle_chargeback(ipn_data):"""Handle payment reversal/chargeback."""txn_id = ipn_data.get('txn_id')reason_code = ipn_data.get('reason_code')# Handle chargebackprint(f"Chargeback: {txn_id}, Reason: {reason_code}")
Subscription/Recurring Billing
Create Subscription Plan
python
def create_subscription_plan(name, amount, interval='MONTH'):"""Create a subscription plan."""client = PayPalClient(CLIENT_ID, CLIENT_SECRET)url = f"{client.base_url}/v1/billing/plans"headers = {"Content-Type": "application/json","Authorization": f"Bearer {client.access_token}"}payload = {"product_id": "PRODUCT_ID", # Create product first"name": name,"billing_cycles": [{"frequency": {"interval_unit": interval,"interval_count": 1},"tenure_type": "REGULAR","sequence": 1,"total_cycles": 0, # Infinite"pricing_scheme": {"fixed_price": {"value": str(amount),"currency_code": "USD"}}}],"payment_preferences": {"auto_bill_outstanding": True,"setup_fee": {"value": "0","currency_code": "USD"},"setup_fee_failure_action": "CONTINUE","payment_failure_threshold": 3}}response = requests.post(url, headers=headers, json=payload)return response.json()def create_subscription(plan_id, subscriber_email):"""Create a subscription for a customer."""client = PayPalClient(CLIENT_ID, CLIENT_SECRET)url = f"{client.base_url}/v1/billing/subscriptions"headers = {"Content-Type": "application/json","Authorization": f"Bearer {client.access_token}"}payload = {"plan_id": plan_id,"subscriber": {"email_address": subscriber_email},"application_context": {"return_url": "https://yourdomain.com/subscription/success","cancel_url": "https://yourdomain.com/subscription/cancel"}}response = requests.post(url, headers=headers, json=payload)subscription = response.json()# Get approval URLfor link in subscription.get('links', []):if link['rel'] == 'approve':return {'subscription_id': subscription['id'],'approval_url': link['href']}
Refund Workflows
python
def create_refund(capture_id, amount=None, note=None):"""Create a refund for a captured payment."""client = PayPalClient(CLIENT_ID, CLIENT_SECRET)url = f"{client.base_url}/v2/payments/captures/{capture_id}/refund"headers = {"Content-Type": "application/json","Authorization": f"Bearer {client.access_token}"}payload = {}if amount:payload["amount"] = {"value": str(amount),"currency_code": "USD"}if note:payload["note_to_payer"] = noteresponse = requests.post(url, headers=headers, json=payload)return response.json()def get_refund_details(refund_id):"""Get refund details."""client = PayPalClient(CLIENT_ID, CLIENT_SECRET)url = f"{client.base_url}/v2/payments/refunds/{refund_id}"headers = {"Authorization": f"Bearer {client.access_token}"}response = requests.get(url, headers=headers)return response.json()
Error Handling
python
class PayPalError(Exception):"""Custom PayPal error."""passdef handle_paypal_api_call(api_function):"""Wrapper for PayPal API calls with error handling."""try:result = api_function()return resultexcept requests.exceptions.RequestException as e:# Network errorraise PayPalError(f"Network error: {str(e)}")except Exception as e:# Other errorsraise PayPalError(f"PayPal API error: {str(e)}")# Usagetry:order = handle_paypal_api_call(lambda: client.create_order(25.00))except PayPalError as e:# Handle error appropriatelylog_error(e)
Testing
python
# Use sandbox credentialsSANDBOX_CLIENT_ID = "..."SANDBOX_SECRET = "..."# Test accounts# Create test buyer and seller accounts at developer.paypal.comdef test_payment_flow():"""Test complete payment flow."""client = PayPalClient(SANDBOX_CLIENT_ID, SANDBOX_SECRET, mode='sandbox')# Create orderorder = client.create_order(10.00)assert 'id' in order# Get approval URLapproval_url = next((link['href'] for link in order['links'] if link['rel'] == 'approve'), None)assert approval_url is not None# After approval (manual step with test account)# Capture order# captured = client.capture_order(order['id'])# assert captured['status'] == 'COMPLETED'
Resources
- references/express-checkout.md: Express Checkout implementation guide
- references/ipn-handling.md: IPN verification and processing
- references/refund-workflows.md: Refund handling patterns
- references/billing-agreements.md: Recurring billing setup
- assets/paypal-client.py: Production PayPal client
- assets/ipn-processor.py: IPN webhook processor
- assets/recurring-billing.py: Subscription management
Best Practices
- Always Verify IPN: Never trust IPN without verification
- Idempotent Processing: Handle duplicate IPN notifications
- Error Handling: Implement robust error handling
- Logging: Log all transactions and errors
- Test Thoroughly: Use sandbox extensively
- Webhook Backup: Don't rely solely on client-side callbacks
- Currency Handling: Always specify currency explicitly
Common Pitfalls
- Not Verifying IPN: Accepting IPN without verification
- Duplicate Processing: Not checking for duplicate transactions
- Wrong Environment: Mixing sandbox and production URLs/credentials
- Missing Webhooks: Not handling all payment states
- Hardcoded Values: Not making configurable for different environments