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

POST /apiv2/withdraw ​

从您的 Netts 余额提取 TRX 至任意 TRON 地址。该请求会立即返回订单号;实际的链上出款由后台异步执行(约 5 分钟内)。可通过轮询状态端点或配置 webhook 来跟踪结果。

ℹ️ 运作方式。 发起提现会立即从您的余额中预扣对应金额(订单被接受的瞬间即扣除余额)。随后后台守护进程会发送 TRX 并将订单标记为 completed 或 failed。初始响应中没有同步的链上结果——您首先收到的始终是 pending 确认。

端点 URL ​

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

请求头 ​

请求头必填描述
Content-Type是application/json
X-API-KEY是来自 Netts 控制台的 API 密钥
X-Real-IP是来自您白名单中的 IP 地址
X-Idempotency-Key否可选的客户端生成密钥(base64),用于安全重试以避免重复提现。如果省略,服务器将自动派生一个。该值将作为您的 orderId。

请求体 ​

json
{
    "amount": 15,
    "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

参数 ​

参数类型必填描述
amount浮点数是TRX 总金额(最低 3)。手续费将从此金额中扣除——收款人收到 amount − fee(net)。
address字符串是目标 TRON 地址(T…,34 个字符,base58)。
sub_and_robot_out布尔值否机器人/子账户出款模式:收取 2 TRX 手续费而非 1 TRX。默认 false。

手续费。 固定手续费从总 amount 中扣除:通常为 1 TRX,当 sub_and_robot_out = true 时为 2 TRX。如果 amount − fee ≤ 0,订单将被拒绝。

请求示例 ​

以下示例还会构建并发送 X-Idempotency-Key,因此意外的重复请求不会导致二次提现。完整规则请参见幂等性。

cURL ​

bash
API_KEY="your_api_key"
ADDR="TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AMOUNT=15
NONCE=$(( $(date +%s) / 2 ))   # stable for retries within a 2s window; or your own order UUID

# X-Idempotency-Key = base64url( HMAC-SHA256( API_KEY, "addr:amount:nonce" ) )
IDEMP=$(printf '%s' "${ADDR}:${AMOUNT}:${NONCE}" \
  | openssl dgst -sha256 -hmac "$API_KEY" -binary | basenc --base64url | tr -d '=')

curl -X POST https://netts.io/apiv2/withdraw \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: $API_KEY" \
  -H "X-Real-IP: your_whitelisted_ip" \
  -H "X-Idempotency-Key: $IDEMP" \
  -d "{\"amount\": $AMOUNT, \"address\": \"$ADDR\"}"

Python ​

python
import time, hmac, hashlib, base64, requests

API_KEY = "your_api_key"
url = "https://netts.io/apiv2/withdraw"
payload = {"amount": 15, "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}

# X-Idempotency-Key = base64url( HMAC-SHA256( API_KEY, "addr:amount:nonce" ) ), padding stripped.
# Generate ONCE per order and resend the same value on every retry.
nonce = str(int(time.time() // 2))   # 2s bucket; or your own order UUID
message = f"{payload['address']}:{payload['amount']}:{nonce}"
idem_key = base64.urlsafe_b64encode(
    hmac.new(API_KEY.encode(), message.encode(), hashlib.sha256).digest()
).decode().rstrip("=")

headers = {
    "Content-Type": "application/json",
    "X-API-KEY": API_KEY,
    "X-Real-IP": "your_whitelisted_ip",
    "X-Idempotency-Key": idem_key,
}

resp = requests.post(url, headers=headers, json=payload)
detail = resp.json().get("detail", {})

if resp.status_code == 202 and detail.get("status") == "pending":
    d = detail["data"]
    print(f"Order ID: {d['orderId']}")            # use it for the status endpoint / webhook
    print(f"Net to recipient: {d['net']} TRX (fee {d['fee']})")
else:
    print(f"Code {detail.get('code')}: {detail.get('msg', detail)}")

响应 ​

已接受 — 提现已排队 (202 Accepted) ​

金额已从您的余额中预扣,出款已加入调度。请轮询状态端点(或等待 webhook),直到状态变为 completed / failed。

json
{
    "detail": {
        "code": 10000,
        "status": "pending",
        "msg": "Withdrawal request accepted, processing within 5 minutes.",
        "data": {
            "orderId": "EXAMPLEorderId0000000000000000000000000000Aa",
            "amount": 15.0,
            "fee": 1.0,
            "net": 14.0,
            "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
    }
}

响应字段 ​

字段类型描述
detail.code整数10000 已接受
detail.status字符串pending
detail.data.orderId字符串订单号 — 43 个字符的 URL 安全字符串。可用于状态端点,并在 webhook 负载中标识订单。
detail.data.amount浮点数请求的总金额 (TRX)
detail.data.fee浮点数扣除的手续费(1 或 2 TRX)
detail.data.net浮点数收款人收到的金额(amount − fee)
detail.data.address字符串目标地址

状态端点 ​

GET https://netts.io/apiv2/withdraw/status/{orderId}

请求头:X-API-KEY + X-Real-IP(订单必须属于经过身份验证的用户)。 orderId 是 URL 安全的 — 原样传递即可,无需 URL 编码。

订单状态HTTPcodestatus
已完成(TRX 已发送)20010000completed(附带 processed_at)
排队中 / 发送中20010001pending
失败2005003failed(附带 error_message)
未找到 / 非本人订单404-1—
json
{
    "detail": {
        "code": 10000,
        "status": "completed",
        "data": {
            "orderId": "EXAMPLEorderId0000000000000000000000000000Aa",
            "amount": 15.0, "fee": 1.0, "net": 14.0,
            "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "processed_at": "2026-01-01 00:00:00+00:00"
        }
    }
}

子用户账户 ​

子用户提现的运作方式与普通用户完全一致 — 仅需使用子用户自己的 API 密钥。 子用户调用相同的 POST /apiv2/withdraw 端点,使用其自身的密钥进行身份验证;提现将从该子用户自身的余额中扣除,并发送至请求指定的任意 address。最低限额相同,手续费相同(1 TRX),流程相同。没有单独的子用户端点 — 每个账户(主账户或子用户)始终只能使用自己的密钥提取自己的余额。

Webhooks ​

无需轮询,只需配置一次 webhook,当您的每笔提现达到最终状态(completed / failed)时,Netts 就会 POST 发送一条签名通知。Webhook 按每个用户独立存储,并适用于该账户的提现。如果未配置 webhook,只需轮询状态端点即可。

配置 / 查看 / 删除 ​

POST   https://netts.io/apiv2/withdraw/webhook      # create or update
GET    https://netts.io/apiv2/withdraw/webhook      # view current config (secret is never returned)
DELETE https://netts.io/apiv2/withdraw/webhook      # unsubscribe

请求头:X-API-KEY + X-Real-IP。

json
// POST body
{
    "callback_url": "https://your-server.example/netts/withdraw-hook",
    "secret": "your_shared_secret_min_8_chars",
    "enabled": true
}
参数类型必填描述
callback_url字符串是接收 POST 请求的 http(s) URL(≤ 2048 字符)
secret字符串是用于对每个负载进行签名的共享密钥(8…256 字符)
enabled布尔值否在不删除配置的情况下开启/关闭推送。默认 true

GET 返回 { callback_url, enabled, secret_set, updated_at } — 密钥本身绝不会返回。

推送负载 ​

Netts 将向您的 callback_url 发送一个 POST 请求,带有请求头 X-Netts-Signature: base64( HMAC-SHA256( secret, raw_body ) ) 以及以下 JSON 请求体:

json
{
    "orderId": "EXAMPLEorderId0000000000000000000000000000Aa",
    "status": "completed",
    "amount": 15.0,
    "fee": 1.0,
    "net": 14.0,
    "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "processed_at": "2026-01-01 00:00:00+00:00",
    "error_message": null
}
  • status 为 completed 或 failed(为 failed 时,将填充 error_message)。

验证签名 ​

签名是基于请求体的规范 JSON 计算的:键名排序,无空格(separators=(",", ":"))。请以相同方式重新计算并对比。

python
import hmac, hashlib, base64, json

def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
    expected = base64.b64encode(
        hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()
    ).decode()
    return hmac.compare_digest(expected, signature_header)

# Flask example: verify against the EXACT bytes received, then parse.
# if verify(request.get_data(), request.headers["X-Netts-Signature"], SECRET): ...

请始终针对接收到的原始字节进行验证。如果您重新序列化已解析的 JSON,请还原规范形式:json.dumps(payload, ensure_ascii=False, separators=(",",":"), sort_keys=True)。

推送保证 ​

  • 请响应 HTTP 2xx 以进行确认。任何其他响应(或超时)都将被视为推送失败。
  • 每个订单最多尝试 3 次,时间窗口为订单创建起 21 分钟内(重试退避间隔约为 5 分钟)。超过该时间后将放弃推送 — 请回退至状态端点。
  • 推送会进行去重:每个订单最多成功推送一次。
  • 请确保您的处理程序基于 orderId 实现幂等。

错误响应 ​

认证错误 (401) ​

json
{ "detail": { "code": -1, "msg": "Invalid API key or IP not in whitelist" } }

余额不足 (403) ​

json
{ "detail": { "code": 1004, "status": "failed", "msg": "Insufficient balance: 2.0 < 15 TRX" } }

存在未完成的提现 (409) ​

您在自己的余额上一次只能有一笔进行中的提现。请等待当前提现处理完毕。

json
{ "detail": { "code": 4090, "status": "failed", "msg": "You have a pending withdrawal. Wait until it is processed." } }

校验错误 (400) ​

json
{ "detail": { "code": 5004, "status": "failed", "msg": "Minimum withdrawal is 3 TRX" } }

错误代码参考 ​

代码描述HTTP 状态码
10000已接受(提现已排队) / 已完成(状态端点)202 / 200
10001挂起 — 排队中或发送中(状态端点)200
208重复的已接受请求 — 返回缓存的响应208
-相同请求仍在处理中(暂勿重试)409
4090您已有一笔进行中的提现409
-1无效的 API 密钥 / IP 不在白名单中,或订单未找到401 / 404
1004余额不足403
5004校验错误(金额 < 3、手续费 ≥ 金额、地址错误、幂等键错误)400
5003提现失败 / 服务不可用200 (状态) / 503
5000服务器内部错误500

速率限制 ​

按每个 API 密钥限制(请求头 X-API-KEY):

周期限制
1 秒5 次请求
1 分钟150 次请求

超出速率限制 (429) ​

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

幂等性 ​

发送可选的 X-Idempotency-Key 请求头,以确保意外的重复请求不会创建第二笔提现 — 系统将返回原始响应,HTTP 状态码为 208。如果未发送该请求头,服务器将在短时间窗口内根据您的请求参数自动派生一个密钥。该密钥同时也是您的 orderId。

如何构建密钥 ​

该密钥为 base64url( HMAC-SHA256( secret, message ) ) 并去除 = 填充 — 一个 43 字符的 URL 安全字符串,其中:

  • secret = 您的 API 密钥(X-API-KEY);
  • message = 以 : 连接的字段 — address:amount:nonce。

nonce 是任何在同一逻辑订单的多次重试间保持不变、但在不同订单间互不相同的值 — 例如您为该订单维护的 UUID,或粗粒度的时间戳分桶。每个订单生成一次该密钥,并在每次重试时重新发送完全相同的值。

python
import hmac, hashlib, base64, time

def make_idempotency_key(api_key, address, amount, nonce=None):
    if nonce is None:
        nonce = str(int(time.time() // 2))   # 2-second bucket; or your own order UUID
    message = f"{address}:{amount}:{nonce}"
    digest = hmac.new(api_key.encode(), message.encode(), hashlib.sha256).digest()
    return base64.urlsafe_b64encode(digest).decode().rstrip("=")  # 43-char URL-safe

格式校验。 传入的 X-Idempotency-Key 必须为 16–64 个字符,字符集限于 A–Z a–z 0–9 + / = _ -。格式错误或超长的密钥将被拒绝,并返回 HTTP 400(code 5004)。

状态码含义
202已接受(首次请求)
208已接受 — 返回缓存的响应(不会产生二次提现)
409相同请求正在处理中 — 请等待,暂勿重试

失败后重试。 只有已接受的结果才会被缓存。如果上一次尝试失败(例如余额不足、参数校验错误),您可以安全地使用相同密钥重试 — 系统将重新尝试该请求,而不是返回旧的错误。当一次尝试仍在处理中时,您会收到 409;请等待后再重试。

注意事项 ​

  • 异步出款。 响应始终为 pending 确认;TRX 由后台守护进程发送,通常在 5 分钟内完成。请使用状态端点或 webhook 获取结果。
  • 余额立即预扣: 在订单被接受时立即预扣(而非最终发送 TRX 时)。
  • 最低限额:3 TRX。手续费:1 TRX(或使用 sub_and_robot_out 时为 2 TRX),从总 amount 中扣除;收款人收到 net = amount − fee。
  • 同一时间仅限一笔进行中的提现挂在您自己的余额下(code 4090)。
  • 子用户提现机制与普通用户完全一致 — 相同的 POST /apiv2/withdraw 端点,相同的规则,但使用子用户自己的 API 密钥进行身份验证。子用户将其自身的余额提取至其指定的任意 address。不存在单独的子用户端点。
  • orderId 为 43 字符的 URL 安全字符串;在状态查询 URL 中原样传递(无需编码)。
  • Webhooks:按用户独立配置,使用 X-Netts-Signature 进行签名;在 21 分钟窗口内最多重试 3 次。通过 POST /apiv2/withdraw/webhook 配置。