what "complete" means
most teams start with one need, usually "show a deposit address at checkout". a month later they are running a node, an indexer, a gas wallet per network and a spreadsheet to reconcile it all. these are the jobs that show up sooner or later:
| job | the question it answers | call |
|---|---|---|
| addresses | where does this customer pay? | POST /hotwallets/{network}/children |
| detection | did the money arrive, and is it final? | webhook deposit.confirmed · GET /deposits |
| consolidation | how do I gather 500 small balances? | POST /sweep |
| payout | how do I pay a supplier or a merchant? | POST /hotwallet/withdraw |
| network move | my USDC is on Solana and I need it on Base | POST /bridge |
| books | what moved this month, and what did it cost? | GET /ledger · GET /statement |
around them sit the small calls that save support tickets: POST /address/validate and POST /address/detect before a payout, GET /balance/{network}/{address}/{token} for a live balance, and GET /quote for the exact fee before anything moves.
from signup to the first address
sign up in the panel with Google, GitHub or an email code. the first key (dr_live_...) is issued there, on the free plan, and goes in the X-Api-Key header of every call. the base URL is https://api.dolaramp.com/v1.
1. create a hotwallet, one per network:
curl https://api.dolaramp.com/v1/hotwallets \
-H "X-Api-Key: dr_live_..." \
-H "Content-Type: application/json" \
-d '{"network":"base","label":"acme main"}'
the response brings a wallet_secret (ws_...) once. it encrypts the key of the hotwallet and of every child; we keep only the ciphertext. without it, not even dolaramp can move the funds, so store it outside the application server. on Base and Arbitrum the hotwallet is one address valid on both networks.
2. generate a deposit address and tag it with your own id:
curl https://api.dolaramp.com/v1/hotwallets/base/children \
-H "X-Api-Key: dr_live_..." \
-H "Content-Type: application/json" \
-d '{"wallet_secret":"ws_...","count":1,"external_refs":["order-10432"]}'
up to 100 children per call. the external_ref is yours: an order number, a user id, merchant:invoice. it comes back in every deposit, so you credit the right customer with no lookup.
arriving is not confirmed
this is the part that costs money when done wrong. a deposit has two moments:
- arriving: the transfer was seen on the network. it means "a transaction exists", not "it cannot be undone". webhook
deposit.detected. - confirmed: the network's own rule was met. webhook
deposit.confirmed. release the order here, never before.
| network | what "confirmed" waits for |
|---|---|
| tron | solidification |
| solana | finalized |
| base · arbitrum | safe head |
| gram (ton) | final on inclusion |
a deposit that never settles within the deadline fires deposit.abandoned: treat it as not received.
webhooks are HTTPS only, retried up to 8 times with a growing interval (30 seconds, then doubling) and signed with HMAC-SHA256. the secret is shown once when you register the endpoint with POST /webhooks. the signature arrives in the X-DolaRamp-Signature header, as the hex HMAC of the raw body. check it before you believe the payload:
import { createHmac, timingSafeEqual } from 'node:crypto';
function isFromDolaramp(rawBody, header, secret) {
const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(header ?? '');
return a.length === b.length && timingSafeEqual(a, b);
}
compute it over the raw bytes you received, not over a re-serialized JSON. if your queue was down, GET /webhooks/deliveries shows what was sent and GET /deposits gives the same facts by polling.
sweep and withdraw, without a gas tank
the classic pain of deposit addresses: to move 20 USDT out of a child, the child needs the network's coin. multiply by a few thousand addresses and you are running a gas operation. here the gas is sponsored and the fee is taken inside the transfer, in the stablecoin.
POST /sweep consolidates children into the hotwallet in batch: by default the 20 most recent, or up to 20 you name in child_addresses. on Solana, gram(TON), Base and Arbitrum it answers confirmed with the tx_hash. on TRON it answers accepted in 1 to 2 seconds and the confirmation follows by webhook (sweep.confirmed).
a payout is one call:
curl https://api.dolaramp.com/v1/hotwallet/withdraw \
-H "X-Api-Key: dr_live_..." \
-H "Content-Type: application/json" \
-d '{"network":"base","token":"USDC","to":"0x...","amount":"10000000",
"wallet_secret":"ws_...","idempotency_key":"payout-inv-10432"}'
amount is in micro-units (6 decimals), so 10000000 is 10 USDC, and the recipient receives the amount minus the fee. three behaviors worth knowing before production:
- idempotency. retry with the same
idempotency_keyand you get the original operation back withreplayed: true. a timeout followed by a retry never pays twice. - no silent partial payout. a withdrawal larger than the balance is refused with
400 insufficient_balance. on TRON you can passallow_partial: trueto send what fits instead. - 202 pending. if the transfer was handed to the network but its landing was not seen in time, the call answers
202withstatus: pending. the outcome arrives aswithdraw.confirmedorwithdraw.failed, usually within a minute.
moving usdc between networks
POST /bridge moves USDC between Solana, Base and Arbitrum through Circle's CCTP: burned on the origin, minted by Circle on the destination, one to one. it is a network move, not a swap: no pool, no slippage. the fast path takes 8 to 20 seconds. the ceiling is $10,000,000 per operation and the minimum amount is $10.
GET /bridge/quote itemizes the operation before you run it: our fee, Circle's fee (passed through without markup) and what the recipient receives. the longer story, with measured times, is in move USDC from Solana to Base.
what it costs
no monthly fee on the free plan, and receiving is free on every plan. you pay per sweep or withdrawal, in the stablecoin, inside the operation:
| network · token | free | pro | what's inside |
|---|---|---|---|
| tron · USDT | $1.60 | $1.55 | $1.50 network fee + our $0.10 / $0.05 |
| base · USDC | $0.10 | $0.05 | our fee only, the gas is on us |
| arbitrum · USDC, USD₮0 | $0.10 | $0.05 | our fee only, the gas is on us |
| solana · USDT, USDC, PYUSD | ~$0.10 | ~$0.05 | network cost + 10% + our $0.10 / $0.05 |
| gram (ton) · USDT | ~$0.18 | ~$0.13 | network cost + 10% + our $0.10 / $0.05 |
the free plan watches 1,000 addresses and the pro plan 50,000. the bridge costs $2 + 0.3% on free and $2 + 0.2% on pro.
two costs that surprise people: the first move out of a brand-new Solana address also pays for its token accounts (~$0.65 on free), and an inactive TRON address pays a one-time activation of 1.50 USDT. if your customers pay on TRON, prefer a fixed address per customer over a throwaway address per order. where the 1.50 comes from is explained in send USDT without TRX.
values from pricing at 25 sep 2026 prices. Solana and gram(TON) follow the price of SOL and TON. GET /v1/quote returns the exact fee for your plan.
what the api does not do
better to know before you design around it:
- no fiat. dolaramp does not convert currency, hold bank balances or send bank transfers. the local-currency side goes through a licensed exchange or payment provider.
GET /ratesgives a mid-market reference for USDT against fiat currencies; it is not an executable quote, so apply your own spread. - no swap. USDT does not become USDC here. the bridge moves the same asset, USDC, between networks.
- no bridge for TRON or gram(TON). the bridge covers Solana, Base and Arbitrum only.
- one hotwallet per network, and 20 children per sweep call. for thousands of children, loop.
- rate limit: 120 requests per minute per key.
- no test network. the API runs on the real networks. a cheap way to rehearse is a few dollars of USDC on Base, where an operation costs $0.10.
keys and safety
each API key has a scope: read (list, quote, poll) or operate (everything, including sweep, withdraw and bridge). a write with a read key answers 403 insufficient_scope, so dashboards and reports can run on a key that cannot move money. a key can also be locked to specific IPs.
the custody model is the point: the hotwallet keys are sealed in an envelope that opens only with your wallet_secret, and every call that moves funds has to carry it. more on security.
the seven integration profiles (store, gateway, exchange, on-ramp only, off-ramp only, mass payouts, crypto card) are drawn call by call in the integration flows, and every endpoint is in the API reference.
faq
What is a stablecoin API?
A REST API that lets your system receive, hold and pay out dollar stablecoins such as USDT and USDC without running nodes or indexers. A complete one covers deposit addresses, deposit detection, consolidation, payouts and reconciliation.
Do I need to buy TRX, SOL, TON or ETH to use the API?
No. The gas is sponsored and the fee is taken inside the operation, in the stablecoin itself. On TRON the network fee of 1.50 USDT is also paid in USDT.
How much does the dolaramp API cost?
Receiving is free and the free plan has no monthly fee. A sweep or withdrawal costs $0.10 on Base and Arbitrum and $1.60 on TRON on the free plan; $0.05 and $1.55 on the pro plan.
Does the API convert stablecoins to local currency?
No. It handles the stablecoin side only. Conversion to and from local currency goes through a licensed exchange or payment provider.