注册 Webhook

通过 GoGoPay 开发者控制台注册 Webhook 端点,配置事件通知, 确保您的应用程序能够及时接收支付状态变更通知。

前置条件

在注册 Webhook 之前,请确保:

  • 已完成 GoGoPay 账户注册和企业认证
  • 已准备好接收 Webhook 的服务器端点
  • 服务器端点支持 HTTPS 协议
  • 已实现 Webhook 签名验证逻辑
重要提示: Webhook 端点必须能够在 30 秒内响应 HTTP 200 状态码, 否则 GoGoPay 会认为发送失败并进行重试。

注册步骤

步骤 1:登录开发者控制台

访问 GoGoPay 开发者控制台:

  • 沙箱环境https://sandbox.gogopay.com
  • 生产环境https://dashboard.gogopay.com

步骤 2:进入 Webhook 配置页面

  1. 登录后,在左侧导航栏找到 "开发者" 菜单
  2. 点击 "Webhooks" 子菜单
  3. 点击 "添加端点" 按钮

步骤 3:配置 Webhook 端点

在配置页面填写以下信息:

字段 描述 示例
端点 URL 接收 Webhook 的服务器地址 https://api.yoursite.com/webhooks/gogopay
描述 端点的描述信息(可选) 生产环境支付通知端点
事件类型 选择要接收的事件类型 payment.succeeded, payment.failed
状态 启用或禁用此端点 启用

事件类型选择

您可以选择接收以下类型的事件通知:

支付相关事件

事件类型 触发时机 建议订阅
payment.succeeded 支付成功完成 ✅ 必须
payment.failed 支付失败 ✅ 推荐
payment.canceled 支付被取消 ✅ 推荐
payment.processing 支付处理中 ⚪ 可选
payment.requires_action 需要用户进一步操作 ⚪ 可选

退款相关事件

事件类型 触发时机 建议订阅
refund.created 退款请求创建 ✅ 推荐
refund.succeeded 退款成功 ✅ 必须
refund.failed 退款失败 ✅ 推荐

会话相关事件

事件类型 触发时机 建议订阅
checkout.session.completed 支付会话完成 ✅ 必须
checkout.session.expired 支付会话过期 ✅ 推荐

测试 Webhook 端点

注册完成后,您可以测试 Webhook 端点是否正常工作:

方法 1:使用控制台测试功能

  1. 在 Webhook 列表中找到您的端点
  2. 点击 "测试" 按钮
  3. 选择要测试的事件类型
  4. 点击 "发送测试事件"
  5. 查看响应结果和日志

方法 2:使用真实支付测试

在沙箱环境中进行真实的支付测试:

// 创建测试支付 fetch('https://sandbox-api.gogopay.com/v1/checkout/sessions', { method: 'POST', headers: { 'Authorization': 'Bearer sk_test_...', 'Content-Type': 'application/json' }, body: JSON.stringify({ payment_method_types: ['card'], line_items: [{ price_data: { currency: 'cny', product_data: { name: 'Webhook 测试商品' }, unit_amount: 100 // 1 元 }, quantity: 1 }], mode: 'payment', success_url: 'https://example.com/success', cancel_url: 'https://example.com/cancel' }) }) .then(response => response.json()) .then(session => { // 使用测试卡号 4242424242424242 完成支付 window.location.href = session.url; });

Webhook 端点实现示例

以下是不同编程语言的 Webhook 端点实现示例:

Node.js (Express)

const express = require('express'); const crypto = require('crypto'); const app = express(); // 使用原始请求体进行签名验证 app.use('/webhook', express.raw({ type: 'application/json' })); app.post('/webhook', (req, res) => { const signature = req.headers['gogopay-signature']; const payload = req.body; try { // 验证签名 if (!verifySignature(payload, signature, process.env.WEBHOOK_SECRET)) { return res.status(400).send('Invalid signature'); } const event = JSON.parse(payload); // 处理事件 switch (event.type) { case 'payment.succeeded': handlePaymentSucceeded(event.data.object); break; case 'payment.failed': handlePaymentFailed(event.data.object); break; case 'checkout.session.completed': handleCheckoutCompleted(event.data.object); break; default: console.log(`Unhandled event type: ${event.type}`); } res.status(200).send('OK'); } catch (error) { console.error('Webhook error:', error); res.status(400).send('Webhook error'); } }); function verifySignature(payload, signature, secret) { const elements = signature.split(','); const timestamp = elements[0].split('=')[1]; const v1 = elements[1].split('=')[1]; const signedPayload = timestamp + '.' + payload; const expectedSignature = crypto .createHmac('sha256', secret) .update(signedPayload, 'utf8') .digest('hex'); return crypto.timingSafeEqual( Buffer.from(v1, 'hex'), Buffer.from(expectedSignature, 'hex') ); } app.listen(3000, () => { console.log('Webhook server running on port 3000'); });

