
agents24 倉庫 paypal-integration Skill 實戰指南Express Checkout、IPN、訂閱與退款全流程實現【免費下載鏈接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity項目地址: https://gitcode.com/GitHub_Trending/agents24/agents本指南以agents24/agents倉庫中 paypal-integration Skill 及其詳細模式文檔為主體系統講解 PayPal 支付集成的六大核心場景OAuth 鑒權與 Express Checkout 服務端訂單、IPN 異步通知驗證與處理、訂閱計費Billing Plans/Subscriptions、退款工作流、統一錯誤處理以及沙箱測試。讀完本文你將掌握一套可直接復制運行的服務端 PayPal 集成代碼骨架并理解 webhook 安全、冪等處理與 sandbox/live 環境切換等生產級細節。一、Skill 定位何時使用 paypal-integration該 Skill 位于倉庫 plugins/payment-processing 插件目錄下屬于 Payment Processing支付處理插件家族的四個 Skill 之一其余為 stripe-integration、pci-compliance、billing-automation。依據 SKILL.md 中的 frontmatter 聲明該 Skill 的激活場景為將 PayPal 作為支付選項接入實現 Express Checkout 快速結賬流程用 PayPal 搭建周期性訂閱計費recurring billing處理退款與支付爭議disputes處理 PayPal webhook即 IPN 異步通知支持國際支付實現 PayPal Subscriptions 訂閱產品在倉庫的文檔體系里Skill 采用「漸進式披露」Progressive Disclosure三層架構Frontmatter 元數據名稱與激活條件始終加載核心指導在 SKILL.md 激活時加載而references/details.md屬于按需加載的第三層資源存放完整的模式與可運行示例即本文主體內容的來源。1.1 三種支付產品產品用途PayPal Checkout一次性支付、Express Checkout 體驗、支持訪客與 PayPal 賬戶支付PayPal Subscriptions周期性計費、訂閱計劃、自動續費PayPal Payouts向多個收款人批量打款適用于市場與平臺支付1.2 兩種集成方式客戶端集成JavaScript SDK使用 Smart Payment Buttons 托管支付流程后端代碼最少服務端集成REST API對支付流程擁有完全控制權可定制結賬 UI支持高級功能。details.md中的示例全部采用服務端 REST API路線通過requests直接調用 PayPal 官方 HTTP 接口不依賴第三方 SDK 封裝便于理解底層請求結構。二、Express Checkout 服務端實現從 OAuth 到訂單捕獲2.1 PayPalClient 基類環境切換與 OAuth 訪問令牌details.md給出的核心類是PayPalClient它同時承擔環境路由與令牌管理兩個職責import requests import json class PayPalClient: def __init__(self, client_id, client_secret, modesandbox): 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, headersheaders, data{grant_type: client_credentials}, auth(self.client_id, self.client_secret) ) return response.json()[access_token]關鍵點拆解mode參數sandbox路由到https://api-m.sandbox.paypal.com其余值路由到生產環境https://api-m.paypal.com。這是隔離測試與線上流量的核心開關OAuth2 客戶端憑證模式向/v1/oauth2/token發起POST攜帶grant_typeclient_credentials并以(client_id, client_secret)作為 HTTP Basic Authrequests.post的auth參數會自動編碼。返回 JSON 中的access_token即為后續所有請求的Bearer憑證倉庫中 payment-integration 智能體 強調「測試憑證必須不能在線上生效」因此在多環境部署時應把mode、CLIENT_ID、CLIENT_SECRET全部納入環境變量管理避免測試卡在線上站點被接受而觸發 PCI 違規。2.2 創建訂單v2/checkout/ordersdef create_order(self, amount, currencyUSD): Create a PayPal order. url f{self.base_url}/v2/checkout/orders headers { Content-Type: application/json, Authorization: fBearer {self.access_token} } payload { intent: CAPTURE, purchase_units: [{ amount: { currency_code: currency, value: str(amount) } }] } response requests.post(url, headersheaders, jsonpayload) return response.json()要點說明訂單創建接口是 PayPalOrders v2API請求體至少包含intentCAPTURE表示創建后直接捕獲與purchase_units采購單元含金額金額value必須轉為字符串str(amount)這是 PayPal API 對金額字段的類型約束避免浮點精度問題創建成功后返回的 JSON 中links數組內rel approve的鏈接即為用戶批準支付頁見下方訂閱部分對同一模式的復用這也被 SKILL.md 的測試示例所驗證next((link[href] for link in order[links] if link[rel] approve), None)。2.3 捕獲訂單與查詢訂單詳情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: fBearer {self.access_token} } response requests.post(url, headersheaders) 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: fBearer {self.access_token} } response requests.get(url, headersheaders) return response.json()生產建議捕獲動作必須在服務端完成。客戶端Smart Buttons 的onApprove回調只負責把orderID回傳后端由后端調用capture_order并向 PayPal 再次確認訂單狀態。這正對應 payment-integration.md 中「服務端驗證從提供商 API 重新拉取支付狀態永遠不要只信任 webhook 負載或客戶端響應」的安全要求。2.4 客戶端入口Smart Buttons 快速開始完整的客戶端-服務端鏈路可參考 SKILL.md 的 Quick Start前端通過 PayPal JS SDK 渲染按鈕createOrder中聲明purchase_unitsonApprove中調用actions.order.capture()成功后把orderID發往后端/api/paypal/capture進行服務端捕獲與校驗// Frontend - PayPal Smart Buttons div idpaypal-button-container/div script srchttps://www.paypal.com/sdk/js?client-idYOUR_CLIENT_IDcurrencyUSD/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三、IPNInstant Payment Notification處理驗證與業務分發IPN 是 PayPal 的異步通知機制支付狀態變化時PayPal 向商戶配置的端點推送表單數據。details.md給出一個完整的 Flask 端點示例其核心分為「回驗」與「分發」兩段。3.1 端點與消息分發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分發邏輯依據payment_status字段路由到三個處理器Completed支付完成、Refunded退款、Reversed退單/撤銷。注意txn_type字段同樣被讀取可用于更細粒度的事件識別。3.2 回驗機制VERIFIED / INVALIDdef 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, dataverify_data) return response.text VERIFIEDIPN 安全模型的核心是回環驗證商戶把收到的完整 IPN 數據原樣加cmd_notify-validate后回傳給 PayPal 的 IPN 端點PayPal 返回VERIFIED才視為可信。生產環境應將 URL 替換為https://ipnpb.paypal.com/cgi-bin/webscr。這一點與倉庫智能體 payment-integration.md 強調的 webhook 安全要求完全一致簽名驗證必須使用官方機制驗證通知真實性絕不處理未驗證的 webhook原始 Body 保留驗證前不得修改請求體JSON 中間件會破壞校驗冪等處理把事件 ID 存入數據庫處理前檢查去重——webhook 失敗會重試提供商不保證單次投遞快速響應應在執行數據庫寫入等昂貴操作之前返回2xx文檔中的示例先返回200處理器內部完成業務超時觸發重試會導致重復處理。3.3 三個業務處理器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(fPayment 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(fRefund 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(fChargeback: {txn_id}, Reason: {reason_code})字段語義說明txn_id本次交易 ID退款場景下是退款交易 IDparent_txn_id退款對應的原始交易 ID退款處理應以它為鍵關聯原訂單mc_gross交易總額含費用reason_code退單原因碼用于風控分析。handle_payment_completed中的is_transaction_processed(txn_id)冪等檢查不可省略——這正是倉庫智能體所列「Out-of-order webhooks breaking Lambda functions (no idempotency) → production failures」這一真實故障案例的防御措施。四、訂閱與周期性計費Billing Plans 與 Subscriptions4.1 創建訂閱計劃v1/billing/plansdef create_subscription_plan(name, amount, intervalMONTH): Create a subscription plan. client PayPalClient(CLIENT_ID, CLIENT_SECRET) url f{client.base_url}/v1/billing/plans headers { Content-Type: application/json, Authorization: fBearer {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, headersheaders, jsonpayload) return response.json()參數解析參數取值/默認含義product_id需預先創建PayPal 要求先創建 Product產品再在計劃中引用其 IDfrequency.interval_unitMONTH/YEAR/WEEK/DAY計費周期單位frequency.interval_count整數每個計費周期的單位數量tenure_typeREGULAR常規/TRIAL試用計費期類型total_cycles0表示無限期該 tenure 的總周期數auto_bill_outstandingTrue是否自動補收欠款setup_fee金額對象一次性設置費0表示免設置費setup_fee_failure_actionCONTINUE設置費收取失敗后的動作payment_failure_threshold3支付連續失敗多少次后暫停訂閱與下方 dunning 思路呼應4.2 為客戶創建訂閱并獲取批準鏈接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: fBearer {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, headersheaders, jsonpayload) 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] }模式要點訂閱創建后同樣返回一個links數組其中rel approve的href是訂閱批準頁。后端應將用戶重定向到該 URL用戶批準后PayPal 回調return_url攜帶subscription_id等參數此時訂閱才正式激活。return_url與cancel_url需要替換為業務方真實域名。4.3 訂閱生命周期與自動化計費訂閱本身不產生代碼但它與倉庫中另一 Skill billing-automation 的訂閱生命周期管理緊密配合。billing-automation 定義的典型狀態機為trial → active → past_due → canceled → paused → resumed其BillingEngine.process_billing_cycle展示了完整的周期處理流程判斷是否到賬期 → 生成發票 → 嘗試扣款 → 成功則標記已付并推進賬期失敗則標記past_due并進入 dunning催繳流程。而 PayPal 側的payment_failure_threshold: 3與auto_bill_outstanding: True正是把「自動重試 失敗上限」下沉到支付服務商側的配置化實現二者互為補充。五、退款工作流部分退款與全額退款def create_refund(capture_id, amountNone, noteNone): 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: fBearer {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, headersheaders, jsonpayload) 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: fBearer {client.access_token} } response requests.get(url, headersheaders) return response.json()退款以capture_id捕獲交易 ID為操作對象調用/v2/payments/captures/{capture_id}/refundamount與note_to_payer均為可選參數不傳amount即全額退款傳amount即部分退款若只做全款退款payload可以保持為空對象{}PayPal 默認退還全部捕獲金額退款完成后可用get_refund_details按refund_id查詢退款明細用于對賬與審計。退款通常由兩類場景觸發商戶主動發起本節的create_refund路徑以及支付服務商主動回調上一節 IPN 的Refunded狀態。兩者都需要在業務系統中記錄refund_id與parent_txn_id的關聯關系保證冪等、防止重復退款。六、統一錯誤處理PayPalError 封裝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(fNetwork error: {str(e)}) except Exception as e: # Other errors raise PayPalError(fPayPal 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)該封裝的價值在于錯誤歸一化無論底層是網絡異常requests.exceptions.RequestException如超時、連接失敗、DNS 解析錯誤還是 PayPal 返回的業務錯誤統一包裝為自定義PayPalError業務層只需捕獲一種異常類型即可統一處理記錄日志、重試、通知用戶。這與倉庫智能體 payment-integration.md 中「Payment integration code with error handling」「實現所有支付操作的冪等性」「處理所有邊界情況支付失敗、爭議、退款」的輸出要求一致。七、沙箱測試與上線遷移SKILL.md 的 Testing 章節給出了完整的沙箱驗證路徑# 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, modesandbox) # 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測試與上線要點沙箱憑證在 developer.paypal.com 創建沙箱應用獲取SANDBOX_CLIENT_ID/SANDBOX_SECRET同時創建測試買家和賣家賬戶全鏈路驗證訂單創建assert id in order→ 批準鏈接存在assert approval_url is not None→ 用測試買家賬戶手動完成批準 → 服務端捕獲captured[status] COMPLETED環境隔離PayPalClient的mode參數即切換開關生產環境必須使用modelive、生產 API 域https://api-m.paypal.com與真實憑證。參照 payment-integration.md 的要求測試憑證必須確保在線上站點失效防止測試卡被線上接受。八、生產級 Checklist 匯總結合details.md的模式與倉庫配套文檔落地 PayPal 集成時建議逐項核對OAuth 令牌管理access_token有有效期長生命周期應用中應按官方建議緩存并在過期前刷新當前示例為每次實例化時獲取生產應升級為帶過期時間的緩存金額處理value一律str()化金額計算使用定點數避免浮點誤差服務端捕獲客戶端只回傳orderID捕獲與狀態校驗必須發生在服務端IPN 回驗所有通知先回傳cmd_notify-validate驗證VERIFIED才處理生產端點替換為ipnpb.paypal.com冪等去重以txn_id/parent_txn_id為鍵落庫去重webhook 重試與重復投遞不會造成重復發貨/重復退款訂閱失敗策略payment_failure_threshold與服務端 dunning 流程聯動避免長期欠費錯誤歸一化所有 PayPal 調用經handle_paypal_api_call包裝業務層只捕獲PayPalError環境隔離sandbox/live 的憑證、域名、回調地址全部環境變量化測試與生產嚴格分離。參考與延伸閱讀Skill 入口與激活條件plugins/payment-processing/skills/paypal-integration/SKILL.md本文主體詳細模式與完整代碼plugins/payment-processing/skills/paypal-integration/references/details.md支付集成智能體安全要求與常見故障plugins/payment-processing/agents/payment-integration.md相關 SkillStripe 集成 stripe-integration、PCI DSS 合規 pci-compliance、訂閱生命周期與催繳 billing-automationSkill 體系與漸進式披露說明docs/agent-skills.md插件安裝方式/plugin install payment-processing詳見 docs/plugins.md【免費下載鏈接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity項目地址: https://gitcode.com/GitHub_Trending/agents24/agents創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考