Summary

The proposal has three current-data resources and three historical resources. Global and chain pages use the same endpoints; adding chain only changes the scope. Historical data uses [timestamp, value] tuples, with Unix timestamps in seconds as JSON numbers.

Responses contain data and identity metadata, not ECharts options or frontend view names. Total, breakdown, dominance, pie, bar, and treemap are presentations of these resources—not separate API concepts.

Endpoint reference

This is the proposed surface area. Parameters not listed for an endpoint are not accepted; unsupported parameters or combinations return 400 rather than being silently ignored.

Current data

Endpoint Parameters Returns
GET /v2/assets chain?: string
Canonical chain slug. Omit for global data.
Asset identities and their current snapshot in the requested scope.
GET /v2/assets/:asset :asset: string
Required canonical asset slug. No query parameters.
One asset, its current global snapshot, and current values by chain.
GET /v2/chains None. Chain identities and current stablecoin snapshots.

Historical data

Scope and grouping are separate. chain=ethereum limits the dataset; groupBy=asset splits that dataset into asset series. Omit groupBy for one total; add it for the complete breakdown. Scope one asset or chain directly instead of sending a list of selections.

Endpoint Scope parameters groupBy values Endpoint-only parameters
GET /v2/history/market-cap chain? · asset? asset · chain None.
GET /v2/history/volume chain? · asset? asset · chain · pegCurrency None.
GET /v2/history/supply asset required · chain? chain includeUnreleased?: boolean, default false.

Combination rule: a request cannot scope and group by the same dimension. For example, chain=ethereum&groupBy=chain is invalid because the result could only contain Ethereum. chain=ethereum&groupBy=asset is valid. Supplying both chain and asset returns the total for that exact intersection.

Date parameters accepted by every history endpoint

Parameter Type Default Meaning
start Unix seconds First available point Inclusive start of the requested range. Must be a JSON-safe integer.
end Unix seconds Latest available point Inclusive end of the requested range. Must be a JSON-safe integer.

Example requests

GET /v2/history/market-cap Global market-cap total
GET /v2/history/market-cap?chain=ethereum Ethereum market-cap total
GET /v2/history/market-cap?asset=tether Tether market-cap history across all chains
GET /v2/history/volume?groupBy=pegCurrency&start=1735689600&end=1767225600 Global volume by peg currency for an explicit time range
GET /v2/history/supply?asset=tether&groupBy=chain Tether supply history split by chain

Legacy to v2

The v2 URLs name the resource being requested. Legacy implementation names, special all values, numeric IDs, and frontend chart modes stay out of the public contract.

Use case Legacy Proposed v2
Asset directory GET /stablecoins GET /v2/assets
Chain-scoped assets GET /stablecoins + /stablecoincharts2/:chain GET /v2/assets?chain=ethereum
Asset detail GET /config → /stablecoin/:numericId GET /v2/assets/tether
Market-cap history GET /stablecoincharts2/all-llama-app GET /v2/history/market-cap
Market cap by asset breakdown inside a 36 MB response GET /v2/history/market-cap?groupBy=asset
Volume by currency GET /chart/volume/currency-breakdown GET /v2/history/volume?groupBy=pegCurrency

Response shape

The current app proxy converts upstream records into chart-library configuration. The v2 API should stop at a portable data contract and let each client decide how to render it. There are only three shapes to learn: a current-data list, a historical total, and a grouped historical response.

Grouped history

Current app proxy response GET /v2/history/market-cap?chain=ethereum&groupBy=asset
{ "stackedDataset": [ { "date": "1728345600", "USDT": 119000000000 } ], "stackedDatasetByCurrency": { "USD": [...] }, "stackedDatasetByPegType": { "peggedUSD": [...] }, "stackedChart": [{ "encode": { "x": "date" }, "color": "#..." }] } +{ + "unit": "usd", + "series": [ + { + "id": 1, + "slug": "tether", + "name": "Tether", + "symbol": "USDT", + "data": [ + [1728345600, 119000000000], + [1728432000, 119400000000] + ] + } + ] +}

A series is simply one returned line: one asset when groupBy=asset, one chain when groupBy=chain, or one currency when groupBy=pegCurrency. Timestamps and values are JSON numbers. The request URL already describes the metric, scope, grouping, and selection, so the response does not repeat them.

Historical total

GET /v2/history/market-cap?chain=ethereum

