Back to Resources

Open Platform API Reference

Complete API reference for Vuken's open platform. Integrate wallet management, collection tasks, and webhook notifications into your application.

Version: M1  Last updated: 2026-05-25


1 Overview

1.1 Base URL

https://vuken.io/api

1.2 Authentication

All open platform endpoints require a Developer API Token in the HTTP header:

Authorization: Bearer <developer-api-token>

How to obtain a Developer API Token:

  1. Register an account and verify your email
  2. Subscribe to the developer plan via POST /subscriptions/activate (requires Session Token)
  3. Create a Developer API Token via POST /api-tokens (requires Session Token)
  4. Use the returned token for all subsequent open platform requests

Developer API Tokens have ['api:access'] abilities and can only access the endpoints documented here. Account management operations (profile, subscriptions, webhooks, transfers) require a Session Token. Tokens do not expire by default and must be manually revoked via DELETE /api-tokens/{id}.

Example:

curl -X GET https://vuken.io/api/wallets \
  -H "Authorization: Bearer 1|your-developer-api-token-here"

1.3 Response Format

All responses are JSON with a uniform envelope:

Success

{
  "code": "OK",
  "message": "success",
  "data": { ... }
}

Failure

{
  "code": "BIZ-WALLET-ADDRESS-NOT-FOUND",
  "message": "wallet address not found",
  "data": {}
}
FieldDescription
codeOK on success; semantic error code on failure
messageHuman-readable description
dataBusiness payload on success; empty object on failure

1.4 HTTP Status Codes

StatusMeaning
200Success (read / update)
201Resource created
401Unauthenticated — invalid or missing token
403Authenticated but not authorized
404Resource not found
409Conflict (duplicate resource, lock conflict)
422Validation failed or business rule violation
429Rate limit exceeded (includes Retry-After header)
502On-chain operation failed (node or contract error)

1.5 Error Codes

Error CodeModuleDescription
BIZ-NETWORK-NOT-FOUNDWalletNetwork code does not exist or is unavailable
BIZ-ADDRESS-TYPE-NOT-ALLOWEDWalletUnsupported address type value
BIZ-MAIN-ADDRESS-ALREADY-EXISTSWalletMain address already exists for this network
BIZ-MAIN-ADDRESS-REQUIREDWalletMust create main address before sub-address
BIZ-SUB-ADDRESS-SUBSCRIPTION-REQUIREDWalletActive sub-address subscription required
BIZ-SUB-ADDRESS-QUOTA-EXCEEDEDWalletSub-address quota for subscription plan exceeded
BIZ-WALLET-ADDRESS-NOT-FOUNDWalletAddress does not exist or does not belong to current user
BIZ-ASSET-NOT-FOUNDWalletAsset symbol does not exist
BIZ-AMOUNT-INVALIDWalletAmount must be a positive integer string
BIZ-COMMAND-LOCKEDWalletAddress already has an active command in progress
BIZ-COMMAND-NOT-FOUNDWalletCommand number does not exist
CHAIN-BALANCE-QUERY-FAILEDWalletOn-chain balance query failed
BIZ-ADDRESS-TYPE-NOT-SUBCollectionCollection can only be executed on sub-addresses
RISK-REVIEW-BLOCKEDCollectionRequest blocked by risk control
BIZ-COLLECTION-TASK-NOT-FOUNDCollectionCollection task does not exist
CASHIER-TOKEN-ACTIVE-EXISTSCashierAn active cashier token already exists for this address
CASHIER-TOKEN-NOT-FOUNDCashierCashier token not found or does not belong to current user
CASHIER-TOKEN-ALREADY-DISABLEDCashierCashier token is already disabled
CASHIER-TOKEN-MISSINGCashierNo cashier Bearer token provided
CASHIER-TOKEN-INVALIDCashierCashier token is invalid, expired, or disabled
BIZ-AMOUNT-BELOW-MINIMUMCashierBalance is below the minimum collect threshold

1.6 Rate Limits

When a rate limit is exceeded, the API returns 429 with headers:

