如何在PHP环境下的PayPal订阅中为首次循环付款应用折扣码
嘿,这个需求我之前做PayPal订阅功能的时候刚好实现过,其实有两种很靠谱的方式,都是基于PayPal REST API来做的(毕竟老的NVP接口现在基本没人用了),给你详细说说:
方法一:创建包含首次优惠的订阅计划
这种方式是预先定义一个订阅计划,把首次付款的优惠直接嵌入到计划的计费周期里,用户订阅这个计划就自动享受首次折扣,后续按原价扣费。
首先,你需要先安装PayPal的PHP SDK:
composer require paypal/rest-api-sdk-php
然后是具体的代码实现,先初始化API上下文(记得替换成你的客户端ID和密钥):
require __DIR__ . '/vendor/autoload.php'; $apiContext = new \PayPal\Rest\ApiContext( new \PayPal\Auth\OAuthTokenCredential( '你的客户端ID', '你的客户端密钥' ) ); // 沙箱环境配置,生产环境可以去掉 $apiContext->setConfig([ 'mode' => 'sandbox', 'log.LogEnabled' => true, 'log.FileName' => '../PayPal.log', 'log.LogLevel' => 'DEBUG', 'cache.enabled' => true, ]);
接下来创建带有首次优惠的计划:
// 定义常规计费周期(每月20美元,无限期) $regularCycle = new \PayPal\Api\BillingCycle(); $regularCycle->setFrequency('MONTH') ->setFrequencyInterval('1') ->setCycles('INFINITE') ->setAmount(new \PayPal\Api\Currency(['value' => '20.00', 'currency' => 'USD'])); // 定义首次优惠周期(第一个月15美元,仅1次) $firstCycle = new \PayPal\Api\BillingCycle(); $firstCycle->setFrequency('MONTH') ->setFrequencyInterval('1') ->setCycles('1') ->setAmount(new \PayPal\Api\Currency(['value' => '15.00', 'currency' => 'USD'])) ->setTenureType('TRIAL'); // 用TRIAL标记这个是优惠周期 // 把两个周期组合成付款规则 $paymentDefinition = new \PayPal\Api\PaymentDefinition(); $paymentDefinition->setName('首月优惠订阅') ->setType('REGULAR') ->setPaymentCycles('INFINITE') ->setAmount(new \PayPal\Api\Currency(['value' => '20.00', 'currency' => 'USD'])) ->setBillingCycles([$firstCycle, $regularCycle]); // 创建并激活计划 $plan = new \PayPal\Api\Plan(); $plan->setName('高级订阅套餐') ->setDescription('高级订阅,首月立减5美元') ->setType('INFINITE') ->setPaymentDefinitions([$paymentDefinition]); try { // 创建计划 $plan->create($apiContext); // 激活计划(默认创建的计划是草稿状态,必须激活才能使用) $patch = new \PayPal\Api\Patch(); $patch->setOp('replace') ->setPath('/') ->setValue(['state' => 'ACTIVE']); $patchRequest = new \PayPal\Api\PatchRequest(); $patchRequest->addPatch($patch); $plan->update($patchRequest, $apiContext); echo "计划创建成功,ID:" . $plan->getId(); } catch (\PayPal\Exception\PayPalConnectionException $ex) { // 处理API连接错误 echo $ex->getCode() . "<br>" . $ex->getData(); die($ex); } catch (Exception $ex) { die($ex); }
用户订阅的时候,直接使用这个计划创建订阅即可:
$subscription = new \PayPal\Api\Subscription(); $subscription->setPlanId($plan->getId()) ->setStartDate(date('c', strtotime('+1 day'))) // 订阅开始日期(可以设为当前时间或未来某一天) ->setSubscriber([ 'name' => ['given_name' => '张三', 'surname' => '李四'], 'email_address' => 'user@example.com' ]); try { $subscription->create($apiContext); // 获取PayPal的批准链接,跳转到这里让用户确认订阅 $approvalUrl = $subscription->getLinks()[0]->getHref(); header("Location: $approvalUrl"); } catch (\PayPal\Exception\PayPalConnectionException $ex) { echo $ex->getCode() . "<br>" . $ex->getData(); die($ex); } catch (Exception $ex) { die($ex); }
方法二:使用一次性优惠券实现首月优惠
这种方式是先创建一个常规的20美元订阅计划,然后生成一个仅适用于首次付款的优惠券,用户订阅时应用这个优惠券,首月自动减5美元,后续恢复原价。
创建优惠券的代码:
$coupon = new \PayPal\Api\Coupon(); $coupon->setName('首月立减5美元') ->setDescription('订阅高级套餐首月享受5美元折扣') ->setDiscountType('FIXED_AMOUNT') ->setAmount(new \PayPal\Api\Currency(['value' => '5.00', 'currency' => 'USD'])) ->setMaxRedemptions(100) // 设置优惠券最大使用次数 ->setValidFrom(date('c')) ->setValidUntil(date('c', strtotime('+30 days'))); // 设置优惠券有效期 try { $coupon->create($apiContext); echo "优惠券创建成功,ID:" . $coupon->getId(); } catch (\PayPal\Exception\PayPalConnectionException $ex) { echo $ex->getCode() . "<br>" . $ex->getData(); die($ex); } catch (Exception $ex) { die($ex); }
然后在创建订阅的时候应用这个优惠券:
$subscription = new \PayPal\Api\Subscription(); $subscription->setPlanId('你的常规20美元计划ID') ->setStartDate(date('c', strtotime('+1 day'))) ->setSubscriber([ 'name' => ['given_name' => '张三', 'surname' => '李四'], 'email_address' => 'user@example.com' ]) ->setAppliedCoupon(['coupon_id' => $coupon->getId()]); // 应用优惠券 // 后续创建订阅和跳转的代码和方法一一致
两种方法的对比
- 方法一(嵌入优惠的计划):优点是配置好后不用额外管理优惠券,用户订阅直接生效;缺点是如果优惠规则变了,需要重新创建计划。
- 方法二(优惠券):优点是灵活,同一个常规计划可以搭配不同优惠券,还能设置有效期和使用次数;缺点是需要额外维护优惠券资源。
注意事项
- 确保你的PayPal账号已经开启了订阅功能(新账号默认开启,老账号如果没开可以去后台设置)。
- 一定要先在沙箱环境测试,用PayPal沙箱账号模拟订阅,确认首次付款是15美元,后续账单是20美元。
- 如果用的是最新的PayPal Checkout SDK,代码结构会有点不一样,但核心逻辑是相同的——要么设置多周期金额,要么应用首次有效的优惠券。
内容的提问来源于stack exchange,提问作者Vishvakarma Dhiman
相关产品推荐
相关产品推荐

