cryptoinfraDocs

#Static Wallet Address

A Static Wallet Address is one permanent crypto address assigned to each of your users. Create the user once and you get the address back; it stays active and reusable for every payment that user ever makes. It does not rotate, it does not expire, and it is not reissued.

Open as MarkdownFor AI assistants

What it replaces. The classic gateway model mints a fresh address for every payment and makes you hand the customer new instructions each time. A static address ends that loop:

  • No address generation per payment. One address per user, created once.
  • Automatic attribution. Whatever lands on the address is credited to that user — you never match a payment by hand.
  • Fewer mistakes, fewer tickets. The customer saves one address in their wallet and reuses it; there is no "which address was this one" question.
  • Fully automated over the API. Create, read, credit and pay out with the same key.
  • A clean history. Every deposit is already filed under the user it belongs to.

You can print the address on a receipt, save it to a customer's profile, or show it in an app, and it will still be correct in five years. Everything else on the platform — balances, payouts, cards — is built on top of these addresses.

bash
curl -X POST https://api.cryptoinfra.build/v1/users \
  -H "Authorization: Bearer $CRYPTOINFRA_API_KEY" \
  -H "content-type: application/json" \
  -d '{"external_user_id": "10482"}'
json
{
  "user_id": "10482",
  "addresses": [
    { "chain": "tron", "address": "TJYBSfZfwwa28mYZPkE9uodBwGbnwEqBK1" }
  ]
}

external_user_id is a number of 5 to 10 digits — the id this user has in your own system. Anything else is refused with 400 validation_error.

Read the static address again at any time with GET /v1/users/{externalId}/addresses. You never need to store it yourself, though you may.

#One static address, not one per coin

The platform runs on one network, TRON. A static address belongs to the chain, and every asset on it lands on the same one.

ChainThe one address acceptsConfirmations before credit
tronTRX, USDT (TRC20), USDC (TRC20)19

So a customer sending USDT on TRON and a customer sending TRX use the same string. The platform tells them apart by what the transaction actually moved, not by where it was sent.

This is why an address alone cannot tell you which order was paid — see Matching a payment to an order below.

#What is open

GET /v1/assets is the authority on what can be received right now. If an asset is not listed there, it is not being watched, and coins sent as it are not credited. The address list is shaped the same way: it is filtered to chains that can actually take money, which is tron alone. It is still a list, so read it as one — by chain, not by position — rather than assuming the shape of the array.

#How a payment becomes a balance

text
customer sends  →  confirming  →  credited
                                      ↓
                             balance + deposit.credited webhook
  1. confirming — the transaction is in a block and the platform is counting confirmations against the number in the table above. Nothing is credited yet. A chain reorg here moves the deposit to orphaned and it is never credited.
  2. credited — the balance moves, in the double-entry ledger, and deposit.credited fires.

A deposit below the asset's minimum is written as ignored_dust instead (see below). The contract also lists a seen status; it is legacy and no deposit is created in it.

You do not poll a chain and you do not run a node. Watch for the webhook, or read GET /v1/users/{externalId}/balances.

#There is no deposit fee

A deposit to an address we issue is credited in full. A 100 USDT deposit credits 100.00 USDT; the only thing ever taken out of it is your own fee, if you have set one (merchant_fee on the deposit). A deposit below min_deposit is never credited: it is marked ignored_dust — a dust floor, not a charge. GET /v1/fees returns your live schedule (deposit.total is 0); read it rather than hard-coding anything.

Every deposit row carries both figures, and they are not interchangeable — amount is what the customer sent, amount_credited (with its amount_credited_base twin) is what reached the balance. Reconcile a balance against amount_credited and reconcile a customer's claim against amount. The deposit.credited webhook spells the same field amountCredited.

Who sent it. Every deposit carries from_address (the webhook: fromAddress). For USDT and USDC it is the from of the token Transfer that paid the address — the wallet the money came from, even when an exchange paid out through a batch or proxy contract signed by an operator address. For TRX it is the sender. Show it to your user as "received from"; there is no need to look the txid up on an explorer.

#Amounts too small to bother with

A deposit below an asset's min_deposit is marked ignored_dust and never credited: the fee to move a few hundred base units exceeds the units themselves, so crediting it would cost more than it is worth. min_deposit is per asset in /v1/assets; read it from there rather than from this page, and treat 0 as "no floor".

#Matching a payment to an order

A static address is shared across every payment that customer ever makes, so an arriving deposit tells you who paid, never what for. The address is a running balance per customer — top-ups, wallets, exchange accounts, anything where money is just credit.

If you are billing per order, do not try to match on amount alone against a shared address — two customers paying 25 USDT in the same minute are indistinguishable. Give each order its own user (a user is free and permanent) and credit the order from that user's deposit.credited event, or keep the order on your side and let the customer spend from their balance.

#Ways money is actually lost

These are the failure modes that cost real customers real coins. All of them are the customer's action, and none of them can be reversed by us, so the wording on your own checkout matters more than anything in this API.

Wrong network, right-looking address. USDT exists on many chains and wallets happily send the wrong one. USDT sent over any network other than TRON does not arrive and cannot be recovered. Always print the network next to the address — "TRON (TRC20) only" — not just the coin name.

An asset that is not open. Covered above: if it is not in /v1/assets, it is not watched.

A token nobody listed. The TRON address accepts TRX, USDT and USDC. A different TRC20 token sent to it is not credited — the address is watched for the assets in /v1/assets and nothing else.

A stale address from your own database. A static address never changes, so this should be impossible — but if you cache them, cache them against the external_user_id you asked for. Showing customer A the address of customer B credits B.

#What happens behind the static address

Two things worth knowing, both invisible to you:

Keys are not on the API server. Addresses are derived from watch-only extended public keys. The server that answers these requests can generate an address and can never spend from one.

The ledger is the balance, not the chain. A user's coins sit at their own address and their payouts leave from it, so the two usually agree — but the ledger is net of holds and of fees the moment they are charged, while the chain catches up a few seconds later, and balances that existed before 4 September 2026 live in the platform's own wallets. Read GET /v1/users/{externalId}/balances; a block explorer will mislead you here, and it is the single most common support question merchants receive. Since 19 September 2026 that response also carries on_chain per asset — what the address holds at that moment — so the two figures sit side by side. They differ by design: our fees leave the address for the platform's profit wallet as they settle, and earnings (your commission, your own fees) are credited to the balance from there. amount is what a payout may spend.

#Reference