Retry-After: 60
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
EndpointLimitKey
POST /wallets20/minUser ID
POST /wallets/{address}/balances/refresh20/minUser ID
POST /collections10/minUser ID
POST /cashier/tokens20/minUser ID
DELETE /cashier/tokens/{tokenNo}20/minUser ID
POST /cashier/collect10/minCashier Token
Read endpoints (GET *)60/minUser ID / Cashier Token

1.7 Idempotency

The following mutating endpoints support idempotency to prevent duplicate operations. Include a client-generated UUID in the header:

Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
EndpointRequired
POST /collectionsYes
POST /cashier/collectYes

If the same Idempotency-Key is submitted again within the window, the original response is returned without re-executing the operation.


2 Wallet

2.1 List Wallet Addresses

GET /wallets

Rate limit: 60/min/user

Returns all wallet addresses belonging to the current user. Supports filtering by address type and pagination.

Query Parameters (optional)

ParameterTypeDefaultDescription
typeintegerFilter by type: 1 main address, 2 sub-address; omit for all
pageinteger1Page number (1-based)
per_pageinteger20Items per page (max 100)

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "items": [
      {
        "wallet_address_id": 1,
        "network_code": "TRON",
        "address": "TXyz123...abc",
        "address_type": 1,
        "address_label": "Main Wallet",
        "status": 1,
        "created_at": "2026-05-21 10:00:00"
      },
      {
        "wallet_address_id": 2,
        "network_code": "TRON",
        "address": "TSUB456...def",
        "address_type": 2,
        "address_label": null,
        "status": 1,
        "created_at": "2026-05-21 10:05:00"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 42,
      "pages": 3
    }
  }
}
FieldDescription
wallet_address_idUnique address ID used in other API calls
address_type1 main address, 2 sub-address
status1 active, 0 disabled

2.2 Get Address Details

GET /wallets/{address}

Rate limit: 60/min/user

Path Parameters

ParameterDescription
addressOn-chain wallet address string (e.g. TXyz123...abc)

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "wallet_address_id": 1,
    "network_code": "TRON",
    "address": "TXyz123...abc",
    "address_type": 1,
    "address_label": "Main Wallet",
    "status": 1,
    "created_at": "2026-05-21 10:00:00"
  }
}

Error Responses

HTTPError CodeScenario
404BIZ-WALLET-ADDRESS-NOT-FOUNDAddress not found or does not belong to current user

2.3 Create Wallet Address

POST /wallets

Rate limit: 20/min/user

Creates a new on-chain wallet address. Key pairs are generated server-side; the private key is encrypted with AES-256-GCM and never returned.

Request Body

{
  "network_code": "TRON",
  "address_type": 1,
  "address_label": "Main Wallet"
}
FieldTypeRequiredDescription
network_codestringNetwork code (e.g. TRON)
address_typeinteger1 main address, 2 sub-address
address_labelstringOptional label, max 120 characters

Response 201

{
  "code": "OK",
  "message": "success",
  "data": {
    "wallet_address_id": 42,
    "network_code": "TRON",
    "address": "TXyz123...abc",
    "address_type": 1,
    "status": 1
  }
}

Error Responses

HTTPError CodeScenario
409BIZ-MAIN-ADDRESS-ALREADY-EXISTSMain address already exists for this network
422BIZ-NETWORK-NOT-FOUNDNetwork code does not exist
422BIZ-ADDRESS-TYPE-NOT-ALLOWEDUnsupported address type value
422BIZ-MAIN-ADDRESS-REQUIREDMain address required before creating sub-address
422BIZ-SUB-ADDRESS-SUBSCRIPTION-REQUIREDActive sub_address subscription required
422BIZ-SUB-ADDRESS-QUOTA-EXCEEDEDSub-address quota for current plan exceeded

Main address uniqueness: Only one main address per user per network is allowed.

Sub-address prerequisite: A main address must exist for the network, and the user must have an active sub_address subscription with available quota (meta.max_sub_addresses; -1 means unlimited).


2.4 Get Address Balances

GET /wallets/{address}/balances

Rate limit: 60/min/user

Returns the last cached balance snapshot. Does not actively query the chain. Use Refresh Address Balances to force an on-chain update.

Path Parameters

