Zum Inhalt springen
KOTOVADOCS
App starten

Currencies, networks and icons

Als Markdown anzeigen

Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.

The catalogue endpoints list every currency Kotova X can swap, the networks each one can be sent and received on, and the icons to show next to them. They need no key.

A currency on one network is called a leg, and every request names a leg with two identifiers. Send both, always: the same currency on two networks is two different legs.

  • currency is the ticker, such as BTC or USDT. Requests match it in any case; answers always use upper case.
  • network is the network code, such as btc, trx or eth. Requests match it in any case; answers always use lower case.

So USDT on TRON is {"currency": "USDT", "network": "trx"}, and USDT on Ethereum is {"currency": "USDT", "network": "eth"}. Numeric ids never appear in the API. A leg also has a ticker field, which is only for display (on some networks a currency trades under another symbol); identifiers always use currency.

A currency must match ^[A-Za-z0-9.]{1,12}$ and a network must match ^[A-Za-z0-9_-]{1,24}$. Anything else is a 400 invalid_request with details.reason set to invalid_format. A well-formed pair of identifiers that is not in the catalogue is a 422 unknown_currency.

When the catalogue renames or merges a currency, the old spelling keeps working as an alias. GET /currencies lists a currency’s old spellings in aliases; USDT, for example, lists USDT0. A request that uses an alias is answered with the canonical identifiers, plus a deprecated_alias warning that names both:

{
"code": "deprecated_alias",
"message": "from.currency \"USDT0\" is a deprecated alias of \"USDT\"; use \"USDT\".",
"field": "from.currency",
"given": "USDT0",
"canonical": "USDT"
}

The same mechanism applies to network codes. When you see this warning, switch to the canonical value. Warnings never make a request fail, so log them where you will notice them.

GET /currencies, GET /networks and GET /pairs (and GET /sources, see Sources) share the same rules.

  • No key and no weight. Send no Authorization header: it is ignored, and leaving it out lets the CDN answer. The calls do not count against your account’s rate limit.
  • Browsers welcome. Answers carry Access-Control-Allow-Origin: *, so a web page can read the catalogue directly. HEAD works on every one of these endpoints.
  • One page. A list answer has data, has_more, next_cursor, catalog_version and updated_at. has_more is always false and next_cursor always null: the whole list comes in one answer. catalog_version changes whenever the catalogue is rebuilt, and updated_at is when that happened.
  • Strict query strings. An unknown or repeated query parameter, or an empty segment such as ?&, is a 400 invalid_request (unknown_parameter or duplicate_parameter). GET /currencies and GET /networks take no parameters at all, so a cache-busting ?t=… is refused rather than ignored.
  • Per-IP limit. Calls that reach the server, rather than the CDN, are limited to 120 per minute per IP address. Over that, the answer is a 429 rate_limited with details.reason set to ip and a Retry-After header.
  • Unavailable catalogue. If the catalogue cannot be read, the answer is a 503 service_unavailable with details.reason set to catalog_missing and a Retry-After header.

Successful answers are cached by the CDN with Cache-Control: public, s-maxage=60, stale-while-revalidate=86400 and carry a weak ETag such as W/"394da0f044c4-5be2a7d1c09e". Send the ETag back in If-None-Match and an unchanged answer comes back as a 304 Not Modified with no body. Error answers are never cached (Cache-Control: no-store).

The catalogue changes rarely, but it does change: currencies are added, and a source can be switched on or off at any time, which changes send, receive and the source lists without a new catalog_version. The ETag covers both, so compare ETags rather than versions. A good pattern is to keep a copy on your server and revalidate it every few minutes with If-None-Match.

Terminal window
# First call: note the ETag header.
curl -si https://api.kotova.io/x/v1/currencies | grep -i '^etag'
# Later: revalidate. 304 means your copy is current.
curl -si https://api.kotova.io/x/v1/currencies \
-H 'If-None-Match: W/"394da0f044c4-5be2a7d1c09e"' | head -n 1

GET /currencies returns every currency that can be sent or received through the API right now, each with the networks it can be used on. It takes no parameters.

Terminal window
curl -s https://api.kotova.io/x/v1/currencies

An answer, shortened to one currency:

