POST /apiv2/order1h
通过多个能量供应商创建 1 小时能量租赁订单,支持自动故障转移。
端点 URL
POST https://netts.io/apiv2/order1h请求标头
| Header | Required | Description |
|---|---|---|
| Content-Type | 是 | application/json |
| X-API-KEY | 是 | 来自 Netts 控制面板的 API 密钥 |
| X-Real-IP | 是 | 来自白名单的 IP 地址 |
请求体
{
"amount": 131000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}请求参数
| Parameter | Type | Required | Description |
|---|---|---|---|
| amount | integer | 是 | 租赁的 Energy 数量(最小值:61000,最大值:3000000) |
| receiveAddress | string | 是 | 接收能量的 TRON 地址(TRC-20 格式) |
供应商选择
API 会根据以下条件自动选择最佳能量供应商:
- 成本效益 - 始终寻找最低可用价格
- 可用性 - 确保充足的能量储备
- 可靠性 - 使用成功率高的供应商
- 速度 - 优先考虑交付时间最快的供应商
示例
cURL
curl -X POST https://netts.io/apiv2/order1h \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip" \
-d '{
"amount": 131000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}'Python
import requests
url = "https://netts.io/apiv2/order1h"
headers = {
"Content-Type": "application/json",
"X-API-KEY": "your_api_key",
"X-Real-IP": "your_whitelisted_ip"
}
payload = {
"amount": 131000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}
response = requests.post(url, headers=headers, json=payload)
data = response.json()
if response.status_code == 200:
detail = data.get('detail', {})
order_data = detail.get('data', {})
print(f"Order ID: {order_data.get('orderId')}")
print(f"Transaction Hash: {order_data.get('hash')}")
print(f"Energy Delivered: {order_data.get('energy')}")
print(f"Cost: {order_data.get('paidTRX')} TRX")
print(f"Delegate Address: {order_data.get('delegateAddress')}")
else:
error_detail = data.get('detail', data)
print(f"Error Code: {error_detail.get('code', 'N/A')}")
print(f"Error Message: {error_detail.get('msg', error_detail)}")响应
成功响应 (200 OK)
{
"detail": {
"code": 10000,
"msg": "Successful, 2.23 TRX deducted",
"data": {
"orderId": "1H123456",
"paidTRX": 2.23,
"hash": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456",
"delegateAddress": "TNp5gsJhBmZFXgCdgjMgr8pEZ8fHgXUHDq",
"energy": 131050
}
}
}响应字段
| 字段 | Type | Description |
|---|---|---|
| detail.code | integer | 成功订单始终为 10000 |
| detail.msg | string | 包含扣费金额的成功消息 |
| detail.data.orderId | string | 统一订单 ID(格式:1H{request_id}) |
| detail.data.paidTRX | number | TRX 总费用(若地址未激活,则包含激活费) |
| detail.data.hash | string | null | 交易哈希。该字段始终存在但可能为空 - 部分供应商不会立即返回哈希。1 分钟后使用 /apiv2/order_check 获取哈希 |
| detail.data.delegateAddress | string | 代理能量的资源池地址 |
| detail.data.energy | integer | 能量数量 + 缓冲(通常为 +50) |
错误响应
认证错误 (401)
{
"detail": "Invalid API key or IP not in whitelist"
}余额不足 (403)
{
"code": 1004,
"msg": "Insufficient funds. Required: 2.23 TRX, Available: 1.50 TRX"
}服务不可用 (503)
{
"code": 5003,
"msg": "Service temporarily unavailable. All energy providers are currently unavailable."
}供应商错误 (503)
{
"code": 5001,
"msg": "Energy provider temporarily unavailable"
}{
"code": 5002,
"msg": "Energy provider temporarily unavailable"
}{
"code": 5004,
"msg": "Energy provider requires higher minimum amount"
}内部服务器错误 (500)
{
"code": 5000,
"msg": "Internal server error occurred"
}错误代码参考
| 代码 | Description | HTTP 状态码 |
|---|---|---|
10000 | 成功 | 200 |
10000 | 成功(缓存响应) | 208 |
- | 重复请求仍在处理中 | 409 |
1004 | 余额不足 | 403 |
5000 | 内部服务器错误 | 500 |
5001 | 能量供应商不可用 | 503 |
5002 | 能量供应商不可用 | 503 |
5003 | 能量服务不可用 | 503 |
5004 | 未达到能量供应商最低数量要求 | 503 |
速率限制
以下速率限制适用于此端点(按 IP 地址):
| 周期 | 限制 | Description |
|---|---|---|
| 1 秒 | 50 次请求 | 每秒最多 50 次请求 |
速率限制响应头
RateLimit-Limit: 50
RateLimit-Remaining: 49
RateLimit-Reset: 1
X-RateLimit-Limit-Second: 50
X-RateLimit-Remaining-Second: 49超出速率限制 (429)
{
"message": "API rate limit exceeded"
}幂等性
API 支持幂等性以防止重复处理订单。当您发送多个相同请求时,系统可确保订单仅被处理一次。
幂等性工作原理
请求的唯一性由以下组合决定:
- 请求时间戳(1 秒窗口)
- 能量数量
- 接收地址
- API 密钥
每个请求都有一个 1 秒的唯一性窗口。为保护系统免遭滥用并确保正确处理,具有相同参数的请求每秒发送频率不能超过一次。
**当前行为:**系统会自动保护客户端免于对已订购的能量进行错误重试。如果您不小心发送了两次相同的请求,您不会被重复扣费。
提供您自己的密钥
您可以通过发送 X-Idempotency-Key 请求头来完全掌控幂等性。当该请求头存在时,仅凭该值决定请求是否重复,上述自动组合将不再使用。当其缺失时,行为保持不变 —— 服务器会为您自动派生密钥。
| 请求头 | X-Idempotency-Key |
| 格式 | 严格为 64 位小写十六进制字符 —— SHA-256 摘要 |
| 有效期 | 自携带该密钥的首次请求起 24 小时 |
| 作用域 | 您的账户。不同账户发送的相同值绝不会返回您的结果 |
任何其他格式的密钥 —— 带连字符的 UUID、base64、大写十六进制 —— 都会在下单前以及发生任何扣费前被拒绝并返回 400:
{
"detail": "Invalid idempotency key format. Must be 64-character hexadecimal string."
}该格式与其他端点不同。
/apiv2/withdraw、/apiv2/bandwidth以及编排器接受 16–64 字符的 base64 密钥。此端点仅接受 64 字符的十六进制摘要,因此从这些端点复制的密钥构建代码在此处将返回 400。
如何生成密钥
从您的 API 密钥派生它。这使得该值对您的账户是唯一的,在重试时可重现,并且任何其他人都无法推导得出:
import hashlib
import hmac
def make_idempotency_key(api_key: str, address: str, amount: int, nonce: str) -> str:
message = f"{address}:{amount}:{nonce}"
return hmac.new(api_key.encode(), message.encode(), hashlib.sha256).hexdigest()**
nonce属于订单,而非请求。**在您端创建订单时仅选取一次,并在每次发送该订单时传递相同的该值 —— 首次尝试和每次重试皆是如此。在发送函数内部生成新值(每次调用时执行str(uuid.uuid4()))会使每次尝试具有不同的密钥,因此超时后的重试会被当作第二个订单接受并再次扣费。最简单正确的选择是您已有的订单 ID:它在首次尝试前即已存在,且在您的进程重启后依然保留。
# 当订单在您的系统中出现时执行一次
order = create_order(address="TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE", amount=131000)
# 首次尝试和每次重试时 —— 相同的三个输入,相同的密钥
key = make_idempotency_key(API_KEY, order.address, order.amount, order.id)
headers = {
"Content-Type": "application/json",
"X-API-KEY": API_KEY,
"X-Idempotency-Key": key,
}密钥有效期为 24 小时。此后相同的 nonce 再次空闲并开启新订单。
请勿使用任何其他人都可以推导得出的值 —— 例如 64 个零、固定单词的摘要。所有账户共享同一密钥空间。此类冲突绝不会暴露其他账户的订单,但您的请求将被拒绝并返回 409,直到其密钥过期为止,这并不是您在重试过程中希望得到的应答。
提交两个相同的订单
有时您确实希望提交两个相同的订单 —— 先后向同一地址发送相同数量的能量。自动密钥无法将其与重试区分开来:两个请求逐字节完全相同,区分它们的唯一依据是它们到达的时刻。
如果没有您自己的密钥,结果取决于它们之间的时间间隔:
| 两次请求之间的间隔 | 会发生什么 |
|---|---|
| 在同一 1 秒窗口内 | 第二个请求被视为重复。它不会被执行:您将收到 208 以及首个订单的响应,包括 orderId。不会对其进行任何扣费 |
| 间隔超过一秒 | 两个不同的密钥 —— 两个订单均被创建且均被扣费 |
因此,如果您依赖自动密钥,请在两个相同的订单之间留出超过一秒的间隔,并读取状态码:208 意味着您刚刚发送的订单未被创建。
暂停等待只是一种变通方案,而非彻底的解决方案。它会隔离每个请求,包括那些您从未打算重复的请求 —— 超时后的重试、连击、队列重新投递的消息。这些也会晚于窗口到达,因此它们会被作为单独的订单创建并单独扣费。此端点的响应超时时间为 10 秒,已经远远超出该窗口:自动密钥无法保护超时后的重试。
您自己的密钥消除了这种不确定性,因为决定权转移到了唯一知晓答案的一方:
| 您的操作 | 您发送的内容 | 结果 |
|---|---|---|
| 第二个真正的全新订单 | 新的 nonce | 新密钥 —— 订单被创建 |
| 重试未知结果的订单 | 首次尝试的 nonce | 相同密钥 —— 208,原始响应,无二次扣费 |
第二行是该请求头存在的原因,也是实现中最容易出错的地方:参见如何生成密钥下的说明。
重复请求的 HTTP 状态码
| 状态码 | 名称 | Description |
|---|---|---|
| 200 | OK | 订单处理成功(首次请求) |
| 208 | Already Reported | 订单已处理,返回缓存响应 |
| 409 | Conflict | 请求正在处理中,请勿重试 |
重复请求 - 已处理 (208)
当收到已完成订单的重复请求时:
{
"detail": {
"code": 10000,
"msg": "Successful, 2.54 TRX deducted",
"data": {
"hash": "9e4c20e21e01e4c39b21b670d1ea1fc1e4b0de94d8fbd4c190d5378ba911dfae",
"energy": 65050,
"orderId": "1H70bcc7962a",
"paidTRX": 2.535,
"delegateAddress": "TNp5gsJhBmZFXgCdgjMgr8pEZ8fHgXUHDq"
}
},
"idempotency": {
"status": "completed",
"cached": true,
"original_created_at": "2025-12-03T10:34:49.104896"
}
}响应体与原始成功响应完全相同,并附带一个额外的 idempotency 对象,表明这是缓存响应。
重复请求 - 仍在处理中 (409)
当原始请求仍在处理中而收到重复请求时:
{
"success": false,
"error": "duplicate_request_processing",
"message": "This request is currently being processed. Please wait and do not retry.",
"idempotency_key": "b9e67b2412d33c92a4f0e1c3d5b7a9f2e4c6d8b0a2f4e6c8d0b2a4f6e8c0d2b4",
"retry_after_seconds": 3
}**建议:**在检查订单状态前,等待指定的 retry_after_seconds 秒。
最佳实践
- 请勿使用相同参数发送并发请求 - 等待每次响应
- 为每个新订单使用新的
nonce,并对其每次重试使用首次尝试的nonce - 绝不要在发送时重新构建
nonce— 重试必须复现首次尝试的密钥,而不是生成新密钥 - 通过等待处理 409 响应,而不是立即重试
- 检查
idempotency.cached字段以识别缓存响应 —208意味着您刚刚发送的订单未被创建
后付费账户
采用后付费结算的账户使用与其他账户相同的端点、URL、请求头和请求体。区别在于订单的支付方式:
- 不会从您的押金中扣除任何费用。每个成功的订单都将计入您账户在合同约定结算货币下的应付余额。您根据协议按发票进行支付。
- 您的账户拥有授信额度。只要应付金额在额度范围内,即使押金为零也会接受订单。
- 仅对已交付的服务进行计费。被拒绝或未执行的订单不收取任何费用。
- 如果接收地址需要激活,激活是同一订单的一部分,并作为单独费用计入账单。
Netts 可根据申请为账户开启后付费结算。每个响应都会告知您订单的支付方式:paymentMode 为 postpaid 或 prepaid。
额外请求字段
| Parameter | Type | Required | Description |
|---|---|---|---|
| test | boolean | 否 | true — 仅计算价格。不进行任何下单、交付或扣费 |
| freezePrice | boolean | 否 | true — 在您的合同下锁定价格 60 秒。不进行任何下单或扣费 |
| quoteId | string | 否 | 按照 freezePrice 签发的报价单价格进行下单 |
| priceCurrency | string | 否 | TRX(默认)或您合同的结算货币,同 settlement.asset。对于后付费账户,始终包含以您的合同货币计价的金额 |
quoteId 不能与 test 或 freezePrice 结合使用。请求体中的任何其他字段都将被拒绝。
价格查询 (test: true)
{
"amount": 65000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
"test": true
}{
"detail": {
"code": 10010,
"msg": "Test calculation",
"data": {
"amount": 65000,
"unitPriceSun": "20",
"discount": null,
"energyTRX": "1.300000",
"activationTRX": "1.100000",
"wouldCostTRX": "2.400000",
"paidTRX": 0,
"paymentMode": "postpaid",
"activationCheck": "inactive",
"alt": {"USDC": {"energy": "0.430541", "activation": "0.364304", "total": "0.794845"}},
"fxAt": "2026-10-19T07:15:18.469870+00:00"
}
}
}| 字段 | Description |
|---|---|
| unitPriceSun | 每单位能量以 SUN 计价的价格,包含您的个人折扣(若有) |
| discount | 您的个人折扣(type, value)或 null |
| energyTRX / activationTRX / wouldCostTRX | 能量费、激活费(如果地址需要)和总计,以 TRX 计价 |
| activationCheck | inactive — 地址将被激活并计费;active — 无需激活;unknown — 当前无法检查 |
alt.<currency> | 以您的合同货币计价的相同金额 |
| fxAt | 合同货币金额所采用的汇率时间 |
固定价格报价 (freezePrice: true)
在下单前使用报价锁定您合同下的价格。
- 发送带有
"freezePrice": true的订单请求。响应代码为10011(Quote issued),包含与价格查询相同的字段,外加quoteId和expiresAt。 - 在 60 秒 内发送带有
"quoteId": "<quoteId>"以及相同的amount和receiveAddress的订单。 - 订单按报价单价格(即报价时的合同价格)进行结算,即使中间价格发生变动。
报价仅可使用一次,且仅适用于同一产品:1 小时报价不可用于支付 5 分钟订单。过期或已使用的报价将被拒绝,且不会创建任何订单。
{
"amount": 65000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
"quoteId": "q_4f540f16a2c94b7f8e3d1a6b5c0e9d72"
}成功订单
{
"detail": {
"code": 10000,
"msg": "Successful, 1.30 TRX for energy + 1.10 TRX for address activation, postpaid",
"data": {
"orderId": "1Hf9544a1508",
"paidTRX": 2.4,
"hash": "032bda8fa6911b42c15a6d8d30520dc22bcc4077972a1503b6a3fae491967eb4",
"delegateAddress": "TVnkj2jHKgmea8DVJFo2teD7rRSpH51bne",
"energy": 65000,
"activationHash": "259e1ab276114ae717a6f62d7d25eb1f89a2dccb637cbe41be626df3c2a78519",
"paymentMode": "postpaid",
"energyTRX": "1.300000",
"activationTRX": "1.100000",
"totalTRX": "2.400000"
}
}
}| 字段 | Description |
|---|---|
| paidTRX | 服务的 TRX 成本。对于后付费账户,不会从押金中扣除 |
| paymentMode | postpaid |
| energyTRX / activationTRX / totalTRX | 精确金额,保留 6 位小数 |
| quoteId, alt | 当订单使用报价下单时出现:报价 ID 及报价金额 |
| activationFinal | 仅当激活金额为预估值时存在且为 false;最终金额将显示在您的发票上 |
所有其他字段与预付费订单相同。
达到授信额度 (402)
{
"detail": {
"code": 1004,
"msg": "Postpaid credit limit reached.",
"paymentMode": "postpaid",
"reason": "limit_reached"
}
}订单未被执行,不计收任何费用。一旦您的付款登记入账或额度上调,将重新接受新订单。
后付费错误代码
| 代码 | HTTP | Description |
|---|---|---|
10010 | 200 | 价格查询结果(test) |
10011 | 200 | 报价已签发(freezePrice) |
1004 | 402 | 达到后付费授信额度 |
4100 | 400 | 无效请求 |
4101 | 400 | 不支持的 priceCurrency |
4102 | 400 | quoteId 与 test 或 freezePrice 同时使用 |
4103 | 409 | 报价已被使用 |
4104 | 409 | 报价已过期 |
4105 | 409 | 幂等性密钥已用于其他请求 |
4106 | 404 | 未找到报价 |
4107 | 409 | 订单参数与报价不一致 |
4108 | 400 | 无效的 quoteId 格式 |
4109 | 422 | 不适用于子账户 |
5032 | 503 | 价格暂时不可用 |
5033 | 503 | 汇率暂时不可用 |
5034 | 503 | 计费服务暂时不可用 — 订单未被接受 |
5036 | 503 | 授信检查暂时不可用 — 请稍后重试 |
对于上述所有 4xx 和 503 响应,不进行任何下单且不收取任何费用。
注意事项
- 订单成功后立即交付能量(通常在 0.5-10 秒内)
- API 响应超时时间:最长 10 秒,通常在 2 秒内响应
- 地址激活:如果接收地址未激活,Netts 将按成本价予以激活
- 激活延迟:对于未激活的地址,由于激活处理过程,API 响应可能需要长达 6 秒
- 全天候 24/7 处理订单,支持供应商自动故障转移
- 最低能量数量:61,000 单位
- 最高能量数量:每笔订单 3,000,000 单位
- 能量缓冲:自动增加 +50 单位用于供应商补偿(免费提供)
- 交易哈希:该字段始终存在,但若供应商未立即返回,则可能为空。如需获取哈希,请在下单后不早于 1 分钟 调用 /apiv2/order_check
- 供应商选择:根据成本和可用性自动选择
- 订单 ID 格式:
1H{request_id},用于统一追踪 - 定价:根据一天中的时间和能量数量动态调整
- 时长:固定 1 小时(3600 秒)
- 速率限制:每个 IP 地址每秒 50 次请求