ParameterDescription
addressOn-chain wallet address string

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "address": "TXyz123...abc",
    "items": [
      {
        "symbol": "TRX",
        "balance_available": "50000000",
        "balance_locked": "0",
        "balance_updated_at": "2026-05-20 09:30:00"
      },
      {
        "symbol": "USDT",
        "balance_available": "1000000000",
        "balance_locked": "0",
        "balance_updated_at": "2026-05-20 09:30:00"
      }
    ],
    "refresh_source": 1,
    "balance_updated_at": "2026-05-20 09:30:00"
  }
}
FieldDescription
items[].symbolAsset symbol
items[].balance_availableAvailable balance (smallest unit integer string)
items[].balance_lockedLocked balance (command in progress)
refresh_sourceLast refresh source: 1 auto, 2 manual

Unit: All balance values are in the smallest on-chain unit. For TRON: 1 TRX = 1,000,000 SUN; 1 USDT = 1,000,000 (6 decimal places).

Error Responses

HTTPError CodeScenario
404BIZ-WALLET-ADDRESS-NOT-FOUNDAddress not found or does not belong to current user

2.5 Refresh Address Balances

POST /wallets/{address}/balances/refresh

Rate limit: 20/min/user

Actively queries the on-chain node for the latest balance and updates the local cache.

Path Parameters

ParameterDescription
addressOn-chain wallet address string

Request Body (optional)

{
  "force": true
}
FieldTypeDescription
forcebooleantrue to bypass cache cooldown; defaults to false

Response 200

Same structure as Get Address Balances, with refresh_source: 2.

Error Responses

HTTPError CodeScenario
404BIZ-WALLET-ADDRESS-NOT-FOUNDAddress not found or does not belong to current user
502CHAIN-BALANCE-QUERY-FAILEDOn-chain node query failed

2.6 Get Address Chain Resources (TRON)

GET /wallets/{address}/resources

Rate limit: 60/min/user

Returns on-chain resource status for a TRON address: Energy, Bandwidth, staked TRX, and delegation details.

This endpoint is only valid for networks that support resource staking (currently TRON). Calling it for other network addresses returns 422 BIZ-CHAIN-RESOURCES-NOT-SUPPORTED.

Path Parameters

ParameterDescription
addressOn-chain wallet address string (must belong to current user)

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "energy": {
      "available": 12500,
      "used": 25000,
      "limit": 65000,
      "staked_sun": "5000000",
      "delegated_out_sun": "2000000",
      "received_sun": "3000000"
    },
    "bandwidth": {
      "free_available": 500,
      "free_used": 100,
      "free_limit": 600,
      "staked_available": 300,
      "staked_used": 200,
      "staked_limit": 500,
      "staked_sun": "1000000",
      "delegated_out_sun": "0",
      "received_sun": "0"
    },
    "withdrawable_sun": "1000000",
    "delegated_to": [
      { "address": "TSub111...abc" }
    ],
    "received_from": [
      { "address": "TMain222...xyz" }
    ]
  }
}

Energy Fields

FieldDescription
energy.availableCurrent available energy (limit - used)
energy.usedEnergy consumed in the current cycle
energy.limitTotal energy cap (own stake + received delegations)
energy.staked_sunTRX staked to obtain energy (SUN)
energy.delegated_out_sunTRX equivalent of energy delegated to other addresses (SUN)
energy.received_sunTRX equivalent of energy received from other addresses (SUN)

Bandwidth Fields

FieldDescription
bandwidth.free_availableRemaining free daily bandwidth (TRON grants 600/day per address)
bandwidth.free_limitFree bandwidth cap (fixed 600/day)
bandwidth.staked_availableRemaining staked bandwidth
bandwidth.staked_limitTotal staked bandwidth cap
bandwidth.staked_sunTRX staked to obtain bandwidth (SUN)

Other Fields

FieldDescription
withdrawable_sunTRX that has passed the unstaking wait period and is ready to withdraw (SUN)
delegated_toList of addresses this address has delegated resources to
received_fromList of addresses that have delegated resources to this address

SUN conversion: 1 TRX = 1,000,000 SUN. staked_sun: "5000000" means 5 TRX staked.

Delegation index note: The delegated_to and received_from fields require a TronGrid Pro API Key. If not configured, these fields will return empty arrays with a warning logged server-side.