{
  "unit": "usd",
  "data": [
    [1728345600, 137000000000],
    [1728432000, 137500000000]
  ]
}

Current asset list

GET /v2/assets?chain=ethereum

{
  "assets": [
    {
      "id": 1,
      "slug": "tether",
      "name": "Tether",
      "symbol": "USDT",
      "pegCurrency": "USD",
      "circulatingUsd": 119000000000
    }
  ]
}

The complete selector data comes from /v2/assets or /v2/chains. A grouped request returns every matching series. For one asset or chain, use the singular asset or chain scope. The frontend can filter a complete breakdown locally or combine individually cached histories; the API does not accept arbitrary selection lists or create an “Other” series.

Keeping responses small

Measurements below are rough, uncompressed JSON estimates captured on July 27, 2026. They are useful for comparing shapes, not performance guarantees.

Payload Current Proposed Change
Global market-cap total 36 MB ~35 KB ~99.9% smaller
Full asset breakdown 36 MB ~6.6 MB ~81.7% smaller
Asset directory + snapshots Separate responses ~115 KB No history embedded
One asset detail Mixed config + metadata TBD No history embedded

Full breakdowns are cacheable and compressible. A client that needs only one asset or chain can use the singular scope instead. Date ranges reduce transfer size further without introducing frontend selection concepts into the API.

How the app would use it

Pie, horizontal bar, and treemap views read current table data. Historical endpoints power total, breakdown, and dominance views. The API never receives names such as treemap or dominance.

/stablecoins and /stablecoins/:chain

UI dataRequest
Asset table, pie, HBar, treemapGET /v2/assets[?chain=:chain]
Market-cap totalGET /v2/history/market-cap[?chain=:chain]
Market-cap breakdown and dominanceGET /v2/history/market-cap?groupBy=asset[&chain=:chain]
Volume totalGET /v2/history/volume[?chain=:chain]
Volume by tokenGET /v2/history/volume?groupBy=asset[&chain=:chain]
Volume by chainGET /v2/history/volume?groupBy=chain (global page only)
Volume by peg currencyGET /v2/history/volume?groupBy=pegCurrency[&chain=:chain]
USD and token inflowsNot included in v2 until the calculation is defined.

/stablecoins/chains

UI dataRequest
Chain table, pie, HBar, treemapGET /v2/chains
Market-cap totalGET /v2/history/market-cap
Market cap by chainGET /v2/history/market-cap?groupBy=chain
Volume total and breakdownsGET /v2/history/volume[?groupBy=chain|pegCurrency]

/stablecoin/:asset

UI dataRequest
Metadata and current chain distributionGET /v2/assets/:asset
Supply totalGET /v2/history/supply?asset=:asset
Supply by chainGET /v2/history/supply?asset=:asset&groupBy=chain
Volume total and by chainGET /v2/history/volume?asset=:asset[&groupBy=chain]

Decisions in this draft

Identity
Stable URL slugs are public identifiers. Immutable internal IDs remain in responses for joins and migrations.
Global scope
Omitting chain means global. There is no all or all-llama-app sentinel.
Time
Unix timestamps remain seconds on the wire and are always JSON numbers. start and end are inclusive.
Units
Historical responses state their unit once, such as "unit": "usd". Values are raw numbers, never preformatted strings.
Missing values
null means unknown or unavailable. Zero means a measured value of zero; the two are never interchangeable.
Presentation
Colors, encodes, stacks, tooltip settings, and UI view names belong to clients—not the API response.
Cache units
Cache totals, complete breakdowns, and singular asset or chain histories. The API does not create cache entries for arbitrary selector combinations.

Still to decide

  1. Market-cap semantics: confirm whether the source is price-adjusted market cap or circulating supply expressed in USD; rename the endpoint and fields if “market cap” is inaccurate.
  2. Net flows: define whether this means daily deltas, rolling sums, or transfer-derived flows before proposing an endpoint name or response.
  3. Double counting: what is the canonical treatment of bridged representations in global totals and chain breakdowns?
  4. Unreleased supply: is includeUnreleased enough, or should released and unreleased amounts always be separate named series?
  5. Incomplete periods: should the latest partial day be returned with an explicit completeness flag, or omitted until final?
  6. Large breakdowns: should an unfiltered grouped response always return every series, and what response-size safeguards are needed?
  7. Rollout: deprecation window, cache headers, rate limits, and whether legacy URLs redirect or run in parallel.