跳到主要内容
GravityDock 引力聚合技术文档
GravityDock 引力聚合

服务端集成与发货通知

接收 GravityDock 支付到账通知,按原始请求体验签,校验订单并幂等发货,返回平台确认回执。

查看 Markdown

渠道支付经 GravityDock 校验后,Dock 向游戏服务端发送 payment.paid 通知。游戏服务端校验通知和商户订单,在事务中发放道具,提交后返回确认。

配置接收地址

  1. 游戏服务端提供可直接访问的公网 HTTPS POST 地址,使用 443 端口和有效 TLS 证书。接收地址应直接处理请求,Dock 不跟随重定向。
  2. 在「游戏管理 → 编辑游戏」填写「游戏发货通知地址」和独立的「通知签名密钥」,游戏服务端配置相同密钥。
  3. 先完成验签、订单校验、幂等发货和回执测试,再开启「启用游戏发货通知」,用受控订单验证整条链路。

请求格式

请求为 POST,Content-Type 为 application/json; charset=utf-8。

请求头含义
X-Dock-Timestamp当前投递尝试的 Unix 秒时间戳。
X-Dock-Delivery-Id投递标识,重试时保持一致。
X-Dock-Signaturev1= 加 HMAC-SHA256 小写十六进制摘要。
{
  "version": 1,
  "event": "payment.paid",
  "delivery_id": "PS-example-delivery",
  "order_no": "PS-example-order",
  "merchant_order_no": "game-order-123",
  "channel_order_id": "channel-order-456",
  "game_id": "12345",
  "channel_id": "23456",
  "provider": "xiaomi",
  "user_id": "player-uid",
  "amount": "1.00",
  "amount_minor": 100,
  "currency": "CNY",
  "product_id": "sku-1",
  "paid_at": "2026-11-04T08:00:00Z",
  "product_count": 2,
  "product_desc": "游戏商品描述",
  "product_id": "游戏商品id",
  "product_name": "游戏商品名",
  "extra": {"role_id": "role-123", "server_id": "server-1"}
}

amount_minor 为整数分,amount 为十进制字符串。按整数分或精确十进制校验金额。游戏与渠道 ID 为字符串,extra 来自下单时的透传快照。游戏服务端应以自身订单保存的角色和区服为准。

签名验证

使用独立通知密钥和原始请求体计算签名。签名输入为时间戳字符串、英文句点和收到的请求体字节依次拼接。应在解析 JSON 前完成验签。

import hashlib
import hmac
import json
import time

def verify_notification(raw_body: bytes, headers, secret: str):
    timestamp = headers["X-Dock-Timestamp"]
    if not timestamp.isascii() or not timestamp.isdecimal():
        raise ValueError("invalid timestamp")
    if abs(int(time.time()) - int(timestamp)) > 300:
        raise ValueError("expired notification")

    message = timestamp.encode("ascii") + b"." + raw_body
    expected = "v1=" + hmac.new(
        secret.encode("utf-8"), message, hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(expected, headers["X-Dock-Signature"]):
        raise ValueError("invalid signature")

    event = json.loads(raw_body)
    if (
        event["version"] != 1
        or event["event"] != "payment.paid"
        or event["delivery_id"] != headers["X-Dock-Delivery-Id"]
    ):
        raise ValueError("invalid notification")
    return event

示例采用 300 秒时间窗。实际处理时,将缺失请求头、格式错误和验签失败映射为失败响应,并保持接收端时钟同步。

幂等发货与回执

  1. 按 merchant_order_no 查游戏订单,核对游戏、渠道、商品、金额、币种及绑定的玩家和角色。
  2. 在同一事务内保存发货记录和道具变更,以游戏与 order_no 设唯一键,并确保同一商户订单只发货一次。已成功处理的重复投递应复用成功结果。
  3. 发货事务提交后返回 HTTP 200 和 JSON。回执中的 code 为整数 0,delivery_id 回传当前通知标识。
{"code": 0, "delivery_id": "PS-example-delivery"}

重试和对账

通知可能重复到达。响应失败、超时或回执不匹配会触发退避重试,最多连续 8 次失败。到「玩家运营 → 订单运营」检查通知状态和投递记录。自动重试沿用首次排队的地址和密钥快照。修改地址或轮换密钥后,对仍需投递的旧记录由授权人员排障后人工重试,使用当前配置。历史已支付订单需逐笔核对,由授权人员对符合条件的订单发起补发。

文档维护:Gravity Engine

文档修改日期:

本页内容