Error Responses

HTTPError CodeScenario
404BIZ-WALLET-ADDRESS-NOT-FOUNDAddress not found or does not belong to current user
422BIZ-CHAIN-RESOURCES-NOT-SUPPORTEDNetwork does not support on-chain resource staking

2.7 List Commands

GET /commands

Rate limit: 60/min/user

Returns all command records for the current user. Supports filtering by type and status with pagination.

Query Parameters (optional)

ParameterTypeDefaultDescription
typeinteger1 query, 2 withdraw, 3 collection, 4 stake, 5 unstake, 6 withdraw-unstaked, 7 vote, 8 claim-reward; omit for all
statusintegerFilter by status (see Command Status Enum); omit for all
pageinteger1Page number
per_pageinteger20Items per page (max 100)

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "items": [
      {
        "command_no": "CMD7QKHY57AIWWXCQZ47P00",
        "type": 2,
        "status": 3,
        "error_code": null,
        "last_error": null,
        "started_at": "2026-05-22 10:00:00",
        "finished_at": "2026-05-22 10:00:15",
        "created_at": "2026-05-22 09:59:58"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 5,
      "pages": 1
    }
  }
}

2.8 Get Command Status

GET /commands/{commandNo}

Rate limit: 60/min/user

Path Parameters

ParameterDescription
commandNoCommand number (e.g. CMD7QKHY57AIWWXCQZ47P00)

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "command_no": "CMD7QKHY57AIWWXCQZ47P00",
    "status": 3,
    "type": 2,
    "error_code": null,
    "last_error": null,
    "started_at": "2026-05-22 10:00:00",
    "finished_at": "2026-05-22 10:00:15"
  }
}

Error Responses

HTTPError CodeScenario
404BIZ-COMMAND-NOT-FOUNDCommand not found or does not belong to current user

3 Collection

Collection is the process of sweeping funds from a sub-address back to the main address.

3.1 Create Collection Task

POST /collections

Rate limit: 10/min/user  Idempotency: Idempotency-Key header required

Request Header

Idempotency-Key: 550e8400-e29b-41d4-a716-446655440001

Request Body

{
  "address": "TXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "asset_symbol": "USDT"
}
FieldTypeRequiredDescription
addressstringSub-address string (address_type=2, must belong to current user)
asset_symbolstringAsset to collect (e.g. USDT)

Response 201

{
  "code": "OK",
  "message": "success",
  "data": {
    "command_no": "CMD-20260520-0002",
    "task_no": "COL-20260520-0001",
    "status": 1,
    "error_code": null,
    "last_error": null,
    "started_at": "2026-05-20 10:20:00",
    "finished_at": null
  }
}
FieldDescription
task_noCollection task number, used to query progress
command_noAssociated command number
statusCollection task status (see Collection Task Status Enum)

Error Responses

HTTPError CodeScenario
403RISK-REVIEW-BLOCKEDRequest blocked by risk control
409BIZ-COMMAND-LOCKEDAddress already has an active command in progress
422BIZ-ADDRESS-TYPE-NOT-SUBOnly sub-addresses can be collected from
422BIZ-WALLET-ADDRESS-NOT-FOUNDAddress not found or does not belong to current user
422BIZ-ASSET-NOT-FOUNDAsset symbol does not exist

TRON Collection Flow (multi-step):

TRC20 strategy (e.g. USDT):

  1. FUNDING_TRX — Main address transfers TRX to sub-address for gas fees
  2. ACQUIRING_ENERGY — Energy acquisition decision: self-delegation or third-party; broadcasts transaction and waits for on-chain confirmation
  3. WAIT_ENERGY_READY — Polls sub-address energy until threshold is met (up to 60 s)
  4. COLLECTING — Sub-address transfers asset to main address
  5. UNDELEGATING_ENERGY — Undelegates energy from sub-address (self-delegation path only)
  6. RECOVER_TRX — Remaining TRX swept back to main address
  7. DONE — Collection complete, Webhook event dispatched

TRX strategy:

  1. COLLECTING — Sub-address transfers TRX to main address
  2. DONE — Collection complete, Webhook event dispatched

