Skip to content
Translated page. The English version is the source of truth.

POST /apiv2/order1h

通过多个能量供应商创建 1 小时能量租赁订单,支持自动故障转移。

端点 URL

POST https://netts.io/apiv2/order1h

请求标头

HeaderRequiredDescription
Content-Typeapplication/json
X-API-KEY来自 Netts 控制台的 API 密钥
X-Real-IP来自您白名单的 IP 地址

请求体

json
{
    "amount": 131000,
    "receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}

请求参数

ParameterTypeRequiredDescription
amountinteger租赁的 Energy 数量(最小值:61000,最大值:3000000)
receiveAddressstring接收能量的 TRON 地址(TRC-20 格式)

供应商选择

API 根据以下标准自动选择最佳能量供应商:

  • 成本效益 - 始终寻找最低可用价格
  • 可用性 - 确保充足的能量储备
  • 可靠性 - 使用成功率高的供应商
  • 速度 - 优先考虑最快交付时间

示例

cURL

bash
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

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)

json
{
    "detail": {
        "code": 10000,
        "msg": "Successful, 2.23 TRX deducted",
        "data": {
            "orderId": "1H123456",
            "paidTRX": 2.23,
            "hash": "a1b2c3d4e5f6789...",
            "delegateAddress": "TDelegatePoolAddress...",
            "energy": 131050
        }
    }
}

响应字段

字段类型描述
detail.codeinteger成功订单始终为 10000
detail.msgstring包含扣费金额的成功信息
detail.data.orderIdstring统一订单 ID(格式:1H{request_id}
detail.data.paidTRXnumber以 TRX 计的总费用(若地址未激活,则包含激活费)
detail.data.hashstring | null交易哈希。该字段始终存在但可能为空 - 部分供应商不会立即返回哈希。1 分钟后请使用 /apiv2/order_check 获取哈希
detail.data.delegateAddressstring代理能量的池地址
detail.data.energyintegerEnergy 数量 + 缓冲量(通常为 +50)

错误响应

认证错误 (401)

json
{
    "detail": "Invalid API key or IP not in whitelist"
}

余额不足 (403)

json
{
    "code": 1004,
    "msg": "Insufficient funds. Required: 2.23 TRX, Available: 1.50 TRX"
}

服务不可用 (503)

json
{
    "code": 5003,
    "msg": "Service temporarily unavailable. All energy providers are currently unavailable."
}

供应商错误 (503)

json
{
    "code": 5001,
    "msg": "Energy provider temporarily unavailable"
}
json
{
    "code": 5002,
    "msg": "Energy provider temporarily unavailable"
}
json
{
    "code": 5004,
    "msg": "Energy provider requires higher minimum amount"
}

服务器内部错误 (500)

json
{
    "code": 5000,
    "msg": "Internal server error occurred"
}

错误代码参考

代码描述HTTP 状态码
10000成功200
10000成功(缓存响应)208
-重复请求仍在处理中409
1004余额不足403
5000服务器内部错误500
5001能量供应商不可用503
5002能量供应商不可用503
5003能量服务不可用503
5004未达到能量供应商最低要求503

速率限制

以下速率限制适用于此端点(按 IP 地址):

周期限制描述
1 秒50 次请求每秒最多 50 次请求

速率限制响应头

http
RateLimit-Limit: 50
RateLimit-Remaining: 49
RateLimit-Reset: 1
X-RateLimit-Limit-Second: 50
X-RateLimit-Remaining-Second: 49

超出速率限制 (429)

json
{
    "message": "API rate limit exceeded"
}

幂等性

API 支持幂等性,以防止重复处理订单。当您发送多个相同的请求时,系统会确保订单仅被处理一次。

幂等性工作原理

请求的唯一性由以下要素组合决定:

  • 请求时间戳(1 秒窗口)
  • Energy 数量
  • 接收地址
  • API 密钥

每个请求都有一个 1 秒的唯一性窗口。为保护系统免受滥用并确保正常处理,具有相同参数的请求发送频率不得高于每秒一次。

当前行为: 系统会自动保护客户端免受已订购能量的错误重试影响。如果您不小心发送了两次相同的请求,您将不会被重复扣费。

提供您自己的密钥

您可以通过发送 X-Idempotency-Key 请求头来自行控制幂等性。当该请求头存在时,仅凭该值决定请求是否为重复请求,不再使用上述自动组合。当它不存在时,一切照旧——由服务器为您推导密钥。

HeaderX-Idempotency-Key
格式严格为 64 个小写十六进制字符 — SHA-256 摘要
生命周期自携带该密钥的首次请求起 24 小时
作用域您的账户。不同账户发送相同的值绝不会返回您的结果

任何其他形式的密钥(带连字符的 UUID、base64、大写十六进制)都会在下单和扣费之前被拒绝并返回 400

json
{
    "detail": "Invalid idempotency key format. Must be 64-character hexadecimal string."
}

格式与其他端点不同。 /apiv2/withdraw/apiv2/bandwidth 和编排器接受 16–64 个字符的 base64 密钥。此端点仅接受 64 个字符的十六进制摘要,因此从这些端点复制的密钥生成代码在此处将返回 400。

如何生成密钥

从您的 API 密钥派生它。这使得该值对您的账户是唯一的、重试时可复现的,且任何其他人都无法推导得出:

python
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:它在首次尝试之前就已存在,并且在您的进程重启后依然保留。

python
# 一次性生成,当订单在您的系统中出现时
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 状态码

状态码名称描述
200OK订单处理成功(首次请求)
208Already Reported订单已处理,返回缓存响应
409Conflict请求正在处理中,请勿重试

重复请求 - 已处理 (208)

当收到已完成订单的重复请求时:

json
{
    "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)

当在原始请求仍在处理期间收到重复请求时:

json
{
    "success": false,
    "error": "duplicate_request_processing",
    "message": "This request is currently being processed. Please wait and do not retry.",
    "idempotency_key": "b9e67b2412d33c92...",
    "retry_after_seconds": 3
}

建议: 在检查订单状态之前,请等待指定的 retry_after_seconds 秒数。

最佳实践

  • 请勿使用相同参数发送并行请求 - 等待每次响应返回
  • 为每笔新订单使用新的 nonce,并在其每次重试中使用首次尝试的 nonce
  • 绝不要在发送时重新生成 nonce — 重试必须复现首次尝试的密钥,而不是生成新密钥
  • 处理 409 响应的方式是等待,而不是立即重试
  • 检查 idempotency.cached 字段以识别缓存响应 — 208 意味着您刚刚发送的订单未被下达

注意事项

  • 订单成功后立即交付 Energy(通常在 0.5-10 秒内)
  • API 响应超时:最长 10 秒,通常在 2 秒内响应
  • 地址激活:如果接收地址未激活,Netts 将按成本价自动激活
  • 激活延迟:对于未激活的地址,由于激活流程,API 响应可能需要长达 6 秒
  • 订单全天候 24/7 处理,支持供应商自动故障转移
  • 最低 Energy 数量:61,000 单位
  • 最高 Energy 数量:每笔订单 3,000,000 单位
  • Energy 缓冲量:自动额外增加 +50 单位作为供应商补偿(免费提供)
  • 交易哈希:该字段始终存在,但如果供应商未立即返回,可能为空。要获取哈希,请在下单后不早于 1 分钟 调用 /apiv2/order_check
  • 供应商选择:根据成本和可用性自动选择
  • 订单 ID 格式1H{request_id},用于统一跟踪
  • 定价:根据一天中的时间和能量数量动态调整
  • 时长:固定 1 小时(3600 秒)
  • 速率限制:每个 IP 地址每秒 50 次请求