如何通过PayPal REST API实现单次购买与定期付款的合并交易
嘿,我之前刚好帮人实现过一模一样的场景!PayPal REST API确实没有专门的“混合单次+订阅交易”的直接示例,但其实可以通过创建包含多种购买单元的Order来实现——Order支持同时包含一次性付款项目和订阅计划,让用户一次完成授权付款。
下面是具体的实现步骤和PHP代码示例(基于PayPal PHP SDK v2):
核心思路
PayPal的Orders API允许在同一个订单的purchase_units数组中添加不同类型的购买项:
- 用常规金额单元处理一次性购买(付款后直接捕获金额)
- 用关联了
plan_id的单元处理订阅(用户授权后自动创建订阅并扣取首次费用)
步骤1:初始化PayPal客户端
首先确保你已经通过Composer安装了PayPal PHP SDK(执行composer require paypal/paypal-checkout-sdk),然后初始化客户端:
require __DIR__ . '/vendor/autoload.php'; // 沙箱环境,生产环境替换为ProductionEnvironment $environment = new \PayPalCheckoutSdk\Core\SandboxEnvironment( '你的客户端ID', '你的客户端密钥' ); $client = new \PayPalCheckoutSdk\Core\PayPalHttpClient($environment);
步骤2:创建包含混合购买项的订单
构建订单请求,同时加入一次性购买和订阅单元:
use PayPalCheckoutSdk\Orders\OrdersCreateRequest; $createOrderRequest = new OrdersCreateRequest(); $createOrderRequest->prefer('return=representation'); $createOrderRequest->body = [ "intent" => "CAPTURE", "purchase_units" => [ // 1. 一次性购买产品 [ "reference_id" => "single_product_001", // 自定义标识,后续回调区分用 "amount" => [ "currency_code" => "USD", "value" => "29.99" // 一次性产品价格 ], "description" => "年度高级版电子书" ], // 2. 订阅产品(需预先在PayPal后台创建订阅计划) [ "reference_id" => "subscription_monthly_001", "amount" => [ "currency_code" => "USD", "value" => "9.99" // 订阅每月费用 ], "description" => "月度会员服务", "plan_id" => "P-XXXXXXXXX" // 替换为你创建的订阅计划ID ] ], "application_context" => [ "return_url" => "https://你的域名.com/paypal-success", // 付款成功跳转地址 "cancel_url" => "https://你的域名.com/paypal-cancel" // 取消跳转地址 ] ]; try { $response = $client->execute($createOrderRequest); // 获取PayPal的授权链接,引导用户跳转付款 $approveLink = null; foreach ($response->result->links as $link) { if ($link->rel === 'approve') { $approveLink = $link->href; break; } } // 保存订单ID到数据库,后续回调验证用 $orderId = $response->result->id; // 跳转到PayPal付款页面 header("Location: {$approveLink}"); exit; } catch (\Exception $e) { // 处理创建订单失败的情况 error_log("创建PayPal订单失败: " . $e->getMessage()); echo "付款创建失败,请稍后重试"; }
步骤3:处理付款成功后的回调
用户在PayPal完成付款后,会跳转到你的return_url,同时携带token参数(即订单ID)。此时你需要捕获一次性付款的金额,并确认订阅已创建:
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest; if (!isset($_GET['token'])) { die("无效的付款回调"); } $orderId = $_GET['token']; $captureRequest = new OrdersCaptureRequest($orderId); $captureRequest->prefer('return=representation'); try { $response = $client->execute($captureRequest); // 遍历购买单元,分别处理一次性付款和订阅 foreach ($response->result->purchase_units as $unit) { switch ($unit->reference_id) { case "single_product_001": // 一次性付款已成功捕获,处理业务逻辑(比如发货、生成订单记录) $captureId = $unit->payments->captures[0]->id; echo "一次性购买已完成,捕获ID: {$captureId}"; break; case "subscription_monthly_001": // 订阅已成功创建,获取订阅ID并关联到用户 $subscriptionId = $unit->payments->subscriptions[0]->id; echo "订阅已创建,订阅ID: {$subscriptionId}"; break; } } } catch (\Exception $e) { error_log("捕获PayPal付款失败: " . $e->getMessage()); echo "付款处理失败,请联系客服"; }
关键注意事项
- 预先创建订阅计划:订阅单元需要关联你在PayPal商家后台(或通过API)创建的订阅计划,计划需设置好周期(月度/季度)、金额、免费试用期等参数。
- 依赖Webhook而非仅return_url:用户可能在付款后关闭页面,所以一定要配置PayPal Webhook,监听
PAYMENT.CAPTURE.COMPLETED(一次性付款完成)和BILLING.SUBSCRIPTION.CREATED(订阅创建)事件,确保业务逻辑的可靠性。 - 金额展示:用户在PayPal付款页面会看到一次性付款+订阅首次费用的总金额,以及明细,确认后才会完成付款。
内容的提问来源于stack exchange,提问作者Amit
相关产品推荐
相关产品推荐