3.2 Get Collection Task Status

GET /collections/{taskNo}

Rate limit: 60/min/user

Path Parameters

ParameterDescription
taskNoCollection task number (e.g. COL-20260520-0001)

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "command_no": "CMD-20260520-0002",
    "task_no": "COL-20260520-0001",
    "status": 11,
    "error_code": null,
    "last_error": null,
    "started_at": "2026-05-20 10:20:00",
    "finished_at": "2026-05-20 10:21:30"
  }
}

Error Responses

HTTPError CodeScenario
404BIZ-COLLECTION-TASK-NOT-FOUNDTask not found or does not belong to current user

4 Cashier

The Cashier module lets you generate time-limited payment links for sub-addresses. Payers open the link in any browser — no Vuken account required.

Two authentication contexts:

GroupAuthUsed By
Token Management (§4.1)Authorization: Bearer <developer-api-token>Your server
Payment API (§4.2)Authorization: Bearer <cashier-token>Payer's browser

4.1 Token Management

These endpoints use your standard Developer API Token. Call them from your server to issue and manage cashier payment links.


4.1.1 Create Cashier Token

POST /cashier/tokens

Rate limit: 20/min/user

Request Body

{
  "address": "TGhCS3TbXRLqEyD2LHB8VkSEs1pHSJaq7c",
  "ttl_minutes": 60
}
FieldTypeRequiredDescription
addressstringSub-address string (must belong to current user)
ttl_minutesintegerToken validity in minutes. Default 60. Allowed: 60, 120, 480, 1440

Response 201

{
  "code": "OK",
  "message": "success",
  "data": {
    "token_no": "CT3F788C86",
    "token": "ct_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "wallet_address_id": 7,
    "address": "TGhCS3TbXRLqEyD2LHB8VkSEs1pHSJaq7c",
    "network_code": "TRON",
    "status": "active",
    "ttl_minutes": 60,
    "expires_at": "2026-06-11T05:00:00+00:00",
    "disabled_at": null,
    "disable_reason": null,
    "created_at": "2026-06-11T04:00:00+00:00"
  }
}

Security: token is only returned in this 201 response. Store it immediately — it cannot be retrieved again. If lost, disable this token and create a new one.

The payment link for the payer is:

https://vuken.io/cashier?ct=<token>

Error Responses

HTTPError CodeScenario
422BIZ-WALLET-ADDRESS-NOT-FOUNDAddress not found or does not belong to current user
422BIZ-ADDRESS-TYPE-NOT-SUBOnly sub-addresses can have cashier tokens
409CASHIER-TOKEN-ACTIVE-EXISTSAn active token already exists for this address

4.1.2 List Cashier Tokens

GET /cashier/tokens

Rate limit: 60/min/user

Query Parameters

ParameterTypeDescription
pageintegerPage number (default 1)
per_pageintegerItems per page (default 15, max 100)

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "data": [
      {
        "token_no": "CT3F788C86",
        "wallet_address_id": 7,
        "address": "TGhCS3TbXRLqEyD2LHB8VkSEs1pHSJaq7c",
        "network_code": "TRON",
        "status": "active",
        "ttl_minutes": 60,
        "expires_at": "2026-06-11T05:00:00+00:00",
        "disabled_at": null,
        "disable_reason": null,
        "created_at": "2026-06-11T04:00:00+00:00"
      }
    ],
    "meta": {
      "current_page": 1,
      "per_page": 15,
      "total": 1,
      "last_page": 1
    }
  }
}

4.1.3 Disable Cashier Token

DELETE /cashier/tokens/{tokenNo}

Rate limit: 20/min/user

Path Parameters

ParameterDescription
tokenNoCashier token number (e.g. CT3F788C86)

Request Body (optional)

{
  "reason": "Replaced by new token"
}

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "token_no": "CT3F788C86",
    "status": "disabled",
    "disabled_at": "2026-06-11T04:30:00+00:00",
    "disable_reason": "Replaced by new token"
  }
}

Error Responses

HTTPError CodeScenario
404CASHIER-TOKEN-NOT-FOUNDToken not found or does not belong to current user
409CASHIER-TOKEN-ALREADY-DISABLEDToken is already disabled