Python (Flask)

from flask import Flask, request, jsonify import hmac import hashlib import json import time app = Flask(__name__) WEBHOOK_SECRET = 'your_webhook_secret' @app.route('/webhook', methods=['POST']) def webhook(): signature = request.headers.get('GoGoPay-Signature') payload = request.get_data() try: # 验证签名 if not verify_signature(payload, signature, WEBHOOK_SECRET): return jsonify({'error': 'Invalid signature'}), 400 event = json.loads(payload) # 处理事件 if event['type'] == 'payment.succeeded': handle_payment_succeeded(event['data']['object']) elif event['type'] == 'payment.failed': handle_payment_failed(event['data']['object']) elif event['type'] == 'checkout.session.completed': handle_checkout_completed(event['data']['object']) else: print(f"Unhandled event type: {event['type']}") return jsonify({'status': 'success'}), 200 except Exception as e: print(f"Webhook error: {e}") return jsonify({'error': 'Webhook error'}), 400 def verify_signature(payload, signature, secret): elements = signature.split(',') timestamp = int(elements[0].split('=')[1]) v1 = elements[1].split('=')[1] # 检查时间戳(5分钟内有效) if time.time() - timestamp > 300: return False signed_payload = f"{timestamp}.{payload.decode('utf-8')}" expected_signature = hmac.new( secret.encode('utf-8'), signed_payload.encode('utf-8'), hashlib.sha256 ).hexdigest() return hmac.compare_digest(v1, expected_signature) if __name__ == '__main__': app.run(port=3000, debug=True)

管理 Webhook 端点

注册后,您可以在控制台管理 Webhook 端点:

查看端点状态

  • 活跃:端点正常接收事件
  • 失败:最近的发送尝试失败
  • 禁用:端点已被禁用

查看发送日志

控制台提供详细的发送日志,包括:

  • 发送时间
  • 事件类型
  • 响应状态码
  • 响应时间
  • 重试次数
  • 错误信息(如有)

编辑端点配置

您可以随时修改端点配置:

  • 更改端点 URL
  • 修改事件订阅
  • 启用/禁用端点
  • 重新生成签名密钥

故障排查

如果 Webhook 发送失败,请检查以下项目:

问题 可能原因 解决方案
连接超时 服务器响应时间过长 优化端点处理逻辑,确保在 30 秒内响应
SSL 证书错误 HTTPS 证书无效或过期 更新 SSL 证书,确保证书链完整
404 错误 端点 URL 不存在 检查 URL 路径和服务器路由配置
500 错误 服务器内部错误 检查服务器日志,修复代码错误
签名验证失败 签名算法实现错误 参考文档重新实现签名验证

安全建议

  • 使用 HTTPS:确保端点 URL 使用 HTTPS 协议
  • 验证签名:始终验证 Webhook 签名
  • 限制访问:只允许 GoGoPay 的 IP 地址访问端点
  • 幂等性:确保重复事件不会产生副作用
  • 日志记录:记录所有 Webhook 事件用于审计
  • 错误处理:优雅处理异常情况

IP 白名单

为了增强安全性,您可以配置防火墙只允许以下 IP 地址访问您的 Webhook 端点:

# GoGoPay Webhook IP 地址(示例) 52.89.214.238 54.187.174.169 54.187.205.235 54.187.216.72
注意: 实际的 IP 地址列表请在开发者控制台的 Webhook 配置页面查看, IP 地址可能会发生变化,请定期更新。

生产环境部署

将 Webhook 端点部署到生产环境时,请注意:

环境配置

  • 使用生产环境的 API 密钥和 Webhook 密钥
  • 配置正确的数据库连接
  • 设置适当的日志级别
  • 配置监控和告警

性能优化

  • 使用连接池优化数据库连接
  • 实现异步处理避免阻塞
  • 配置负载均衡器
  • 设置合适的超时时间

下一步

完成 Webhook 注册后,您可以: