Webhook 配置
通过 Webhook 实时接收发货状态更新。
什么是 Webhook?
Webhook 是在事件发生时,由 atoship 自动推送到你服务器的消息通知,例如:
- 已创建面单
- 包裹已发货
- 派送状态发生变化
- 出现异常
优势:
- 实时更新(无需轮询)
- 触发自动化流程
- 即时同步你的系统
- 提升客户体验
可用事件
发货事件
| 事件 | 触发时机 | 使用场景 |
|---|---|---|
| shipment.created | 已购买面单 | 更新库存 |
| shipment.cancelled | 面单已作废 | 恢复库存 |
| shipment.delivered | 包裹已签收 | 发送评价邀请 |
| shipment.returned | 已收到退货 | 处理退款 |
| shipment.exception | 派送异常 | 通知客服 |
物流跟踪事件
| 事件 | 触发时机 | 使用场景 |
|---|---|---|
| tracking.in_transit | 承运商首次扫描 | 通知客户 |
| tracking.out_for_delivery | 已上派送车 | 当日提醒 |
| tracking.delivered | 确认签收 | 关闭订单 |
| tracking.failed_attempt | 派送尝试失败 | 提醒客户 |
| tracking.exception | 出现问题 | 排查处理 |
订单事件
| 事件 | 触发时机 | 使用场景 |
|---|---|---|
| order.imported | 订单已同步 | 开始履约 |
| order.updated | 订单已修改 | 更新记录 |
| order.cancelled | 订单已取消 | 停止履约 |
账户事件
| 事件 | 触发时机 | 使用场景 |
|---|---|---|
| balance.low | 钱包余额低于阈值 | 充值提醒 |
| billing.adjustment | 承运商费用调整 | 复核账单 |
配置指南
第 1 步:创建接收端点
你的端点必须:
- 接受 POST 请求
- 使用 HTTPS(生产环境必需)
- 在 5 秒内返回 200 状态码
- 以幂等方式处理重试
端点示例(Node.js/Express):
const express = require('express');
const app = express();
app.post('/webhooks/atoship', express.json(), (req, res) => {
// Acknowledge immediately
res.status(200).send('OK');
// Process asynchronously
processWebhook(req.body).catch(console.error);
});
async function processWebhook(event) {
switch (event.type) {
case 'shipment.delivered':
await markOrderDelivered(event.data.order_id);
await sendDeliveryEmail(event.data);
break;
case 'tracking.exception':
await alertCustomerService(event.data);
break;
// Handle other events...
}
}
第 2 步:注册 Webhook
- 进入 设置 > Webhooks
- 点击 添加 Webhook 端点
- 输入你的 URL:https://yoursite.com/webhooks/atoship
- 选择要接收的事件
- 点击 保存
第 3 步:复制 Webhook 密钥
保存后:
- 点击你的 Webhook
- 复制 签名密钥(Signing Secret)
- 妥善保管(存入环境变量)
第 4 步:验证签名
重要提示:请务必验证 Webhook 签名,以防止伪造请求。
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expectedSig = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
// Use timing-safe comparison
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSig, 'hex')
);
}
app.post('/webhooks/atoship', express.json(), (req, res) => {
const signature = req.headers['x-atoship-signature'];
const secret = process.env.ATOSHIP_WEBHOOK_SECRET;
if (!verifySignature(req.body, signature, secret)) {
console.error('Invalid webhook signature');
return res.status(401).send('Invalid signature');
}
// Signature valid, process event
res.status(200).send('OK');
processWebhook(req.body);
});
事件载荷(Payload)结构
标准格式
{
"id": "evt_1234567890abcdef",
"type": "shipment.delivered",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"shipment_id": "shp_abc123",
"tracking_number": "9400111899223456789012",
"carrier": "USPS",
"service": "Priority Mail",
"order_id": "order_xyz789",
"order_reference": "ORD-12345",
"delivered_at": "2024-01-15T10:28:00Z",
"delivery_location": "Front door",
"signed_by": "RESIDENT"
},
"metadata": {
"organization_id": "org_xxxxx",
"attempt": 1
}
}
重试机制
自动重试
如果你的端点返回非 2xx 状态码或超时:
| 尝试次数 | 延迟时间 |
|---|---|
| 1 | 立即 |
| 2 | 1 分钟 |
| 3 | 5 分钟 |
| 4 | 30 分钟 |
| 5 | 2 小时 |
| 6 | 6 小时 |
连续失败 6 次后,该 Webhook 将被标记为失败。
处理重试
幂等性至关重要:
const processedEvents = new Map(); // Use Redis in production
async function processWebhook(event) {
// Check if already processed
if (processedEvents.has(event.id)) {
console.log('Event ' + event.id + ' already processed, skipping');
return;
}
// Mark as processing
processedEvents.set(event.id, { status: 'processing', timestamp: Date.now() });
try {
// Process event
await handleEvent(event);
processedEvents.set(event.id, { status: 'completed', timestamp: Date.now() });
} catch (error) {
processedEvents.set(event.id, { status: 'failed', error: error.message });
throw error; // Let retry happen
}
}
测试 Webhook
发送测试事件
- 进入 设置 > Webhooks
- 点击你的端点
- 点击 发送测试事件
- 选择事件类型
- 查看响应结果
本地开发
使用 ngrok 进行本地测试:
# Install ngrok
npm install -g ngrok
# Expose local port
ngrok http 3000
# Use provided URL
# https://abc123.ngrok.io/webhooks/atoship
Webhook 日志
查看推送尝试记录:
- 进入 Webhook 设置
- 点击 推送日志(Delivery Logs)
- 查看请求 / 响应详情
- 重新推送失败的记录
最佳实践
响应时间
尽快返回 200:
// Good - Acknowledge immediately, process async
app.post('/webhooks', (req, res) => {
res.status(200).send('OK');
queue.add('process-webhook', req.body);
});
// Bad - Blocking response
app.post('/webhooks', async (req, res) => {
await processWebhook(req.body); // May timeout
res.status(200).send('OK');
});
监控
跟踪 Webhook 运行状况:
- 推送成功率
- 平均响应时间
- 失败的事件类型
- 重试频率
故障排查
收不到 Webhook
请检查:
- 端点 URL 是否正确
- 是否已启用 HTTPS
- 防火墙是否放行 atoship 的 IP
- 是否已订阅相应事件
- Webhook 是否已启用
签名验证失败
常见原因:
- 使用了已解析的 JSON,而非原始请求体(raw body)
- Webhook 密钥错误
- 编码不一致
超时错误
如果 Webhook 超时:
- 立即返回 200
- 异步处理业务逻辑
- 使用消息队列
- 检查服务器性能
需要帮助?
- API 文档:完整的 Webhook 参考
- 开发者聊天:技术支持
- 邮箱:[email protected]
- 客服支持:前往 /dashboard/support 创建工单