CoinVastSwap now
Developers

The CoinVast public API
Five endpoints. No key. No signup.

Last updated

Five JSON endpoints, no API key: list coins, pull live prices, get a signed quote, create a swap and track it to completion. It is the same API our own swap card calls, so if the site works, your integration works.

Quick facts

Everything you need before the first request

Base URL
https://coinvast.io/api
Authentication
None. No API key, no signup, no allowlist.
Format
JSON in, JSON out. Send Content-Type: application/json on POSTs.
Rate modes
float and fixed both exist at the API level. The site UI currently uses float; the API accepts either.
Quote TTL
30 seconds for float, 60 seconds for fixed. After that the quoteId is rejected.
Order window
30 minutes for the deposit to arrive, then the order expires.
Coin ids
Lowercase, network-qualified where tickers collide: "btc", "xmr", "usdt-trc20", "usdc-base".
Errors
Always { "error": "human readable message" }. 400 bad request or disabled coin, 404 unknown order, 429 if our edge throttles abusive traffic, 500 our fault, 503 maintenance pause or rate source down.
MethodPathReturns
GET/api/coinsthe full coin registry
GET/api/tickerUSD prices for headline coins
POST/api/quotea signed, short-lived rate quote
POST/api/ordercreate a swap from a quote
GET/api/order/{id}live order status + timeline
Reference

GET /api/coins

The full coin registry, currently 32 assets. This is the source of truth for everything else: valid coin ids, per-coin minimums, confirmation counts, and the address pattern we use to sanity-check payout addresses. Cache it for minutes, not days; the list changes when we add coins.

curl https://coinvast.io/api/coins
{
  "coins": [
    {
      "id": "xmr",
      "ticker": "XMR",
      "name": "Monero",
      "network": "Monero",
      "decimals": 8,
      "confirmations": 10,
      "minAmount": 0.05,
      "addressPattern": "^[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}$",
      "custody": "node",
      "popular": true
    },
    { "id": "usdt-trc20", "ticker": "USDT", "network": "Tron (TRC-20)", "...": "..." }
  ]
}
  • id is what every other endpoint expects. Tickers alone collide across networks, so USDT on Tron is usdt-trc20, on Ethereum usdt-erc20, on TON usdt-ton.
  • minAmount is the smallest accepted deposit in coin units. Quotes and orders below it are rejected with a 400.
  • addressPattern is a regex source for a basic format check, not full validation. We apply it server-side to payout and refund addresses; you can apply it client-side to fail fast.
  • Coins with a memo field (tag or memo chains like XRP and TON) may need payoutMemo when you create an order, and their deposit may come with a depositMemo you must include when sending.

GET /api/ticker

USD prices and 24-hour change for a fixed set of headline coins (BTC, ETH, XMR, SOL, LTC, TON, DOGE, KAS). It exists for the price strip on our site. It is not a quote: use /api/quote for any number you intend to trade on. On upstream failure it returns an empty entries array with status 200 rather than an error.

curl https://coinvast.io/api/ticker
{
  "entries": [
    { "id": "btc", "ticker": "BTC", "priceUsd": 106240.0, "change24hPct": 1.42 },
    { "id": "xmr", "ticker": "XMR", "priceUsd": 412.55, "change24hPct": -0.83 }
  ]
}

POST /api/quote

A live quote for a pair and amount. Two modes: float (0.5% spread, quote valid 30 seconds) and fixed (1.0% spread, valid 60 seconds). Both work over the API even though our own UI currently exposes float only. The spread and the payout network fee are separate fields, never hidden in the rate.

curl -X POST https://coinvast.io/api/quote \
  -H "Content-Type: application/json" \
  -d '{ "from": "xmr", "to": "btc", "amountIn": 2.5, "mode": "float" }'
{
  "quote": {
    "id": "eyJmcm9tIjoieG1yIi...<base64url payload>.<hex hmac>",
    "from": "xmr",
    "to": "btc",
    "amountIn": 2.5,
    "amountOut": 0.00965312,
    "rate": 0.00386365,
    "mode": "float",
    "spreadPct": 0.5,
    "networkFee": 0.00006,
    "expiresAt": 1781234567890
  }
}
  • quote.id is the signed quoteId you pass to /api/order. It is self-contained and HMAC-signed; tampering with it or re-using it after expiresAt gets a 400. Treat it as opaque.
  • All amounts are in coin units, not satoshis or wei. rate is amountOut per 1 unit of from, after spread, before the network fee. amountOut is what actually lands: amountIn × rate minus networkFee, floored to the coin's display precision.
  • expiresAt is epoch milliseconds. Refresh rather than racing the clock: a quote with 2 seconds left is a 400 waiting to happen.
  • 400 on unknown coin, identical pair, amount under the coin minimum, or amount too small to clear the network fee. 503 when the upstream price source is down with no cache, or when swaps are paused for maintenance.

POST /api/order

Turns an unexpired quote into a swap and returns a deposit address. The pair, amount and mode in the body must match the quote exactly; any drift gets a 400 telling you to refresh the rate. The deposit must arrive within 30 minutes or the order expires.

