PayPal Webhook签名验证始终失败,返回{ verification_status: "FAILURE" }
PayPal Webhook签名验证始终返回FAILURE的解决方案
核心问题及修复步骤
1. 环境地址不匹配
你代码中调用的是沙盒环境API地址(https://api-m.sandbox.paypal.com),但你明确说明使用正式密钥和真实交易,正式环境必须切换到生产地址:https://api-m.paypal.com。不管是获取授权令牌还是验证签名的接口,都要替换为生产环境地址,沙盒地址仅适用于沙盒测试场景。
2. webhook_event参数错误
你当前传递的是req.body.resource,但PayPal的verify-webhook-signature接口要求webhook_event是完整的Webhook事件体(即整个req.body),而非仅resource部分。签名是基于完整事件内容生成的,仅传递resource会直接导致验证失败。
修正后的代码示例
获取授权令牌(正式环境)
const params = new URLSearchParams() params.append('grant_type', 'client_credentials') const getAuthToken = await axios.post( 'https://api-m.paypal.com/v1/oauth2/token', params, { headers: { 'content-type': 'application/x-www-form-urlencoded' }, auth: { username: '你的正式环境Client ID', password: '你的正式环境Secret', }, }, )
验证Webhook签名(正式环境)
const verifyWebhook = await axios.post('https://api-m.paypal.com/v1/notifications/verify-webhook-signature', { auth_algo: req.headers['paypal-auth-algo'], cert_url: req.headers['paypal-cert-url'], transmission_id: req.headers['paypal-transmission-id'], transmission_sig: req.headers['paypal-transmission-sig'], transmission_time: req.headers['paypal-transmission-time'], webhook_id: '你的正式环境Webhook ID', webhook_event: req.body, // 传递完整事件体,而非req.body.resource }, { headers: { Authorization: `Bearer ${getAuthToken.data.access_token}`, 'Content-Type': 'application/json', }, }) console.log(verifyWebhook.data);
额外检查点
- 确认Webhook ID是正式环境生成的,而非沙盒环境的ID;
- 确保接收Webhook的服务器没有修改原始请求体(比如解析后重新序列化时改变了空格、字段顺序等),签名验证对内容一致性要求极高,任何格式变动都会导致失败;
- 检查请求头是否完整传递,没有遗漏PayPal的自定义头字段。
内容的提问来源于stack exchange,提问作者Darkbound
相关产品推荐
相关产品推荐

