#Quickstart
Six calls, in order. Each one is copy-paste. Do them once against the sandbox, then switch the key and the base URL to live.
Before you start: sign up at the dashboard, verify your email, and copy your API key from Settings → API keys. The key is shown once. Keep it on your server — never in a browser or an app.
export CRYPTOINFRA_KEY=ck_live_your_key
export API=https://api.cryptoinfra.build#1. Tell us where to send events
curl -sX POST $API/v1/developer/webhooks \
-H "Authorization: Bearer $CRYPTOINFRA_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://yourapp.example/cryptoinfra/webhook"}'The response has endpoint.secret. Store it now — it is never shown again. Every event we send is signed with it (x-cryptoinfra-signature, HMAC-SHA256 of the raw body).
#2. Create a user, get their address
curl -sX POST $API/v1/users \
-H "Authorization: Bearer $CRYPTOINFRA_KEY" \
-H "Content-Type: application/json" \
-d '{"external_user_id":"10482"}'{ "user_id": "10482", "addresses": [ { "chain": "tron", "address": "TJYBSfZf…" } ] }external_user_id is the id this user has in your system: a number, 5 to 10 digits. The address is permanent. Show it to the user once, save it if you like — it never changes. Calling this again with the same id is safe: you get the same user and the same address.
#3. Money arrives — we tell you
When the user sends USDT, USDC or TRX to that address and it confirms, your webhook gets:
{
"userExternalId": "10482",
"assetId": "usdt_trc20",
"amount": "<decimal string>",
"amountCredited": "<decimal string>",
"txid": "<txid>",
"fromAddress": "<who sent it, T…>"
}with header x-cryptoinfra-event: deposit.credited. Deposits are free, so amountCredited equals amount unless you set a fee of your own. Reply 200 fast; do the work after.
#4. Read the balance
curl -s $API/v1/users/10482/balances \
-H "Authorization: Bearer $CRYPTOINFRA_KEY"{ "balances": [ { "asset_id": "usdt_trc20", "symbol": "USDT", "amount": "<decimal string>" } ] }This is the number to trust. It is already net of anything in flight.
#5. Quote a payout, then send it
curl -s "$API/v1/withdrawal-fee-quote?asset_id=usdt_trc20&amount=25&user_id=10482&to_address=TAs66Ct…" \
-H "Authorization: Bearer $CRYPTOINFRA_KEY"{ "total_fee": "<decimal string>", "network_fee": "<decimal string>", "platform_fee": "<decimal string>", "dynamic": true }Show the user total_fee. It is charged on top of the amount, so the balance must cover amount + total_fee. No number is printed here on purpose: the fee is priced the moment you ask and moves with the network — always read it from the quote, never from an example.
curl -sX POST $API/v1/withdrawals \
-H "Authorization: Bearer $CRYPTOINFRA_KEY" \
-H "Content-Type: application/json" \
-d '{"external_user_id":"10482","asset_id":"usdt_trc20",
"to_address":"TAs66Ct…","amount":"25","idempotency_key":"payout-8814"}'You get 202 with "status": "queued". amount is what the recipient receives. idempotency_key is your own order id: reuse it on every retry and you can never pay twice.
#6. Learn how it ended
Your webhook gets withdrawal.confirmed (money delivered) or withdrawal.failed (hold refunded, nothing lost). Before you tell the user it is done, read it once:
curl -s $API/v1/withdrawals/186 \
-H "Authorization: Bearer $CRYPTOINFRA_KEY""status": "confirmed" is the truth. Webhooks are a hint; the read is the answer.
That is the whole integration. Everything below is what people get wrong the first time.
#Five mistakes, and the fix for each
| Mistake | Fix |
|---|---|
| Matching a deposit to an order by amount | Give each order its own user, or keep the order on your side. An address tells you who paid, never what for |
| Crediting your user from the webhook alone | Reply 200, then read GET /v1/users/{id}/balances and credit from that |
Retrying a payout with a new idempotency_key | Same key, every retry. A timeout that did create the payout returns it, not a second one |
| Printing a fee from these docs | Quote it. Every fee is priced when you ask; the quote says whether it is live |
| Waiting for a swap webhook | There is none. Poll GET /v1/swap/orders/{id} |
#Where next
- Static Wallet Address — everything about the address and what lands on it
- Payouts — statuses, batches, what each error means
- Webhooks — verifying the signature, retries, the full event list
- Fees and pricing — the rule and the live price sheet
- Fee calculator — the sheet applied to any amount, live
- Errors and Idempotency — the two conventions worth reading before go-live