4.2 Payment API

These endpoints use a Cashier Token (ct_xxx) as the Bearer token. They are intended for the payer's browser session. Each request automatically extends the token's expiry.

Authorization: Bearer ct_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

4.2.1 Get Session

GET /cashier/session

Returns the current payment session including the receiving address, per-asset minimum collection amounts, and the latest collection task (if any).

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "token_no": "CT3F788C86",
    "expires_at": "2026-06-11T05:00:00+00:00",
    "min_collect_amounts": {
      "USDT": "20000000",
      "TRX": "1000000"
    },
    "address": {
      "wallet_address_id": 7,
      "address": "TGhCS3TbXRLqEyD2LHB8VkSEs1pHSJaq7c",
      "network_code": "TRON",
      "address_label": "Workspace #7"
    },
    "active_task": {
      "task_no": "COLTEST0000000001",
      "command_no": "CMD-TEST-00000001",
      "status": 6,
      "last_error": null,
      "started_at": "2026-06-10 04:00:00",
      "finished_at": null
    }
  }
}
FieldDescription
min_collect_amountsPer-asset minimum collect threshold map (key = asset symbol, value = smallest-unit integer string). Empty map means no minimum.
active_taskLatest collection task object, or null if no task exists. When non-null, a collection is already in progress — do not trigger a new one.
active_task.statusSee Collection Task Status Enum

Error Responses

HTTPError CodeScenario
401CASHIER-TOKEN-MISSINGNo Bearer token provided
401CASHIER-TOKEN-INVALIDToken is invalid, expired, or disabled

4.2.2 Get Balance

GET /cashier/balance

Returns the current on-chain balance of the payment address (cached; use /cashier/session to trigger a refresh).

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "address": "TGhCS3TbXRLqEyD2LHB8VkSEs1pHSJaq7c",
    "items": [
      {
        "symbol": "USDT",
        "balance_available": "25000000",
        "balance_locked": "0",
        "balance_updated_at": "2026-06-11T04:10:00+00:00"
      },
      {
        "symbol": "TRX",
        "balance_available": "5000000",
        "balance_locked": "0",
        "balance_updated_at": "2026-06-11T04:10:00+00:00"
      }
    ],
    "balance_updated_at": "2026-06-11T04:10:00+00:00"
  }
}

All amounts are in the smallest on-chain unit. See Balance Units.

Error Responses

HTTPError CodeScenario
401CASHIER-TOKEN-MISSINGNo Bearer token provided
401CASHIER-TOKEN-INVALIDToken is invalid, expired, or disabled

4.2.3 Get Active Task

GET /cashier/task

Returns the latest collection task for this payment session, or null if no task exists.

Response 200

{
  "code": "OK",
  "message": "success",
  "data": {
    "task_no": "COLTEST0000000001",
    "command_no": "CMD-TEST-00000001",
    "status": 6,
    "last_error": null,
    "started_at": "2026-06-10 04:00:00",
    "finished_at": null
  }
}

Error Responses

HTTPError CodeScenario
401CASHIER-TOKEN-MISSINGNo Bearer token provided
401CASHIER-TOKEN-INVALIDToken is invalid, expired, or disabled

4.2.4 Trigger Collection

POST /cashier/collect

Triggers a collection task to sweep the balance at the payment address to the main wallet.

Rate limit: 10/min/token  Idempotency: Idempotency-Key header required

Request Header

Idempotency-Key: 550e8400-e29b-41d4-a716-446655440099

Request Body

{
  "asset_symbol": "USDT"
}
FieldTypeRequiredDescription
asset_symbolstringAsset to collect (e.g. USDT, TRX)

Response 201

{
  "code": "OK",
  "message": "success",
  "data": {
    "task_no": "COL20260611XXXXXXXX",
    "command_no": "CMD20260611XXXXXXXX",
    "status": 1,
    "last_error": null,
    "started_at": "2026-06-11T04:15:00+00:00",
    "finished_at": null
  }
}

Error Responses

