{"openapi":"3.1.0","info":{"title":"GEO 驾驶舱 Webhook API","version":"1.0.0","description":"外部业务系统向来源追踪服务回传注册、充值和支付事件。"},"servers":[{"url":"/"}],"paths":{"/webhooks/events":{"post":{"summary":"接收外部业务事件","operationId":"receiveSourceEvent","parameters":[{"name":"X-GEO-Timestamp","in":"header","required":true,"schema":{"type":"string","pattern":"^\\d{10,12}$"},"description":"发送时的 Unix 秒级时间戳，允许误差 300 秒。"},{"name":"X-GEO-Signature","in":"header","required":true,"schema":{"type":"string","pattern":"^v1=[a-f0-9]{64}$"},"description":"v1=HMAC-SHA256(secret, timestamp + \".\" + rawBody)。"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"event_id":"evt_01J5EXAMPLE","event_type":"user.registered","occurred_at":"2026-08-20T10:00:00.000Z","click_id":"0f62d3c3-38c2-4db5-8451-8db1cabb2f0d","user_id":"user_12345","data":{"registration_source":"web"}}}}},"responses":{"200":{"description":"同一事件已处理，幂等返回"},"202":{"description":"新事件已接收","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResult"}}}},"400":{"description":"JSON 或字段格式错误"},"401":{"description":"签名无效或时间戳过期"},"409":{"description":"同一 event_id 对应了不同事件内容"},"413":{"description":"请求体超过 64 KiB"},"415":{"description":"Content-Type 不是 application/json"},"426":{"description":"生产环境必须通过 HTTPS 调用"}}}}},"components":{"schemas":{"WebhookEvent":{"type":"object","additionalProperties":false,"required":["event_id","event_type","occurred_at","click_id","user_id"],"properties":{"event_id":{"type":"string","minLength":1,"maxLength":128},"event_type":{"type":"string","enum":["user.registered","wallet.recharged","order.paid"]},"occurred_at":{"type":"string","format":"date-time"},"click_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","minLength":1,"maxLength":128},"data":{"type":"object","additionalProperties":true,"default":{}}}},"WebhookResult":{"type":"object","required":["status","event_id","matched_click"],"properties":{"status":{"type":"string","enum":["accepted","duplicate"]},"event_id":{"type":"string"},"matched_click":{"type":"boolean"}}}}}}