Fund endpoints let an organization transfer funds to an Infini UID, withdraw funds, query withdrawal status and fees, and read its available USDT, USDC, and USD balances.
All Fund API prefix:
/v2/funds
All endpoints use HMAC-SHA256 authentication with Date, Digest when the request has a body, and Authorization with keyId. For a GET request with query parameters, the signed request path must include the complete query string. See Chapter 4: Authorization and Security Mechanisms.
| Permission | Endpoints |
|---|---|
fund.withdraw | POST /v2/funds/internal-transfer, POST /v2/funds/withdraw, GET /v2/funds/withdraw/status, POST /v2/funds/withdraw/status/batch, GET /v2/funds/withdraw/fees, GET /v2/funds/balances |
IP whitelist: API keys that include
fund.withdrawmust be configured with a non-empty IP whitelist when created or updated in the merchant dashboard.
request_id is optional when creating a withdrawal:
- When omitted, Infini generates the withdrawal request ID and preserves the existing withdrawal behavior. Separate caller retries without a shared ID are not idempotent.
- When supplied, it must be a UUID and is used as the idempotency key.
- When the same merchant retries with the same
request_id, the API returns the previously created withdrawal information withis_duplicate: true. - Use one
request_idfor exactly one logical withdrawal. Do not reuse it for a different amount, chain, token, or destination address.
After gateway authentication, application responses use the standard code / message / data envelope. Business success is indicated by code === 0; a non-zero code indicates an error and message carries the details. Some downstream business failures can be returned with HTTP 200, a non-zero code, and data: null.
HMAC or gateway validation failures can be rejected before the request reaches the application and may return a gateway response such as {"message":"client request can't be validated"} instead of the application envelope. Clients should check the HTTP status first, then check code whenever the envelope is present.
POST /v2/funds/internal-transfer
Transfers funds from the authenticated organization to a recipient identified by an Infini UID.
- Required permission:
fund.withdraw - V1 supports same-currency transfers in
USDT,USDC, orUSDonly. - The transfer has no fee: the amount deducted from the sender equals the amount received by the recipient.
- A successful V1 transfer completes synchronously and returns
status: completed.
| Field | Type | Required | Description |
|---|---|---|---|
| request_id | string (UUID) | No | Idempotency key. When omitted, Infini generates one |
| recipient_uid | string | Yes | Recipient Infini UID; it cannot belong to the source organization |
| token_type | string | Yes | Recipient account currency: USDT, USDC, or USD |
| source_currency | string | No | Source account currency. Defaults to token_type; V1 requires it to equal token_type |
| amount | string | Yes | Positive amount deducted and received. USDT and USDC support up to six decimal places with a minimum of 0.000001; USD supports up to two decimal places with a minimum of 0.01 |
| note | string | No | Optional transfer note |
{
"request_id": "4b4436ba-90a1-4f26-940d-97177a7a3400",
"recipient_uid": "12345678",
"token_type": "USDC",
"source_currency": "USDC",
"amount": "10.25",
"note": "Customer refund"
}{
"code": 0,
"message": "",
"data": {
"request_id": "4b4436ba-90a1-4f26-940d-97177a7a3400",
"status": "completed",
"is_duplicate": false
}
}request_id is optional. When supplied, it must be a UUID and is used as the idempotency key. A retry by the same organization with an already completed request_id returns the original request ID with is_duplicate: true. Use one request ID for exactly one logical transfer; do not reuse it for different transfer details.
| HTTP Status | Code | Description |
|---|---|---|
| 401 | 401 | The application could not authenticate the API key |
| 403 | 403 | The API key lacks fund.withdraw or the IP whitelist rejected the request |
| 400 or 200 | 30013 | A parameter is invalid, including an invalid UUID, UID, currency, amount, precision, cross-currency transfer, self-transfer, or a request ID already owned by another organization |
| 200 | 10005 | The sender or recipient could not be found |
| 200 | 10030 | The source organization's owner is protected from transfers |
| 200 | 20012 | The source account's usable balance is insufficient |
| 200 | 30005 | The transfer exceeds the remaining operation limit |
| 200 | 30015 | Internal transfers are restricted for the source organization |
| 200 | 30034 | The source currency is USD, but the organization does not have a USD Cash Account |
| 500 | 500 | An unexpected internal or downstream service error occurred |
POST /v2/funds/withdraw
Creates a withdrawal from the authenticated organization to an external wallet.
- Required permission:
fund.withdraw
| Field | Type | Required | Description |
|---|---|---|---|
| request_id | string (UUID) | No | Idempotency key. When omitted, Infini generates one |
| chain | string | Yes | Public chain name, for example ETHEREUM or ARBITRUM |
| token_type | string | Yes | Token type, for example USDT or USDC |
| source_currency | string | No | Source account currency. Defaults to token_type. Set it to USD to deduct from the organization's USD Cash Account when withdrawing USDT or USDC; other cross-currency pairs are rejected |
| amount | string | Yes | Maximum amount deducted from the source account. Digits after the sixth decimal place are truncated without rounding; when source_currency is USD, at most two decimal places are allowed. The resulting amount must be at least 1 and greater than the applicable fees |
| wallet_address | string | Yes | Destination address valid for the selected chain |
| note | string | No | Optional withdrawal note |
Use GET /v2/funds/withdraw/fees as the current source of truth for enabled chain/token pairs and their fees. Chain and token names in examples are uppercase.
{
"request_id": "e94b4e88-36c2-4550-907e-839742cf5fae",
"chain": "ETHEREUM",
"token_type": "USDT",
"source_currency": "USD",
"amount": "10.00",
"wallet_address": "0x5f716e5775b18409917e2a2f0762d29d6c385cb0",
"note": "Treasury withdrawal"
}{
"code": 0,
"message": "",
"data": {
"request_id": "e94b4e88-36c2-4550-907e-839742cf5fae",
"status": "pending",
"is_duplicate": false
}
}For an idempotent retry, data.is_duplicate is true and data.status is the existing withdrawal's current status.
| HTTP Status | Code | Description |
|---|---|---|
| 401 | 401 | The application could not authenticate the API key |
| 403 | 403 | The API key lacks fund.withdraw, the IP whitelist rejected the request, or withdrawal is disabled for the selected chain/token pair |
| 200 | 30001 | The core withdrawal configuration rejected the selected token |
| 200 | 30002 | The organization's source fund account does not exist |
| 200 | 30003 | The source account's available balance is insufficient |
| 200 | 30005 | The amount exceeds the remaining daily withdrawal limit |
| 200 | 30007 | The amount is below the minimum or is not greater than the applicable fees |
| 200 | 30012 | No withdrawal fee configuration is available for the selected chain/token pair |
| 400 or 200 | 30013 | A request parameter is invalid, such as the UUID, chain/token pair, amount, precision, source currency, or wallet address |
| 200 | 30022 | The destination is an internal Infini address; use an internal transfer instead |
| 200 | 30023 | The usable balance is insufficient after accounting for locked or reserved funds |
| 200 | 30034 | source_currency is USD, but the organization does not have a USD Cash Account |
| 200 | 80016 | A required asset price or exchange rate is temporarily unavailable |
| 500 | 500 | An unexpected internal or downstream service error occurred |
Codes returned by the core fund service use the standard application envelope and may have HTTP 200 even when code is non-zero. HMAC failures rejected by the gateway may not include an application error code.
GET /v2/funds/withdraw/status?request_id={request_id}
Returns the current state and amounts for a withdrawal owned by the authenticated organization.
- Required permission:
fund.withdraw - The HMAC signing path must include
?request_id={request_id}.
| Field | Type | Required | Description |
|---|---|---|---|
| request_id | string (UUID) | Yes | Withdrawal request ID |
{
"code": 0,
"message": "",
"data": {
"request_id": "e94b4e88-36c2-4550-907e-839742cf5fae",
"status": "completed",
"amount": "11",
"fee": "0.1",
"actual_amount": "10.9",
"transaction_hash": "0xabc123",
"chain": "ETHEREUM",
"token_type": "USDT",
"source_currency": "USD",
"gas_fee": "0.08",
"gas_fee_currency": "USD",
"fx_fee": "0.02",
"fx_fee_currency": "USD",
"fee_paid_by": "BENEFICIARY"
}
}| Field | Type | Description |
|---|---|---|
| request_id | string | Withdrawal request ID |
| status | string | Current withdrawal status |
| amount | string | Total amount deducted from the source account |
| fee | string | Legacy Gas fee field; new integrations should use gas_fee and gas_fee_currency |
| actual_amount | string | Actual amount sent on-chain in token_type |
| transaction_hash | string | On-chain transaction hash; empty before submission |
| chain | string | Public chain name |
| token_type | string | Token type |
| source_currency | string | Source account currency |
| gas_fee | string | Customer-facing Gas fee charged for the withdrawal |
| gas_fee_currency | string | Currency of gas_fee |
| fx_fee | string | FX fee charged for a cross-currency withdrawal; 0 for same-currency withdrawals |
| fx_fee_currency | string | Currency of fx_fee |
| fee_paid_by | string | Fee liability: PAYER or BENEFICIARY |
| Status | Description |
|---|---|
pending | Withdrawal created and waiting for submission or review |
processing | Transaction submitted and waiting for confirmation |
completed | Withdrawal completed |
failed | Withdrawal failed |
POST /v2/funds/withdraw/status/batch
Returns withdrawals owned by the authenticated organization whose creation times fall within the requested range.
- Required permission:
fund.withdraw start_timeandend_timeare Unix timestamps in seconds and form an inclusive range.- Results are ordered by
created_atdescending. pagedefaults to1;page_sizedefaults to20and cannot exceed100.- A range with no matching withdrawals returns HTTP 200 with an empty
withdrawalsarray. - Invalid time ranges or pagination values return HTTP 400. A failure that prevents processing the query returns HTTP 500.
| Field | Type | Required | Description |
|---|---|---|---|
| start_time | integer | Yes | Inclusive withdrawal creation start time, as a Unix timestamp in seconds |
| end_time | integer | Yes | Inclusive withdrawal creation end time, as a Unix timestamp in seconds; must be greater than or equal to start_time |
| page | integer | No | Page number; defaults to 1 |
| page_size | integer | No | Number of withdrawals per page; defaults to 20, maximum 100 |
{
"start_time": 1787500000,
"end_time": 1787599999,
"page": 1,
"page_size": 20
}Because this is a POST request with a body, include the body Digest in the HMAC-authenticated request and sign the path /v2/funds/withdraw/status/batch.
{
"code": 0,
"message": "",
"data": {
"withdrawals": [
{
"request_id": "e94b4e88-36c2-4550-907e-839742cf5fae",
"created_at": 1787564636,
"status": "completed",
"amount": "11",
"fee": "0.1",
"actual_amount": "10.9",
"transaction_hash": "0xabc123",
"chain": "ETHEREUM",
"token_type": "USDT",
"source_currency": "USDT",
"gas_fee": "0.1",
"gas_fee_currency": "USDT",
"fx_fee": "0",
"fx_fee_currency": "USDT",
"fee_paid_by": "BENEFICIARY"
}
],
"total": 1,
"page": 1,
"page_size": 20,
"total_pages": 1
}
}Each item uses the same amount, fee, chain, and status semantics as the single-query endpoint and additionally returns created_at. Pagination metadata describes the complete matching time range, not only the current page.
GET /v2/funds/withdraw/fees
Returns currently enabled public chain/token pairs and their fees. Fees are dynamic; clients should query this endpoint instead of hard-coding a fee table.
- Required permission:
fund.withdraw
{
"code": 0,
"message": "",
"data": {
"fees": [
{
"chain": "ARBITRUM",
"token_type": "USDC",
"withdraw_fee": "0.5"
},
{
"chain": "ETHEREUM",
"token_type": "USDT",
"withdraw_fee": "2"
}
]
}
}Each withdraw_fee is denominated in the corresponding token_type.
GET /v2/funds/balances
Returns only the authenticated organization's USDT, USDC, and USD Cash AVAILABLE_BALANCE values.
- Required permission:
fund.withdraw
{
"code": 0,
"message": "",
"data": {
"available_balance_usdt": "120.50",
"available_balance_usdc": "75.25",
"available_balance_usd": "1000.00"
}
}When the organization has no balance entry for one of the currencies, its value is returned as "0". In particular, available_balance_usd is "0" when the USD Cash Account is not open.