Skip to content

Fund API Documentation

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

Authentication and Permissions

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.

PermissionEndpoints
fund.withdrawPOST /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.withdraw must be configured with a non-empty IP whitelist when created or updated in the merchant dashboard.

Withdrawal Idempotency

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 with is_duplicate: true.
  • Use one request_id for exactly one logical withdrawal. Do not reuse it for a different amount, chain, token, or destination address.

Response Envelope

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.

Transfer Funds to an Infini UID

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, or USD only.
  • 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.

Request Body

FieldTypeRequiredDescription
request_idstring (UUID)NoIdempotency key. When omitted, Infini generates one
recipient_uidstringYesRecipient Infini UID; it cannot belong to the source organization
token_typestringYesRecipient account currency: USDT, USDC, or USD
source_currencystringNoSource account currency. Defaults to token_type; V1 requires it to equal token_type
amountstringYesPositive 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
notestringNoOptional transfer note

Request Example

{
  "request_id": "4b4436ba-90a1-4f26-940d-97177a7a3400",
  "recipient_uid": "12345678",
  "token_type": "USDC",
  "source_currency": "USDC",
  "amount": "10.25",
  "note": "Customer refund"
}

Response Example

{
  "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.

Error Codes

HTTP StatusCodeDescription
401401The application could not authenticate the API key
403403The API key lacks fund.withdraw or the IP whitelist rejected the request
400 or 20030013A 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
20010005The sender or recipient could not be found
20010030The source organization's owner is protected from transfers
20020012The source account's usable balance is insufficient
20030005The transfer exceeds the remaining operation limit
20030015Internal transfers are restricted for the source organization
20030034The source currency is USD, but the organization does not have a USD Cash Account
500500An unexpected internal or downstream service error occurred

Withdraw Organization Funds

POST /v2/funds/withdraw

Creates a withdrawal from the authenticated organization to an external wallet.

  • Required permission: fund.withdraw

Request Body

FieldTypeRequiredDescription
request_idstring (UUID)NoIdempotency key. When omitted, Infini generates one
chainstringYesPublic chain name, for example ETHEREUM or ARBITRUM
token_typestringYesToken type, for example USDT or USDC
source_currencystringNoSource 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
amountstringYesMaximum 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_addressstringYesDestination address valid for the selected chain
notestringNoOptional 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 Example

{
  "request_id": "e94b4e88-36c2-4550-907e-839742cf5fae",
  "chain": "ETHEREUM",
  "token_type": "USDT",
  "source_currency": "USD",
  "amount": "10.00",
  "wallet_address": "0x5f716e5775b18409917e2a2f0762d29d6c385cb0",
  "note": "Treasury withdrawal"
}

Response Example

{
  "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.

Error Codes

HTTP StatusCodeDescription
401401The application could not authenticate the API key
403403The API key lacks fund.withdraw, the IP whitelist rejected the request, or withdrawal is disabled for the selected chain/token pair
20030001The core withdrawal configuration rejected the selected token
20030002The organization's source fund account does not exist
20030003The source account's available balance is insufficient
20030005The amount exceeds the remaining daily withdrawal limit
20030007The amount is below the minimum or is not greater than the applicable fees
20030012No withdrawal fee configuration is available for the selected chain/token pair
400 or 20030013A request parameter is invalid, such as the UUID, chain/token pair, amount, precision, source currency, or wallet address
20030022The destination is an internal Infini address; use an internal transfer instead
20030023The usable balance is insufficient after accounting for locked or reserved funds
20030034source_currency is USD, but the organization does not have a USD Cash Account
20080016A required asset price or exchange rate is temporarily unavailable
500500An 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 Withdrawal Status

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}.

Query Parameters

FieldTypeRequiredDescription
request_idstring (UUID)YesWithdrawal request ID

Response Example

{
  "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"
  }
}

Response Fields

FieldTypeDescription
request_idstringWithdrawal request ID
statusstringCurrent withdrawal status
amountstringTotal amount deducted from the source account
feestringLegacy Gas fee field; new integrations should use gas_fee and gas_fee_currency
actual_amountstringActual amount sent on-chain in token_type
transaction_hashstringOn-chain transaction hash; empty before submission
chainstringPublic chain name
token_typestringToken type
source_currencystringSource account currency
gas_feestringCustomer-facing Gas fee charged for the withdrawal
gas_fee_currencystringCurrency of gas_fee
fx_feestringFX fee charged for a cross-currency withdrawal; 0 for same-currency withdrawals
fx_fee_currencystringCurrency of fx_fee
fee_paid_bystringFee liability: PAYER or BENEFICIARY

Status Values

StatusDescription
pendingWithdrawal created and waiting for submission or review
processingTransaction submitted and waiting for confirmation
completedWithdrawal completed
failedWithdrawal failed

List Withdrawal Statuses

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_time and end_time are Unix timestamps in seconds and form an inclusive range.
  • Results are ordered by created_at descending.
  • page defaults to 1; page_size defaults to 20 and cannot exceed 100.
  • A range with no matching withdrawals returns HTTP 200 with an empty withdrawals array.
  • Invalid time ranges or pagination values return HTTP 400. A failure that prevents processing the query returns HTTP 500.

Request Body

FieldTypeRequiredDescription
start_timeintegerYesInclusive withdrawal creation start time, as a Unix timestamp in seconds
end_timeintegerYesInclusive withdrawal creation end time, as a Unix timestamp in seconds; must be greater than or equal to start_time
pageintegerNoPage number; defaults to 1
page_sizeintegerNoNumber of withdrawals per page; defaults to 20, maximum 100

Request Example

{
  "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.

Response Example

{
  "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.

List Withdrawal Fees

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

Response Example

{
  "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 Available Balances

GET /v2/funds/balances

Returns only the authenticated organization's USDT, USDC, and USD Cash AVAILABLE_BALANCE values.

  • Required permission: fund.withdraw

Response Example

{
  "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.