curl -X POST https://coinvast.io/api/order \
  -H "Content-Type: application/json" \
  -d '{
    "quoteId": "eyJmcm9tIjoieG1yIi...<from the quote>",
    "from": "xmr",
    "to": "btc",
    "amountIn": 2.5,
    "mode": "float",
    "payoutAddress": "bc1qw4nsga9w3h9jzx0nmtkfh4nv9vh87qj5y3z8ae",
    "refundAddress": "48jWWbXZUd9b2iDVnYrqyTXi3FuKKZBRkVtJ1MYkdnRb...",
    "email": "you@example.com"
  }'
{
  "order": {
    "id": "K7TQ2WXMNR",
    "createdAt": 1781234567890,
    "status": "AWAITING_DEPOSIT",
    "quote": { "...": "the verified quote, echoed back" },
    "payoutAddress": "bc1qw4nsga9w3h9jzx0nmtkfh4nv9vh87qj5y3z8ae",
    "refundAddress": "48jWWbXZUd9b2iDVnYrqy...",
    "depositAddress": "888tNkZrPN6JsEgekjMnAB...",
    "timeline": [
      { "at": 1781234567890, "status": "AWAITING_DEPOSIT",
        "note": "Swap created — waiting for your XMR deposit" }
    ],
    "expiresAt": 1781236367890
  }
}
  • Required: quoteId, from, to, amountIn, mode, payoutAddress. The payout address must match the destination coin's addressPattern.
  • Optional: refundAddress (strongly recommended, validated against the from coin's pattern), payoutMemo for tag and memo chains, and email for status notifications. The email is write-only: it is never returned by any public endpoint, including this response.
  • Send the deposit to depositAddress (plus depositMemo if present) for the exact amountIn, before expiresAt.
  • Order ids are 10 characters from an unambiguous uppercase alphabet, and lookups are case-insensitive.

GET /api/order/{id}

The live state of an order: current status, full timeline with timestamps and transaction hashes (depositTxid, payoutTxid appear once known). Expiry is applied lazily on read, so an abandoned order flips to EXPIRED the first time anyone fetches it past the window.

curl https://coinvast.io/api/order/K7TQ2WXMNR
{
  "order": {
    "id": "K7TQ2WXMNR",
    "status": "SENDING",
    "depositTxid": "5f2a9c...",
    "payoutTxid": "b81d04...",
    "timeline": [
      { "at": 1781234567890, "status": "AWAITING_DEPOSIT", "note": "..." },
      { "at": 1781234890123, "status": "CONFIRMING", "txid": "5f2a9c..." },
      { "at": 1781235241000, "status": "EXCHANGING" },
      { "at": 1781235290456, "status": "SENDING", "txid": "b81d04..." }
    ],
    "...": "same shape as the create response"
  }
}

Unknown id: 404 with { "error": "Order not found" }. There is no list-orders endpoint by design; an order is only reachable by its id.

Order lifecycle

The eight statuses, in order

AWAITING_DEPOSITDeposit address issued, watching the chain for your payment.
CONFIRMINGDeposit seen, waiting for the coin's required confirmations.
EXCHANGINGDeposit confirmed and screened, filling at the quoted terms.
SENDINGPayout transaction broadcast to the destination network.
COMPLETEDPayout confirmed. Final, never clawed back.
EXPIREDNo deposit arrived within the 30-minute window. Final.
REFUNDEDDeposit returned to the refund address. Final.
REJECTEDFailed pre-trade screening, returned, never held. Final.

Polling advice: GET the order every 5 to 10 seconds while it is in flight. Stop on COMPLETED, EXPIRED, REFUNDED or REJECTED; those four are final and the order will never change again. The happy path is AWAITING_DEPOSIT → CONFIRMING → EXCHANGING → SENDING → COMPLETED, and the slowest hop is almost always the deposit chain's confirmations, not us.

Good citizen

No key needed, so do not make us add one

The API is open because keys add friction without adding trust. A few requests keep it that way. Poll orders at 5 to 10 second intervals, not in a tight loop. Quote when a user actually asks for a rate; hammering /api/quote to build your own price feed is what /api/ticker and public price APIs are for.

Quotes are signed and they expire. Do not stockpile quoteIds, and do not try to edit one; the signature check will reject it. And never cache deposit addresses across orders. Each order gets its own deposit address, and sending a second payment to an old one is the slow, painful kind of support ticket.

Partners and listings

Aggregators and listing sites: welcome

If you run an exchange aggregator, a comparison site or a listing directory, this API is enough to integrate the full flow today: coins, quote, create, track. It is the exact same API our own swap card uses, not a separate partner surface, so it gets exercised on every swap on the site.

For anything beyond the public endpoints, email info@coinvast.io with the subject "partner" and a sentence about what you are building. One honest roadmap note: per-order webhooks are not public yet. Today you poll GET /api/order/{id} for status; push notifications for integrators are planned but not shipped, and we would rather say so than document an endpoint that does not exist.

Keep reading

Related pages

First request to first swap in five minutes

Talk to us about integrating

No API key · JSON everywhere · the same API our swap card runs on