创建订单
创建一个新的支付订单。此接口使用请求头 HMAC 签名。
接口
POST /v4.0.0/api/orders/create请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
accessKeyId | string | 是 | 您的商户 Access Key ID |
merchantOrderId | string | 是 | 您的订单标识符,在(链 + 商户 + 渠道)范围内唯一 |
merchantChannel | string | 否 | 商户渠道,默认为 default |
blockChain | string | 是 | 区块链名称(如 ETH、TRON、BSC、POLYGON),大小写不敏感 |
tokenSymbol | string | 是 | 代币符号(如 usdt、usdc) |
amount | string | 是 | 支付金额,十进制字符串(如 "10.50"),最多精确到小数点后 2 位 |
splitterAddress | string | 是 | 您的分账合约地址,必须处于已激活状态且属于该商户 |
subject | string | 否 | 订单主题 / 描述 |
expireDuration | integer | 否 | 过期时长(秒),默认 172800(48 小时),上限 259200(72 小时) |
callbackUrl | string | 否 | 前端自定义跳转链接,不传则以 api key 配置的 callbackUrl 为准 |
remark | string | 否 | 订单备注 |
extra | string | 否 | 订单额外信息 |
param1 | string | 否 | 订单额外参数 1 |
param2 | string | 否 | 订单额外参数 2 |
WARNING
请求体里没有 notifyUrl。后端通知地址是 api key 上的配置,创建订单时无法逐笔覆盖; 只有 callbackUrl(前端跳转)可以逐笔指定。两者方向相反,详见 Notify URL 与 Callback URL 的区别。
NOTE
merchantOrderId 的唯一性是按 (链 + 商户地址 + 商户渠道) 判定的, 所以同一个 merchantOrderId 可以在不同链上各存在一笔订单。
请求示例
json
{
"accessKeyId" : "01K...BB",
"merchantOrderId" : "aaf..-8",
"merchantChannel" : null,
"blockChain" : "ETH",
"tokenSymbol" : "usdt",
"amount" : "0.05",
"splitterAddress" : "0xfd5...f8b",
"subject" : "Test Order - API Doc",
"remark" : null,
"param1" : null,
"param2" : null,
"callbackUrl" : null,
"extra" : null,
"expireDuration" : 60000,
"payWebType" : null
}响应示例
json
{
"code" : 0,
"msg" : "success",
"ui" : null,
"version" : null,
"count" : 0,
"data" : {
"merchantAddress" : "0x17a...42",
"merchantChannel" : "default",
"blockChain" : "ETH",
"tokenSymbol" : "usdt",
"createChannel" : 1,
"merchantOrderId" : "aaf..-8",
"payOrderId" : "01K...H8",
"tokenAddress" : "0xdac17f958d2ee523a2206206994597c13d831ec7",
"receiptAddress" : "0x5...c4",
"amount" : 0.05,
"state" : 0,
"accessSign" : "AA377....F5",
"rate" : 80,
"obtainAmount" : 0.0496,
"platformFee" : 4.0E-4,
"expireDuration" : "60000",
"underPaid" : false,
"paidAmount" : 0.0,
"createTime" : 1785753243948,
}
}NOTE
data 里未赋值的字段会以 null 返回(如 payTxId、param1、errorMsg),上面的示例为可读性省略了它们。 另外 expireDuration、confirmCount、chainId、eip712ChainId 是 JSON 字符串而不是数字—— 服务端把 Java 的 long / Long 统一序列化成字符串,避免 JavaScript 超过 2^53 丢精度。
响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
code | integer | 0 表示成功,非零表示错误 |
msg | string | 可读的消息文本 |
data.merchantAddress | string | 部署分账合约的商户地址 |
data.merchantChannel | string | 商户下单渠道,如果入参为空,则返回默认的default |
data.blockChain | string | 区块链名称(如 ETH、TRON、BSC、POLYGON) |
data.tokenSymbol | string | 代币符号(如 usdt、usdc) |
data.createChannel | integer | 下单渠道,0 = 通过商户系统下单,1 = 通过 api key 下单 |
data.merchantOrderId | string | 商户下单时填入的商户订单号 |
data.payOrderId | string | HashNut 生成的唯一订单ID(26 位 ULID) |
data.tokenAddress | string | 支付订单的 token 合约地址,比方说: USDT的合约地址 |
data.receiptAddress | string | 订单收款地址,客户支付订单时需要发送 token 到该地址 |
data.amount | number | 订单应付金额 |
data.state | integer | 订单状态(0 = INIT)。参见订单状态 |
data.accessSign | string | 后续查询 / 确认订单必须回传的凭证,请落库保存 |
data.rate | integer | 手续费率,除以 rateBase 得到实际比率 |
data.obtainAmount | number | 扣除平台手续费后商户实收金额 |
data.platformFee | number | 平台手续费,商户提现时才会收取 |
data.expireDuration | string | 过期时长(秒) |
data.underPaid | bool | 订单是否被短款支付,如果用户未支付该状态为false,如果用户支付金额不足,则该字段为true,用户补款足额支付后该字段为true |
data.paidAmount | number | 用户已经支付的金额 |
data.createTime | date | 订单创建时间 |
TIP
请在您的系统中同时保存 payOrderId、merchantOrderId 和 accessSign。 accessSign 是服务端用 secretKey 对 payOrderId + merchantOrderId 做的 HMAC, 客户端无法自行重算,而查询订单和确认支付都要求带上它。
跳转支付页URL
订单创建后,跳转到支付页面的URL格式如下:
https://defi.hashnut.io/pay?accessSign=${accessSign}&merchantOrderId=${merchantOrderId}&payOrderId=${payOrderId}&blockChain=${blockChain}&payApiVersion=v4返回码
业务错误不使用独立的错误码段,统一通过 code + msg 返回,具体原因看 msg:
code | 说明 |
|---|---|
0 | 成功 |
-1 | 失败 |
-2 | 异常(参数校验失败、业务规则不满足等,msg 为具体原因) |
-3 | 未授权 |
-4 | 未认证 |
创建订单时常见的 msg:
msg | 含义 |
|---|---|
can not find api key by accessKeyId[...] | accessKeyId 不存在,或不是 api key 类型 |
invalid request sign | 签名不匹配,见认证签名 |
request timestamp out of allowed window, ... | 时间戳超出 ±5 分钟窗口,通常是机器时钟不准 |
duplicate request uuid, replay rejected | hashnut-request-uuid 复用了 |
client ip [...] not allowed | 出口 IP 不在 api key 的 bindIp 白名单里 |
coin not support / chain not support | 该链或该币种未开通 |
merchant order id already exist | 同链 + 同商户 + 同渠道下 merchantOrderId 重复 |
eoa splitter address not active | 分账合约未激活,或不属于该商户 |
the minimum unit of the amount is 0.01 | amount 小数位超过 2 位 |
max expire duration is 259200 | expireDuration 超过 72 小时 |