{
"data": [
{
"currency": "BTC",
"name": "Bitcoin",
"type": "cryptocurrency",
"icon": {
"url": "https://cdn.kotova.io/images/currencies/BTC.svg",
"fallback_url": "https://assets.kotova.io/images/currencies/BTC.svg"
},
"aliases": [],
"networks": [
{
"network": "btc",
"network_name": "Bitcoin",
"name": "Bitcoin",
"ticker": "BTC",
"contract_address": null,
"token_standard": null,
"decimals": 8,
"memo": { "supported": false, "label": null },
"address_format": "standard",
"icon": {
"url": "https://cdn.kotova.io/images/currencies/BTC.svg",
"fallback_url": "https://assets.kotova.io/images/currencies/BTC.svg"
},
"send": true,
"receive": true,
"send_sources": ["sideshift", "chainflip", "changenow", "ffio"],
"receive_sources": ["sideshift", "chainflip", "changenow", "ffio"]
}
]
}
],
"has_more": false,
"next_cursor": null,
"catalog_version": "394da0f044c4",
"updated_at": "2026-11-10T07:00:52Z"
}

Each entry in data is a currency:

Field Type Meaning
currency string The identifier: the ticker, in upper case.
name string Display name, such as Tether.
type string Extensible: cryptocurrency, stablecoin, utility_token, meme and others. Accept values you do not know.
icon icon or null The currency’s icon (see Icons).
aliases array of strings Old spellings still accepted for this currency.
networks array One entry per network the currency can be used on through the API.

Each entry in networks is a leg:

Field Type Meaning
network string The identifier: the network code, in lower case.
network_name string The network’s display name, such as TRON.
name string The currency’s display name on this network, such as Tether (TRC20).
ticker string Display ticker on this network. Never use it as an identifier.
contract_address string or null The token contract; null for a network’s native coin.
token_standard string or null TRC20, ERC20 and so on; null for a native coin.
decimals integer On-chain decimals of this leg. Amounts carry at most min(decimals, 12) fractional digits.
memo object Whether the network takes a memo, and what it calls it (see Memos).
address_format string Extensible: standard, or lightning_invoice on the Lightning network.
icon icon or null The icon for this currency on this network.
send boolean Usable as from through the API right now.
receive boolean Usable as to through the API right now.
send_sources array of slugs Sources that accept this leg as from, in display order. Empty when send is false.
receive_sources array of slugs Sources that pay out this leg, in display order. Empty when receive is false.

A currency is listed when at least one of its legs can be used in at least one direction. A leg that cannot be used in either direction is left out.

send and receive say whether a leg can be used as from or as to right now. A quote with a leg in a direction it does not support fails with a 422 currency_unavailable. Lightning legs always have receive: false in v1: receiving on Lightning is not available yet.

The per-leg source lists let you apply your own source exclusions without an extra request. A pair is served by exactly the sources that appear in the from leg’s send_sources and in the to leg’s receive_sources. Remove the sources you exclude; if nothing is left, do not offer the pair, because a quote would fail. You can narrow it further with the fields from GET /sources, such as rate_types or freeze_protection.

// Sources that could serve from → to, minus the slugs you exclude.
function servingSources(currencies, from, to, excluded = []) {
const leg = (id) =>
currencies
.find((c) => c.currency === id.currency)
?.networks.find((n) => n.network === id.network);
const a = leg(from);
const b = leg(to);
if (!a?.send || !b?.receive) return [];
return a.send_sources.filter(
(slug) => b.receive_sources.includes(slug) && !excluded.includes(slug)
);
}
servingSources(data, { currency: 'BTC', network: 'btc' },
{ currency: 'USDT', network: 'trx' }, ['changenow']);

These lists say which sources serve a leg. Whether a source returns a quote for a given amount, at a given moment, is only known when you request a quote.

Some networks need a memo (also called a destination tag) next to the address. memo says whether a network takes one:

  • supported is true when the network takes a memo;
  • label is what the network calls it, such as Memo or Destination Tag, and null when supported is false.

When supported is true, show a memo field labelled with label wherever your user enters an address, and send it as to_memo or refund_memo when you create the order. A memo on a network that does not take one is refused with a 422 memo_not_supported.

Try itGET/currenciesNo key
Connection

GET /networks returns every network that has at least one currency usable through the API. It takes no parameters.

Terminal window
curl -s https://api.kotova.io/x/v1/networks

One entry from the answer:

{
"network": "xrp",
"name": "XRP Ledger",
"symbol": "XRP",
"family": "other",
"icon": {
"url": "https://cdn.kotova.io/images/chains/xrp.svg",
"fallback_url": "https://assets.kotova.io/images/chains/xrp.svg"
},
"memo": { "supported": true, "label": "Destination Tag" },
"address_format": "standard",
"evm_chain_id": null,
"explorer_tx_url_template": "https://xrpscan.com/tx/{hash}"
}
Field Type Meaning
network string The identifier: the network code, in lower case.
name string Display name, such as XRP Ledger.
symbol string Symbol of the network’s native coin.
family string Extensible, lower case: utxo, evm, solana, tron, cosmos, near or other. Accept values you do not know.
icon icon or null The network’s icon.
memo object supported and label, as on a leg.
address_format string Extensible: standard, or lightning_invoice on the Lightning network.
evm_chain_id integer or null The EVM chain id; null outside the evm family.
explorer_tx_url_template string or null A block explorer link for a transaction. Replace {hash} with the transaction hash.