HTTPError CodeScenario
401CASHIER-TOKEN-MISSINGNo Bearer token provided
401CASHIER-TOKEN-INVALIDToken is invalid, expired, or disabled
409BIZ-COMMAND-LOCKEDA collection task is already in progress
422BIZ-ASSET-NOT-FOUNDAsset symbol does not exist
422BIZ-AMOUNT-BELOW-MINIMUMBalance is below the minimum collect threshold

5 Webhooks

When key events occur (collection completed, command succeeded/failed), the platform delivers an HTTP POST request to the webhook_url you configured.

5.1 Setup

Webhooks require a Session Token to configure (server-side setup only):

  1. Subscribe to the developer plan: POST /subscriptions/activate
  2. Set your webhook endpoint: PUT /subscriptions/config
{
  "service_code": "developer",
  "config": {
    "webhook_url": "https://your-server.com/webhooks/receive",
    "webhook_secret": "your-signing-secret"
  }
}

webhook_secret is used to generate the X-Webhook-Signature header. Store it securely — it cannot be retrieved after being set.


5.2 Event Types

Event TypeTrigger
withdrawal.completedA withdrawal command is broadcast successfully (txid obtained)
withdrawal.failedA withdrawal command fails (signing / broadcast error)
collection.completedA collection task completes — tokens credited to the main address (DONE)
collection.failedA collection task fails at any step and enters a terminal state (FAILED)

Webhooks only fire on terminal states. Intermediate steps (e.g. FUNDING_TRX, COLLECTING) do not trigger webhooks.


5.3 Payload Format

All webhook requests are POST with Content-Type: application/json. All event fields are at the top level of the JSON body — there is no nested data wrapper. The signature (see §5.5) is computed over this raw body.

Common fields (present on every event):

FieldDescription
event_idGlobally unique identifier (UUID). Fixed per event; unchanged across retries. Use for deduplication.
event_typeEvent type (see table above)
occurred_atEvent timestamp (ISO 8601)

withdrawal.* payload:

{
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_type": "withdrawal.completed",
  "occurred_at": "2026-05-22T10:00:00+08:00",
  "command_no": "CMD5GH3KQWXYZ12345",
  "status": 3,
  "txid": "2a09503378f288571f916d8d1e856eb116f69d3e6ff6dbb83fab6a186eb33d14",
  "error": null,
  "finished_at": "2026-05-22T10:00:15+08:00"
}
FieldDescription
command_noWithdrawal command number
status3 SUCCESS, 4 FAILED
txidOn-chain transaction hash; null on failure
errorFailure reason; null on success
finished_atTerminal timestamp

collection.* payload:

{
  "event_id": "550e8400-e29b-41d4-a716-446655440002",
  "event_type": "collection.completed",
  "occurred_at": "2026-05-22T10:01:00+08:00",
  "task_no": "COL7ABCDEFG123456X",
  "status": 11,
  "network_code": "TRON",
  "asset_symbol": "USDT",
  "address": "TSubXxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "swept_amount": 10000000,
  "sweep_tx_hash": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
  "credited_at": "2026-05-22T10:01:00+08:00",
  "error": null
}
FieldDescription
task_noCollection task number
status11 DONE, 12 FAILED
network_codeNetwork code (e.g. TRON)
addressSub-address the collection ran on
swept_amountAmount swept to the main address (smallest unit integer); null on failure
sweep_tx_hashSweep transaction hash; null on failure
credited_atOn-chain credit timestamp; null on failure
errorFailure reason; null on success

5.4 Request Headers

Every webhook delivery includes the following headers:

X-Webhook-Signature: sha256=<hex_signature>
X-Event-Id:          <uuid>
X-Event-Type:        collection.completed

5.5 Signature Verification

The X-Webhook-Signature header is HMAC-SHA256 computed over a canonical JSON rebuilt from the payload — not the raw request body. The platform sorts the top-level keys of the full payload using MySQL's JSON key ordering (shorter keys first, then byte order), re-encodes with unescaped Unicode and no extra whitespace, then signs:

canonical_json = json_encode(sort_keys(full_payload), UNESCAPED_UNICODE)   // no spaces
signature      = "sha256=" + hex( HMAC-SHA256(canonical_json, webhook_secret) )

