brazosd
控制台

文档

商户 Trade API 接入

本文档说明商户如何接入 Brazosd Trade API,用 Agent 作为前端入口、商户 SaaS 作为后端履约系统。

1. 启用商户功能

使用普通 Brazosd Bearer token 调用:

http
POST /api/v1/trade/merchant
Authorization: Bearer <access_token>

启用后,当前 org 会得到一个 merchant profile。平台默认抽佣比例为 1500 ppm,即 0.15%。Brazosd 会同时创建商户回调签名用的 Ed25519 key。商户可用:

http
GET /api/v1/trade/merchant/callback-keys
Authorization: Bearer <access_token>

获取用于校验 Brazosd 回调签名的公钥列表。

2. 生成 Trade API 密钥

商户后端持有 Ed25519 私钥,Brazosd 只保存公钥。私钥只能放在商户服务端,不要放进浏览器、Agent prompt、日志或用户可见配置。

python
from base64 import b64encode
from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.hazmat.primitives import serialization

private_key = ed25519.Ed25519PrivateKey.generate()
public_key = private_key.public_key()

private_key_b64 = b64encode(private_key.private_bytes(
    encoding=serialization.Encoding.Raw,
    format=serialization.PrivateFormat.Raw,
    encryption_algorithm=serialization.NoEncryption(),
)).decode()

public_key_b64 = b64encode(public_key.public_bytes(
    encoding=serialization.Encoding.Raw,
    format=serialization.PublicFormat.Raw,
)).decode()

print("PRIVATE_KEY_B64=", private_key_b64)
print("PUBLIC_KEY_B64=", public_key_b64)

注册公钥:

http
POST /api/v1/trade/merchant/public-keys
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "name": "prod-2026-05",
  "publicKeyB64": "<PUBLIC_KEY_B64>"
}

保存返回的 id,创建订单时放入 x-brazosd-tradeapi-pubkey-id

3. 配置回调 URL

http
PUT /api/v1/trade/merchant/callback-url
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "url": "https://merchant.example.com/brazosd/order-callback"
}

回调 URL 必须是 https://,host 必须是域名,不能是 IP 或 localhost

4. 创建产品

Product 只存价格无关的身份和展示信息。价格在创建订单时快照到订单行里。

http
POST /api/v1/trade/products
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "name": "CRM Agent Seat",
  "description": "Monthly CRM agent seat"
}

description 最多 200 个字符。

5. 签名并创建订单

签名 canonical string:

text
METHOD
REQUEST_URI
TIMESTAMP
BODY

例如 POST /api/v1/tradeapi/orders 时,REQUEST_URI/api/v1/tradeapi/ordersTIMESTAMP 是 Unix seconds,Brazosd 会校验 5 分钟时间窗口。签名是 raw Ed25519 signature 的 base64。

python
import json
import time
import requests
from base64 import b64decode, b64encode
from cryptography.hazmat.primitives.asymmetric import ed25519

base_url = "https://brazosd.example.com"
path = "/api/v1/tradeapi/orders"
private_key = ed25519.Ed25519PrivateKey.from_private_bytes(
    b64decode("<PRIVATE_KEY_B64>")
)

body = {
    "agentId": "<agent_uuid>",
    "buyerUserId": 123,
    "outTradeNo": "merchant-order-10001",
    "description": "CRM Agent monthly usage",
    "expiresInSeconds": 1800,
    "items": [
        {
            "productId": "<product_uuid>",
            "amountMicroyuans": 199000000,
            "note": "May subscription"
        }
    ]
}
body_bytes = json.dumps(body, separators=(",", ":"), ensure_ascii=False).encode()
timestamp = str(int(time.time()))
canonical = b"POST\n" + path.encode() + b"\n" + timestamp.encode() + b"\n" + body_bytes
signature = b64encode(private_key.sign(canonical)).decode()

resp = requests.post(
    base_url + path,
    data=body_bytes,
    headers={
        "content-type": "application/json",
        "x-brazosd-tradeapi-pubkey-id": "<registered_public_key_id>",
        "x-brazosd-tradeapi-timestamp": timestamp,
        "x-brazosd-tradeapi-signature": signature,
    },
    timeout=10,
)
resp.raise_for_status()
print(resp.json())

outTradeNo 在同一个 merchant 下幂等。相同 outTradeNo 和相同请求体会返回同一个订单;相同 outTradeNo 但请求体不同会返回冲突。

6. 用户授权和白名单

订单创建后,Brazosd 会向 buyerUserId 创建一个授权表单。用户确认后才会扣款。用户勾选“不再询问此类订单”时,本订单的所有 productId 会加入该 org + agent 的允许列表;后续相同 product 可自动同意支付。

Gift credits 只能用于平台自身消费,不能用于 merchant 订单。Trade API 订单只会扣 buyer org 的 recharge credits。

7. 处理回调

订单支付成功或用户取消时,Brazosd 会 POST JSON 到商户 callback URL。Brazosd 对回调做 Ed25519 签名:

Headers:

text
X-Brazosd-Callback-Key-Id: <callback_key_uuid>
X-Brazosd-Callback-Timestamp: <unix_seconds>
X-Brazosd-Callback-Signature: <base64_signature>

回调签名 canonical string 同样是:

text
METHOD
REQUEST_URI
TIMESTAMP
BODY

校验示例:

python
from base64 import b64decode
from cryptography.hazmat.primitives.asymmetric import ed25519

def verify_brazosd_callback(method, request_uri, body_bytes, timestamp, signature_b64, public_key_b64):
    public_key = ed25519.Ed25519PublicKey.from_public_bytes(b64decode(public_key_b64))
    canonical = (
        method.upper().encode()
        + b"\n"
        + request_uri.encode()
        + b"\n"
        + timestamp.encode()
        + b"\n"
        + body_bytes
    )
    public_key.verify(b64decode(signature_b64), canonical)

商户服务应按 eventIdorder.id + order.status 做幂等处理。

回调失败时,Brazosd 每 30 分钟重试一次任务;每次任务会连续尝试最多 3 次,间隔 5 秒。Brazosd 会保留每个 callback URL 最近一次失败信息,即使之后成功也不会删除失败记录,只会更新最近成功时间。