The list has the same envelope as GET /currencies: has_more, next_cursor, catalog_version and updated_at.

Try itGET/networksNo key
Connection

GET /pairs tells you what a leg can be swapped into, what can be swapped into it, or whether one particular pair is served. There is no list of every pair: give at least one side.

Parameter Meaning
from Currency sent. Needs from_network.
from_network Network of from. Needs from.
to Currency received. Needs to_network.
to_network Network of to. Needs to.

What you get depends on the sides you give:

  • Both sides: that pair, when at least one source serves it, or an empty data list when none does.
  • from and from_network only: every leg the from leg can be swapped into.
  • to and to_network only: every leg that can be swapped into the to leg.
Terminal window
curl -s 'https://api.kotova.io/x/v1/pairs?from=BTC&from_network=btc&to=USDT&to_network=trx'
{
"data": [
{
"from": { "currency": "BTC", "network": "btc" },
"to": { "currency": "USDT", "network": "trx" },
"rate_types": ["fixed", "variable"],
"sources": ["sideshift", "changenow", "ffio"]
}
],
"has_more": false,
"next_cursor": null,
"catalog_version": "394da0f044c4",
"updated_at": "2026-11-10T07:00:52Z",
"warnings": []
}

Each pair has:

Field Type Meaning
from object currency and network of the leg sent.
to object currency and network of the leg received.
rate_types array The rate types (fixed, variable) that at least one serving source offers.
sources array of slugs The sources that serve this pair, in display order.

A pair carries no amounts and no limits: those come only from a quote. warnings holds a deprecated_alias warning when you used an old spelling.

Status Code When
400 invalid_request No side at all (details.reason is from_or_to_required), half a side (required, with details.field naming the missing parameter), an identifier in the wrong format, or an unknown parameter.
422 unknown_currency A leg is not in the catalogue. details.side says which.
422 currency_unavailable A leg exists but cannot be used in that direction right now.
422 same_currency Both sides name the same leg.
Try itGET/pairsNo key
Connection
Parameters

Currency sent.

Network of `from`.

Currency received.

Network of `to`.

Currencies, legs, networks, sources and Kotova X itself come with an icon. Every icon is an object with two URLs:

{
"url": "https://cdn.kotova.io/images/currencies/BTC.svg",
"fallback_url": "https://assets.kotova.io/images/currencies/BTC.svg"
}
  • url is the file on Kotova’s CDN, https://cdn.kotova.io.
  • fallback_url is the same path on Kotova’s mirror, https://assets.kotova.io. Some networks block the CDN; if url fails to load, retry once with fallback_url. It is null when an icon is hosted elsewhere, in which case url is that address as stored.
  • The icon itself can be null. Show a placeholder, such as the ticker’s first letters, rather than a broken image.

A leg’s icon is the currency’s icon on that network: the leg’s own artwork where there is one, otherwise the currency’s icon, otherwise the network’s.

Use the URLs exactly as returned. They are absolute and already percent-encoded, paths are case-sensitive, and they do not follow a naming pattern, so never build one from a ticker or a network code.

<img src="https://cdn.kotova.io/images/currencies/BTC.svg"
data-fallback="https://assets.kotova.io/images/currencies/BTC.svg"
onerror="this.onerror = null; if (this.dataset.fallback) this.src = this.dataset.fallback;"
alt="BTC" width="24" height="24">
// Builds an <img> for an icon object from the API (or null).
function iconImg(icon, alt, size = 24) {
const img = document.createElement('img');
img.alt = alt;
img.width = img.height = size;
if (!icon) return img; // or render your own placeholder
img.src = icon.url;
img.addEventListener('error', function retry() {
img.removeEventListener('error', retry);
if (icon.fallback_url) img.src = icon.fallback_url;
});
return img;
}

Icon files are served with Access-Control-Allow-Origin: *, and browsers and proxies may cache them. You may also cache or self-host unmodified copies of Kotova-hosted icon files to display Kotova data. A file can change under the same URL, so refresh any copy you keep, for example once a week.

The Kotova X icon, which you must show wherever you present a Kotova X quote or order, is covered in Display requirements.