Do not verify against the raw request body — the transmitted key order is not guaranteed. You must rebuild canonical_json with the same key-sort rule (length first, then byte order) before hashing. All current event fields are scalar top-level values, so a single top-level key sort is sufficient.

Verification examples:

// PHP
$payload   = json_decode($request->getContent(), true);
uksort($payload, fn ($a, $b) => (strlen($a) <=> strlen($b)) ?: strcmp($a, $b));
$canonical = json_encode($payload, JSON_UNESCAPED_UNICODE);
$expected  = 'sha256=' . hash_hmac('sha256', $canonical, $webhookSecret);
$valid     = hash_equals($expected, (string) $request->header('X-Webhook-Signature'));
# Python
import hmac, hashlib, json
payload   = json.loads(raw_body)
ordered   = dict(sorted(payload.items(), key=lambda kv: (len(kv[0]), kv[0])))
canonical = json.dumps(ordered, ensure_ascii=False, separators=(',', ':'))
expected  = 'sha256=' + hmac.new(webhook_secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()
valid     = hmac.compare_digest(expected, request.headers['X-Webhook-Signature'])
// Node.js
const crypto = require('crypto');
const payload = JSON.parse(rawBody);
const ordered = {};
for (const k of Object.keys(payload).sort((a, b) => a.length - b.length || (a < b ? -1 : a > b ? 1 : 0))) {
  ordered[k] = payload[k];
}
const canonical = JSON.stringify(ordered);
const expected = 'sha256=' + crypto.createHmac('sha256', webhookSecret).update(canonical).digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(receivedSignature));

Always use a timing-safe comparison (hash_equals, hmac.compare_digest, timingSafeEqual) to prevent timing attacks.


5.6 Retry Policy

If your server does not return 2xx within the timeout, the platform will retry:

AttemptDelay
1stImmediate
2ndAfter 1 minute
3rdAfter 5 minutes
4th+Marked DEAD, retries stop

Timeout: 15 s total per request. Your endpoint must return 2xx within this window.

After DEAD, the delivery can be viewed in GET /webhooks/deliveries (Session Token required).


5.7 Receiver Best Practices

  1. Verify the signature — reject any request where X-Webhook-Signature is missing or invalid.
  2. Return 200 immediately — process the event asynchronously to avoid timeout failures.
  3. Deduplicate by event_id — the same event may be delivered more than once on retry; your handler must be idempotent.
  4. Use HTTPS — plaintext endpoints expose your payload and invalidate signature security.

Appendix

Command Status Enum

ValueNameDescription
1PENDINGQueued, waiting to execute
2RUNNINGCurrently executing
3SUCCESSCompleted successfully
4FAILEDExecution failed
5REJECTEDBlocked by risk control
6CANCELLEDManually cancelled

Command Type Enum

ValueNameDescription
1QUERYQuery command
2WITHDRAWALWithdrawal / transfer out
3COLLECTIONSub-address collection
4STAKEStake TRX for resources
5UNSTAKEUnstake TRX
6WITHDRAW_UNSTAKEDWithdraw matured unstaked TRX
7VOTEVote for Super Representatives
8WITHDRAW_REWARDClaim voting rewards

Collection Task Status Enum

ValueNameDescription
1PENDINGTask created; no step has started yet
2FUNDING_TRXTransferring TRX gas fee to sub-address
16ACQUIRING_ENERGYEnergy acquisition in progress — self-delegation or third-party proxy transaction broadcast, awaiting on-chain confirmation
17WAIT_ENERGY_READYPolling sub-address energy until threshold is met (up to 60 s)
6COLLECTINGTransferring asset to main address
15UNDELEGATING_ENERGYUndelegating energy from sub-address (self-delegation path only)
8RECOVER_TRXRecovering remaining TRX to main address
11DONEAll steps complete; webhook dispatched
12FAILEDUnrecoverable error; task abandoned

Supported Networks

network_codeNetworkNative Asset
TRONTRON MainnetTRX

Balance Units

All balance and amount values use the smallest on-chain unit as integer strings:

NetworkAssetSmallest UnitExample
TRONTRXSUN (1 TRX = 1,000,000 SUN)"1000000" = 1 TRX
TRONUSDT (TRC20)6 decimal places"1000000" = 1 USDT