API
The recorder's read-only HTTP API: base URL, conventions, status codes and examples.
A recorder serves what it records over plain HTTP. The API is read-only, has no authentication and allows requests from any origin. Flowscope clients load the same paths from the data hub, which runs a recorder; you can use it from curl, scripts or your own tools.
Base URL
The recorder listens on 127.0.0.1:8787 by default. Change it with --listen or FLOWSCOPE_RECORD_LISTEN.
http://127.0.0.1:8787Every path below is relative to that base. Behind a reverse proxy the base is the proxy’s URL, for example https://data.example.com.
Endpoints
| Method | Path | Answer | Type |
|---|---|---|---|
GET | /health | ok | Text |
GET | /v1/markets | Market keys recorded, one per line | Text |
GET | /v1/segments/<key>/ | Days held for a market, one per line | Text |
GET | /v1/segments/<key>/<YYYY-MM-DD>.fsd | One day segment | Binary |
GET | /v1/hl/coins | Hyperliquid coins recorded, one per line | Text |
GET | /v1/hl/status | Accounts, requests and coverage per coin | Text |
GET | /v1/hl/levels/<COIN>?from=<ms>&to=<ms> | TP, SL and liquidation runs | Binary |
GET | /v1/hl/footprint/<COIN>?from=<ms>&to=<ms> | OI, net-long and net-short footprint minutes | Binary |
GET | /v1/options/<COIN>[?at=<ms>] | A coin’s Deribit option chain, the newest or the newest at at | Binary |
Conventions
| Topic | Rule |
|---|---|
| Methods | GET and HEAD. Anything else answers 405. |
| Text answers | text/plain; charset=utf-8, one item per line, each line ending in \n. An empty list is an empty body. |
| Binary answers | application/octet-stream, little-endian. See Segment format, Positions codec and option snapshots. |
| Market keys | <Venue>_<SYMBOL>, for example BinanceUsdm_BTCUSDT. Only ASCII letters, digits, _ and -, shorter than 128 characters. |
| Days | YYYY-MM-DD, UTC. |
| Times | Milliseconds since the Unix epoch, UTC, as integers. |
| Query strings | Read only by /v1/hl/levels, /v1/hl/footprint (from, to) and /v1/options (at); ignored elsewhere. |
| Paths | Matched literally. Percent-encoding is not decoded. |
| Connections | One request per connection. Every answer carries Connection: close. |
Response headers
Every answer, including errors, carries the same set of headers:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 3
Cache-Control: no-store
Access-Control-Allow-Origin: *
Connection: closeCache-Control depends on the endpoint. Past days are cacheable forever; see Caching and CORS.
HEAD
HEAD answers with exactly the headers a GET would send, including Content-Length, and no body. Use it to check whether a day exists, or how large it is, without downloading it.
curl -I http://127.0.0.1:8787/v1/segments/BinanceUsdm_BTCUSDT/2026-10-03.fsdHTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 214392
Cache-Control: public, max-age=31536000, immutable
Access-Control-Allow-Origin: *
Connection: closeStatus codes
| Status | Reason | When | Body |
|---|---|---|---|
200 | OK | Success | The answer |
400 | Bad Request | Invalid market key, invalid day, or an invalid Hyperliquid range | bad market key, bad day or bad range |
404 | Not Found | Unknown path, a day or coin not recorded, Hyperliquid or option recording turned off, or no option snapshot yet | not found, not recorded, coin not recorded, hyperliquid positions not recorded, options of <COIN> are not recorded, option chains not recorded or no snapshot yet |
405 | Method Not Allowed | A method other than GET or HEAD | read-only |
431 | Request Header Fields Too Large | The request head is larger than 8 KiB | request head too large |
503 | Service Unavailable | A recorded Hyperliquid coin has no sample yet | no sample yet |
Error bodies are short plain-text lines meant for people. Use the status code in programs.
A client that does not finish sending its request head within 10 seconds is disconnected without an answer.
CORS
Every answer carries Access-Control-Allow-Origin: *, so a web page on any origin can read the API with a simple GET. Preflight requests (OPTIONS) are not supported and answer 405; plain fetch(url) calls do not trigger one. See Caching and CORS.
Quick tour
BASE=http://127.0.0.1:8787
curl $BASE/health
curl $BASE/v1/markets
curl $BASE/v1/segments/BinanceUsdm_BTCUSDT/
curl -o 2026-10-03.fsd $BASE/v1/segments/BinanceUsdm_BTCUSDT/2026-10-03.fsd
curl $BASE/v1/hl/coins
curl $BASE/v1/hl/status
FROM=$(( ($(date +%s) - 3600) * 1000 ))
TO=$(( $(date +%s) * 1000 ))
curl -o btc.levels "$BASE/v1/hl/levels/BTC?from=$FROM&to=$TO"
curl -o btc.fp "$BASE/v1/hl/footprint/BTC?from=$FROM&to=$TO"
curl -o btc.opt $BASE/v1/options/BTCVersioning
Paths carry the API version (/v1/). Binary payloads carry their own format version in their header: day segments are at version 3 (versions 2 and 1 still decode), Hyperliquid payloads at version 1, option snapshots at FSO2 (the version is in the magic; FSO1 still decodes).