Getting Started

The ByteTree API provides real-time and historical data for FX rates, global stocks, crypto assets, and computed ByteTrend metrics.

Base URL

All endpoints are served from:

https://api.bytetree.io

Authentication

Every endpoint except GET /api/health requires an API key, sent as a bearer token:

curl https://api.bytetree.io/api/assets \
-H "Authorization: Bearer YOUR_API_KEY"

See Authentication for how to obtain a key and the full scope and error model.

Response Format

All endpoints return JSON by default. You can request alternative formats using the format query parameter:

FormatContent-TypeDescription
jsonapplication/jsonDefault. Standard JSON.
csvtext/csvComma-separated values (RFC 4180).
toontext/toonTOON — compact, token-efficient encoding ideal for LLM consumers.
# CSV
curl "https://api.bytetree.io/api/rates?format=csv"

# TOON
curl "https://api.bytetree.io/api/rates?format=toon"

Unsupported format values return 400 Bad Request.

Response Conventions

Paginated list envelope

List endpoints that support consumer-driven pagination return:

{
  "count":  10,
  "total":  4287,
  "limit":  10,
  "offset": 0,
  "data":   [ /* records on this page */ ]
}
FieldDescription
countLength of the returned data array (records on this page).
totalFull match count for the same filter, ignoring limit and offset. Computed in parallel with the paged query.
limit / offsetEchoed input. Consumers paginate by advancing offset until offset + count >= total.
dataArray of records for this page.

This is the shape for top-level list endpoints/api/assets, /api/rates, /api/prices, /api/universes, /api/fx among them.

Compatibility: the envelope is additive. Callers that read only count and data are unaffected. See the Changelog for the cutover note.

Which shape to expect

Rather than memorising a list, read it from the request. Pagination fields appear exactly where you can meaningfully page, and data is an array everywhere except one endpoint:

ShapeReturnsWhere
Paginated list{count, total, limit, offset, data[]}Top-level list endpoints — the envelope above
Entity series{symbol, count, data[]} (or {pair, …})One entity’s series, e.g. /api/prices/:symbol, /api/fx/:symbol/series. Not paginated — it’s one thing’s history, not a list
Keyed map{count, data} where data is an object keyed by symbol/api/metrics/latest only. count is the number of keys

The keyed map is the one to watch: data is an object, not an array, so iterating it as a list fails rather than returning nothing.

Single-record reads

Single-record endpoints — e.g. GET /api/assets/:id, GET /api/rates/:pair — return { data: ... } and may include the lookup key as a sibling field. They are not paginated.

Unknown query parameters are rejected

Passing a parameter an endpoint doesn’t accept returns 400, rather than being silently ignored:

{ "error": "Unknown query parameter 'typ'. Did you mean 'type'? Accepted parameters: type, region, sector, limit, offset." }

Close misspellings get a suggestion, and the accepted list is always echoed. An endpoint that takes no parameters says so explicitly.

This is deliberate. Silently ignoring an unrecognised parameter means a filter you thought you applied simply didn’t apply, and the response looks plausible — a filtered query returning unfiltered data with a 200. Failing loudly turns a wrong answer into an obvious error.

format is accepted everywhere and never counts as unknown. Authentication is checked first, so an invalid key returns 401 rather than 400, even if the request also carries a bad parameter.

Available Endpoints

MethodPathDescription
GET/api/healthHealth check
GET/api/currenciesCurrency code to name mapping
GET/api/ratesLatest rates for all FX pairs
GET/api/rates/sparklines12-month weekly closes per pair
GET/api/rates/:pairDaily time series for one pair
GET/api/assetsList assets with optional filters
GET/api/assets/:idSingle asset by ID or symbol
GET/api/pricesLatest price per symbol
GET/api/prices/sparklines12-month weekly closes per symbol
GET/api/prices/:symbolDaily price time series for one symbol
GET/api/fxTracked FX pairs with latest scores and trend regime
GET/api/fx/:symbolLatest computed metrics for one FX pair
GET/api/fx/:symbol/seriesDaily metric time series for one FX pair
GET/api/fx/:symbol/pricesClose-only price series for one FX pair
GET/api/metrics/latestLatest metrics across all symbols
GET/api/metrics/:symbol/latestLatest computed metrics snapshot
GET/api/metrics/:symbolComputed metrics time series
GET/api/metrics/distributionCross-sectional metric distributions
GET/api/metrics/regime-transitionsTrend-regime transition event log
GET/api/summarySingle-screen dataset overview
GET/api/universesAvailable universes and dimension configs
GET/api/universes/:universeLatest group metrics across all dimensions
GET/api/universes/:universe/:categoryGroups within a dimension
GET/api/universes/:universe/:category/:groupTime series for one group
GET/api/universes/:universe/:category/configGrouping config for a dimension

:universe takes a slug your key can reach. Examples throughout this documentation use macro, but your key’s universes depend on your subscription — list them with GET /api/universes and substitute one of yours. A universe outside your scope returns 403; see Universes.

Data Sources

All market data is sourced from institutional-grade data providers and updated daily. FX pairs are quoted as XXXUSD (e.g. GBPUSD = 1.27 means 1 GBP buys 1.27 USD).

Quick Example

Fetch the latest rate for GBP/USD:

curl https://api.bytetree.io/api/rates/GBPUSD
{
  "pair": "GBPUSD",
  "count": 365,
  "data": [
    {
      "date": "2025-02-17T00:00:00.000Z",
      "open": 1.2580,
      "high": 1.2620,
      "low": 1.2560,
      "close": 1.2601
    }
  ]
}