Market data and fees
Step by step: reference prices, FX rates, candles and live network fees, and how to attribute them.
# Market data and fees
Show a fiat value next to a crypto amount, draw a price chart and display the current network fee. You will use the market endpoints for **reference prices and FX rates** aggregated from public sources, and [Live stats](https://docs.rarebl.com/api/stats/live) and [Recommended fees](https://docs.rarebl.com/api/fees/recommended) for fees.
> **These are reference prices, not Rarebl trading rates.** Rarebl does not guarantee that you can buy or sell at these prices, and they are not an offer. Do not use them to settle a trade.
## Before you start
- Nothing to install. These are read-class calls: 5 per second, burst 20 per IP, so cache results for a few seconds instead of calling per page view.
- A decimal type for money. Chain amounts are exact decimal strings and `price` is one too.
## Step 1 — Get a price
[Prices](https://docs.rarebl.com/api/market/price) takes the **median of the fresh sources** and excludes any source more than 2% from the median. Quotes are `usd`, `eur`, `gbp`, `ghs` and `ngn` (the last four are derived from the dollar price through the FX rates).
```bash cURL
curl "https://api.rarebl.com/open/market/price?assets=BTC,ETH"e=usd"
```
```js JavaScript
const { prices } = await rarebl.marketPrice(['BTC', 'ETH'], 'usd'); // or fetch the URL above
```
```python Python
prices = c.price(["BTC", "ETH"], "usd")
```
```php PHP
$prices = $c->price(['BTC', 'ETH'], 'usd');
```
```bash Shell
rarebl price BTC,ETH --quote usd
```
**You should see** one entry per asset (the Bitcoin entry shortened to three sources).
```json
{ "asset": "BTC", "quote": "USD", "price": "63421.45", "change24h": "-7.1155",
"sources": [ { "id": "binance", "pair": "BTC/USD", "price": 63449.83, "volume": 11.75039 },
{ "id": "kraken", "pair": "BTC/USD", "price": 63426.4, "volume": 5752.38744852 },
{ "id": "coinbase", "pair": "BTC/USD", "price": 63421.45, "volume": 16529.56926348 } ],
"stale": false, "updatedAt": "2026-11-15T01:00:51.309Z" }
```
| Field | Meaning |
| --- | --- |
| `asset`, `quote` | The symbol and the quote currency (upper case in replies). |
| `price` | A decimal string. |
| `change24h` | The percent change over 24 hours as a string such as `"-1.25"`, or `null`. |
| `sources` | The exchanges that went into the median. An entry with `excluded: true` was an outlier; `usdtProxy: true` marks a USDT market used because fewer than two USD or USDC markets were fresh. |
| `stale` | True when there were not enough fresh sources, or two sources disagree by more than 4%. Show the price with a warning, or hide it. |
| `updatedAt` | When it was computed. |
## Step 2 — Convert with FX
[FX](https://docs.rarebl.com/api/market/fx) returns currency rates against a base, with the source and update time.
```bash cURL
curl "https://api.rarebl.com/open/market/fx?base=usd"es=ghs,ngn"
```
**You should see** the rates keyed by quote currency.
```json
{ "rates": { "GHS": "11.747527", "NGN": "1352.072165" }, "source": "er-api", "updatedAt": "2026-11-15T00:37:02.017Z" }
```
## Step 3 — Draw a chart
[History](https://docs.rarebl.com/api/market/history) returns OHLC candles (`1m`, `1h` or `1d`; at most 1,000 per call). Use `from` and `to` to page through longer ranges. Candle `volume` is `null`, and a fiat quote other than USD converts candles at the current FX rate, which is an approximation.
```bash cURL
curl "https://api.rarebl.com/open/market/history?asset=BTC"e=USD&interval=1h&from=1763161200"
```
**You should see** candles, oldest first.
```json
{ "candles": [
{ "ts": "2026-11-14T23:00:00.000Z", "open": "64136.4", "high": "64174.2", "low": "64068.4", "close": "64139.5", "volume": null },
{ "ts": "2026-11-15T00:00:00.000Z", "open": "64123.32", "high": "64469.5", "low": "63430.38", "close": "63478.34", "volume": null }
] }
```
## Step 4 — Show the network fee
[Live stats](https://docs.rarebl.com/api/stats/live) gives every chain's head, mempool and fee in one call. It refreshes about every 2 seconds, so poll no faster than that.
```bash cURL
curl "https://api.rarebl.com/open/stats/live"
```
```js JavaScript
async function refresh() {
const { data } = await (await fetch('https://api.rarebl.com/open/stats/live')).json();
for (const c of data.chains) {
const el = document.querySelector(`[data-fee="${c.id}"]`);
el.textContent = c.fee?.standard != null ? `${c.fee.standard} ${c.fee.unit}` : 'unavailable';
}
}
refresh();
setInterval(refresh, 2000);
```
**You should see** an entry per chain with a `fee`. A chain that is `lagging` or `down` has `fee: null`: show "unavailable" rather than a number.
```json
{ "id": "btc", "status": "ok", "tip": { "height": 975869, "hash": "000000000000000000018a26062659ab25520a26b803d3e4ec9568a85c3f4235", "time": "2026-11-15T01:00:09Z" },
"mempool": { "count": 55876, "bytes": 22836693 }, "fee": { "unit": "sat/vB", "standard": "0.12" }, "checkedAt": "2026-11-15T01:01:02Z" }
```
When the user can choose a speed, call [Recommended fees](https://docs.rarebl.com/api/fees/recommended) for that chain.
```bash cURL
curl "https://api.rarebl.com/open/fees/recommended?chain=btc"
```
**You should see** slow, standard and fast rates and their unit (`details` omitted here).
```json
{ "chain": "btc", "unit": "sat/vB", "slow": "0.12", "standard": "0.12", "fast": "0.12", "baseFee": null, "updatedAt": "2026-11-15T01:01:02Z" }
```
The unit depends on the chain, so always show it next to the number:
- **UTXO chains:** `sat/vB`. The three speeds map to estimator targets of 24, 6 and 2 blocks on Bitcoin. Bitcoin Cash has no estimator on its node, so all three values are the relay minimum.
- **ETH:** `Gwei`, with `baseFee` set and priority fee percentiles in `details`.
- **TRON:** `sun`; `standard` is the energy price in sun per energy unit, and `slow` and `fast` are `null`.
For a UTXO transaction the fee is about `rate × vsize`: a 142 vB transaction at 1 sat/vB costs about 142 sats.
## Step 5 — Show a fiat value, with attribution
```js JavaScript
const { data } = await (await fetch('https://api.rarebl.com/open/market/price?assets=BTC"e=GHS')).json();
const p = data.prices[0];
if (!p.stale) {
const fiat = (Number(balanceBtc) * Number(p.price)).toFixed(2); // for display only: use a decimal library if you store it
label.textContent = `${fiat} GHS · reference price`;
}
```
- Say where the number comes from: show "Reference price from public exchange feeds via Rarebl" (or similar) near it, and state that it is not a trading rate.
- Exchange data comes from Binance, Coinbase Exchange, Kraken, Bitstamp, Bitfinex, OKX, Bybit and KuCoin; FX from ExchangeRate-API (open.er-api.com) and the ECB.
- Check `stale` and `updatedAt`, and decide what your product does when the data is old.
- Map a token contract to a price symbol with [Assets](https://docs.rarebl.com/api/market/assets) (for example USDT on `eth` and on `tron`), then ask for that symbol. [Tickers](https://docs.rarebl.com/api/market/tickers) lists the individual exchange tickers behind a price.
## Common errors
| Reply | What it means | What to do |
| --- | --- | --- |
| `API400` with `data.param` | An unknown asset, quote or interval, or a bad range. | Check the symbol against [Assets](https://docs.rarebl.com/api/market/assets). |
| `API429` | More than 5 reads per second. | Cache for a few seconds and honour `Retry-After`. |
| `stale: true` in a price | Not enough fresh sources, or they disagree. | Show a warning or hide the price. |
| `fee: null` in live stats | That chain is `lagging` or `down`. | Show "unavailable" and keep the last value. |
| `API502` | A node is unavailable. | Keep the last value and retry after a longer pause. |
## Next steps
- Decide a fee for a payment: [Send a transaction](https://docs.rarebl.com/guides/send-a-transaction) and [Estimate](https://docs.rarebl.com/api/tx/estimate).
- Get fee updates pushed: [Live data over WebSocket](https://docs.rarebl.com/guides/websocket) (`fees:<chain>`).
- Errors and retries: [Errors and rate limits](https://docs.rarebl.com/guides/handle-errors).