← 返回商户后台

商户 API 接入文档

更新:2026-09-20。依据当前 B 服务实现整理。

接入地址与凭证

服务地址:https://nyshanghu.com。商户程序仅调用 B,所有商户共用 URL,通过独立凭证隔离数据。

管理员开通商户时交付 api_key_idapi_secretwebhook_secret。后两项仅创建时展示,应保存在商户服务器安全配置中,不能放入网页、App 或日志。管理员令牌不是商户 API 密钥。

开通前请提供商户的 HTTPS 回调完整 URL(443 端口);其域名需由平台加入允许名单。回调 URL 是商户接收通知的接口,与平台地址申请 API 不同。

当前服务器自动任务及主网广播未启用;接口接入完成不代表充值监听、通知投递和归集已正式上线。请与平台确认启用状态。

申请客户固定充值地址

POST https://nyshanghu.com/v1/addresses

{"customer_id":"user_10001"}

customer_id:商户自身已登录用户的固定编号,1–100 位 ASCII 字母、数字或 _.:@-。不要每次点击充值生成新编号,不传 merchant_id。首次分配地址,同商户同客户重复请求返回原地址;不同客户独立地址。

响应字段包括 id、merchant_id、customer_id、network、asset、address、created_at。当前主网 network 为 tron-mainnet,asset 为 USDT。将 address 显示给客户;不返回私钥。申请成功不代表已充值。

请求签名

所有商户接口使用以下请求头:

请求头
Content-Typeapplication/json
X-Key-Id商户 api_key_id
X-Timestamp当前 Unix 秒数,十进制字符串
X-Nonce每次请求新的随机串,16–100 位 ASCII 字符
X-Signature使用 api_secret 计算的 HMAC-SHA256 小写十六进制

签名原文由五段组成,以真实换行符连接,末尾无额外换行:

timestamp
nonce
大写HTTP方法
请求路径及原始查询字符串
SHA256(原始请求体字节)的小写十六进制

路径不含域名;例如 /v1/deposits?limit=50&offset=0,查询顺序、编码必须与实际请求一致。GET 请求体为空字节。时间允许偏差 ±300 秒,nonce 不可重用。超时重试重新生成时间戳和 nonce、重新签名,但 customer_id 保持不变。序列化后的 JSON 必须与实际发送字节完全相同。

Python 地址申请示例

仅依赖标准库。通过环境变量设置:

保存下方代码为 merchant_client.py,运行 python merchant_client.py user_10001

"""商户服务器端地址申请示例;仅依赖标准库。"""
import hashlib
import hmac
import json
import os
import secrets
import sys
import time
import urllib.request


def get_address(customer_id):
    """Use the authenticated user's stable ID, not an ID supplied by another user."""
    url = os.environ['DEPOSIT_API_URL']
    from urllib.parse import urlsplit
    parsed = urlsplit(url)
    if parsed.scheme not in ('http', 'https') or parsed.path != '/v1/addresses' or parsed.query or parsed.fragment or parsed.username or parsed.password:
        raise ValueError('DEPOSIT_API_URL must be the full /v1/addresses endpoint')
    if parsed.scheme != 'https' and parsed.hostname not in ('127.0.0.1', 'localhost'):
        raise ValueError('Remote connections require HTTPS')
    body = json.dumps({'customer_id': customer_id}, separators=(',', ':')).encode()
    timestamp, nonce = str(int(time.time())), secrets.token_hex(16)
    message = '\n'.join([timestamp, nonce, 'POST', parsed.path, hashlib.sha256(body).hexdigest()])
    signature = hmac.new(os.environ['DEPOSIT_API_SECRET'].encode(), message.encode(), hashlib.sha256).hexdigest()
    request = urllib.request.Request(url, data=body, method='POST', headers={
        'Content-Type': 'application/json', 'X-Key-Id': os.environ['DEPOSIT_API_KEY_ID'],
        'X-Timestamp': timestamp, 'X-Nonce': nonce, 'X-Signature': signature,
    })
    # Do not forward signed requests or credentials to redirect targets.
    class NoRedirect(urllib.request.HTTPRedirectHandler):
        def redirect_request(self, req, fp, code, msg, headers, newurl):
            return None
    with urllib.request.build_opener(NoRedirect).open(request, timeout=15) as response:
        return json.load(response)


if __name__ == '__main__':
    if len(sys.argv) != 2:
        raise SystemExit('Usage: python examples/merchant_client.py <stable_customer_id>')
    print(json.dumps(get_address(sys.argv[1]), ensure_ascii=False))

查询及补发接口

下表路径均相对于服务地址,均需上述签名。

方法与路径功能及参数
GET /v1/addresses地址列表;limit、offset、customer_id
GET /v1/deposits充值列表;limit、offset、customer_id、state
GET /v1/deposits/{id}本商户单笔充值
GET /v1/summary累计确认金额、地址数等统计
GET /v1/ledger账本分录;limit、offset
GET /v1/webhooks通知投递记录;limit、offset、state
POST /v1/webhooks/{id}/retry请求重试本商户通知;空请求体
GET /v1/reconciliation本商户账本一致性检查

列表响应为 {items,limit,offset,total}。limit 默认50、范围1–200;offset 默认0、非负。接口只能读取本商户记录,不能靠提交 merchant_id 切换身份。

金额以 amount_raw 十进制字符串为准,USDT decimals=6;1000000 表示1 USDT。使用整数或精确小数计算,不使用浮点金额。充值入账以 confirmed 状态为准。

充值到账 Webhook

B 将 JSON 以 POST 发送到商户配置的回调 URL。事件含:event_id、event_type=deposit.confirmed、deposit_id、merchant_id、customer_id、network、asset、contract、address、txid、log_index、amount_raw、amount、decimals=6、status=confirmed

请求头:X-Webhook-TimestampX-Webhook-Signature

验签算法与商户请求签名不同:

expected = hmac.new(
    webhook_secret.encode(),
    timestamp.encode() + b'.' + raw_request_body,
    hashlib.sha256,
).hexdigest()
valid = hmac.compare_digest(expected, received_signature)

使用独立 webhook_secret;必须针对原始请求体验签,不能先解析再序列化。验证时间戳合理性(建议±300秒)、事件类型、商户归属、网络/合约及金额格式后,在数据库事务中按 event_id/deposit_id 去重并入账。成功提交后返回 HTTP 2xx;重复通知验证后直接返回2xx,不得重复加款。超时或非2xx会重试,不能假设通知仅送一次。

错误处理

HTTP状态含义
401凭证或签名无效、时间戳异常
403商户停用或入口禁止访问
404不存在或不属于本商户
409nonce重放、幂等冲突或状态冲突
422请求字段或配置不符合要求
429请求过于频繁
502 / 503依赖暂不可用

不要将 HTTP 200 当作到账证明,必须检查业务状态。

在线文档入口

商户接入文档: https://nyshanghu.com/docs 。此页面提供商户接口说明,不需要管理员令牌;业务 API 仍须商户签名认证。