You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PayPal IPN未传递发票号问题排查:按钮代码已配置但web_accept类型交易丢失invoice/custom字段

问题分析与解决方案

首先得给你敲个重点:你现在用的checkout.js是PayPal已经弃用的旧版v4 Checkout SDK,这绝对是你遇到IPN字段缺失问题的核心原因之一,再加上广告拦截工具搞的鬼,才会出现这种奇怪的现象。

为什么会出现txn_type为web_accept且字段丢失?

从你测试的Adblock拦截情况来看,当checkout.js的依赖资源被拦截时,PayPal的按钮会自动降级到传统的web_accept表单提交模式——这不是你配置的Express Checkout流程,而是一个 fallback 方案。在这个降级模式下,你通过JS代码设置的invoice_numbercustom字段根本没被传递到PayPal的支付流程里,自然IPN里就拿不到这些值了。而正常加载成功的Express Checkout流程(txn_type为express_checkout)是能正确传递字段的,这也验证了这个逻辑。

解决步骤

1. 立刻切换到最新的PayPal JS SDK

旧的checkout.js已经被PayPal淘汰,不再维护,兼容性问题只会越来越多。新的SDK是https://www.paypal.com/sdk/js,适配现代浏览器,抗拦截能力更强,而且能确保字段正确传递。给你改好的示例代码,直接替换原来的即可:

<script src="https://www.paypal.com/sdk/js?client-id=你的客户端ID"></script>
<script>
  paypal.Buttons({
    style: {
      label: 'checkout',
      fundingicons: true,
      size: 'responsive',
      shape: 'rect',
      color: 'gold'
    },
    createOrder: (data, actions) => {
      return actions.order.create({
        purchase_units: [{
          amount: {
            value: amount, // 确保这个变量在当前作用域有正确值
            currency_code: currency // 同上
          },
          invoice_id: '{$invoice}', // 对应原来的invoice_number
          custom_id: '{$invoice}' // 对应原来的custom字段
        }]
      });
    },
    onApprove: (data, actions) => {
      return actions.order.capture().then(details => {
        // 这里可以加支付成功后的前端逻辑,比如跳转或提示
      });
    }
  }).render('#paypal-button-container'); // 把这个ID改成你页面上的按钮容器ID
</script>

注意:新SDK的API有变化,用createOrder替代了旧的payment.create,字段名也换成了invoice_idcustom_id,别搞错了。

2. 应对广告拦截工具的影响

虽然新SDK已经优化了资源加载,被拦截的概率低很多,但还是可以做些兜底:

  • 给PayPal按钮容器起个不那么“显眼”的ID/类名,比如别直接叫paypal-checkout-button(不过新SDK已经处理了大部分这类拦截)
  • 可以加个加载失败的提示:如果按钮在3秒内没渲染出来,就显示“检测到广告拦截工具,请暂时关闭后重试”的提示,引导用户处理

3. 加固你的IPN处理逻辑

不管用不用新SDK,你的ipn.php都得更健壮:

  • 不要只靠invoicecustom字段判断,结合txn_idmc_grosspayment_status等多个字段一起验证,避免单一字段缺失导致流程失败
  • 一定要严格验证PayPal的IPN签名,防止伪造的请求搞破坏——PayPal官方有PHP的签名验证示例,直接用就行

额外检查点

切换新SDK后,如果还有问题,先排查这两点:

  • 确认前端的amountcurrency变量是正确赋值的,别是空或者错误的值
  • 检查你的ipn.php是否正确处理了字符编码(比如你示例里的charset=windows-1252,要确保PHP脚本用对应编码解析POST参数)

内容的提问来源于stack exchange,提问作者artie

火山引擎 最新活动