Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    amurata

    paypal-integration

    amurata/paypal-integration
    Business
    5
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    エクスプレスチェックアウト、サブスクリプション、返金管理をサポートするPayPal決済処理を統合します。PayPal決済の実装、オンライン取引の処理、Eコマースチェックアウトフローの構築時に使用します。

    SKILL.md

    English | 日本語

    PayPal統合

    エクスプレスチェックアウト、IPN処理、定期請求、返金ワークフローを含むPayPal決済統合をマスターします。

    このスキルを使用する場面

    • 支払いオプションとしてPayPalを統合
    • エクスプレスチェックアウトフローの実装
    • PayPalでの定期請求の設定
    • 返金および支払い紛争の処理
    • PayPal Webhook(IPN)の処理
    • 国際決済のサポート
    • PayPalサブスクリプションの実装

    コアコンセプト

    1. 決済プロダクト

    PayPalチェックアウト

    • 一回限りの支払い
    • エクスプレスチェックアウト体験
    • ゲストおよびPayPalアカウント決済

    PayPalサブスクリプション

    • 定期請求
    • サブスクリプションプラン
    • 自動更新

    PayPalペイアウト

    • 複数の受取人への送金
    • マーケットプレイスおよびプラットフォーム決済

    2. 統合方法

    クライアント側(JavaScript SDK)

    • スマート決済ボタン
    • ホスト型決済フロー
    • 最小限のバックエンドコード

    サーバー側(REST API)

    • 決済フローの完全な制御
    • カスタムチェックアウトUI
    • 高度な機能

    3. IPN(即時支払い通知)

    • Webhookのような決済通知
    • 非同期決済更新
    • 検証が必要

    クイックスタート

    // Frontend - PayPal Smart Buttons
    <div id="paypal-button-container"></div>
    
    <script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&currency=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 successful
            console.log('Transaction completed by ' + details.payer.name.given_name);
    
            // Send to backend for verification
            fetch('/api/paypal/capture', {
              method: 'POST',
              headers: {'Content-Type': 'application/json'},
              body: JSON.stringify({orderID: data.orderID})
            });
          });
        }
      }).render('#paypal-button-container');
    </script>
    
    # Backend - Verify and capture order
    from paypalrestsdk import Payment
    import paypalrestsdk
    
    paypalrestsdk.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 successful
            return {
                'status': 'success',
                'transaction_id': payment.id,
                'amount': payment.transactions[0].amount.total
            }
        else:
            # Payment failed
            return {
                'status': 'failed',
                'error': payment.error
            }
    

    エクスプレスチェックアウト実装

    サーバー側注文作成

    import requests
    import json
    
    class PayPalClient:
        def __init__(self, client_id, client_secret, mode='sandbox'):
            self.client_id = client_id
            self.client_secret = client_secret
            self.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(即時支払い通知)処理

    IPN検証と処理

    from flask import Flask, request
    import requests
    from urllib.parse import parse_qs
    
    app = Flask(__name__)
    
    @app.route('/ipn', methods=['POST'])
    def handle_ipn():
        """Handle PayPal IPN notifications."""
        # Get IPN message
        ipn_data = request.form.to_dict()
    
        # Verify IPN with PayPal
        if not verify_ipn(ipn_data):
            return 'IPN verification failed', 400
    
        # Process IPN based on transaction type
        payment_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', 200
    
    def verify_ipn(ipn_data):
        """Verify IPN message authenticity."""
        # Add 'cmd' parameter
        verify_data = ipn_data.copy()
        verify_data['cmd'] = '_notify-validate'
    
        # Send back to PayPal for verification
        paypal_url = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr'  # or production URL
    
        response = 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 order
        print(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 system
        print(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 chargeback
        print(f"Chargeback: {txn_id}, Reason: {reason_code}")
    

    サブスクリプション/定期請求

    サブスクリプションプラン作成

    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 URL
        for link in subscription.get('links', []):
            if link['rel'] == 'approve':
                return {
                    'subscription_id': subscription['id'],
                    'approval_url': link['href']
                }
    

    返金ワークフロー

    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"] = note
    
        response = 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()
    

    エラー処理

    class PayPalError(Exception):
        """Custom PayPal error."""
        pass
    
    def handle_paypal_api_call(api_function):
        """Wrapper for PayPal API calls with error handling."""
        try:
            result = api_function()
            return result
        except requests.exceptions.RequestException as e:
            # Network error
            raise PayPalError(f"Network error: {str(e)}")
        except Exception as e:
            # Other errors
            raise PayPalError(f"PayPal API error: {str(e)}")
    
    # Usage
    try:
        order = handle_paypal_api_call(lambda: client.create_order(25.00))
    except PayPalError as e:
        # Handle error appropriately
        log_error(e)
    

    テスト

    # Use sandbox credentials
    SANDBOX_CLIENT_ID = "..."
    SANDBOX_SECRET = "..."
    
    # Test accounts
    # Create test buyer and seller accounts at developer.paypal.com
    
    def test_payment_flow():
        """Test complete payment flow."""
        client = PayPalClient(SANDBOX_CLIENT_ID, SANDBOX_SECRET, mode='sandbox')
    
        # Create order
        order = client.create_order(10.00)
        assert 'id' in order
    
        # Get approval URL
        approval_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'
    

    リソース

    • references/express-checkout.md: エクスプレスチェックアウト実装ガイド
    • references/ipn-handling.md: IPN検証と処理
    • references/refund-workflows.md: 返金処理パターン
    • references/billing-agreements.md: 定期請求設定
    • assets/paypal-client.py: 本番環境対応PayPalクライアント
    • assets/ipn-processor.py: IPN Webhookプロセッサー
    • assets/recurring-billing.py: サブスクリプション管理

    ベストプラクティス

    1. 常にIPNを検証: 検証なしでIPNを信頼しない
    2. 冪等処理: 重複したIPN通知を処理
    3. エラー処理: 堅牢なエラー処理を実装
    4. ログ記録: すべての取引とエラーをログ記録
    5. 徹底的にテスト: サンドボックスを広範囲に使用
    6. Webhookバックアップ: クライアント側のコールバックのみに依存しない
    7. 通貨処理: 常に通貨を明示的に指定

    よくある落とし穴

    • IPNを検証しない: 検証なしでIPNを受け入れる
    • 重複処理: 重複した取引をチェックしない
    • 間違った環境: サンドボックスと本番環境のURL/認証情報を混在
    • Webhookの欠落: すべての支払い状態を処理しない
    • ハードコードされた値: 異なる環境に対して設定可能にしない
    Recommended Servers
    Correkt Commerce
    Correkt Commerce
    MCP Hive
    MCP Hive
    AurelianFlo
    AurelianFlo
    Repository
    amurata/cc-tools
    Files