注册 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 配置页面
- 登录后,在左侧导航栏找到 "开发者" 菜单
- 点击 "Webhooks" 子菜单
- 点击 "添加端点" 按钮
步骤 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:使用控制台测试功能
- 在 Webhook 列表中找到您的端点
- 点击 "测试" 按钮
- 选择要测试的事件类型
- 点击 "发送测试事件"
- 查看响应结果和日志
方法 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 注册后,您可以:
- 使用测试卡号 - 测试 Webhook 事件接收
- 集成支付页面 - 完整的支付流程
- 深入了解 Webhook - 学习更多高级用法