Reference

Docs

Three endpoints, no auth, JSON only. Every quote is signed so a consumer can verify the price, the band and the provenance all came from the same key.

Endpoints

EndpointReturns
GET /api/quotesEvery tracked instrument, priced against one proxy snapshot.
GET /api/quote/:tickerOne instrument, signed, with the digest and signer address.
GET /api/healthUpstream reachability, signer address, current session. Returns 503 when upstream is down.

Quote fields

FieldMeaning
priceThe number to use. Equal to anchorPrice when provenance is TRADED or STALE; drifted when DERIVED.
anchorPriceThe last price actually observed on tape, before modelling.
confidenceBpsTwo-sided uncertainty in basis points. Capped at 1500; beyond that a quote is not worth publishing.
session0 REGULAR · 1 PRE · 2 POST · 3 CLOSED · 4 HOLIDAY
provenance0 TRADED · 1 DERIVED · 2 STALE
lastTradeTimeUnix seconds of the last print, reconciled against the exchange calendar rather than taken from upstream.
driftBpsHow far the anchor was moved by the model. Zero when TRADED.
maxDeviationBpsSpread between the highest and lowest source reading.

Provenance, and how to treat each value

ValueMeansSafe to
TRADEDObserved print, session open, under 5 minutes old.Settle, liquidate, mark.
DERIVEDTape shut. Last close drifted against a 24/7 proxy.Mark to market, display, size positions. Not liquidate.
STALENo usable anchor, or the tape is open and upstream stopped printing.Nothing automatic. During an open session this signals an upstream fault, so we deliberately do not model over it.

The confidence model

live print:
  bps = BASE[session] + maxDeviationBps       // 8 regular, 35 pre/post

gap (DERIVED or STALE):
  sigma = overnightSigmaBps * (hours/17.5)^k  // k and sigma both fitted
  bps   = 1.96 * sigma + maxDeviationBps      // two-sided 95%
  bps   = max(bps, BASE[CLOSED])              // never tighter than a live one

bps = clamp(bps, 1, 1500)

Both sigma and k come from calibration.json, fitted by npm run calibrate against two years of realised close-to-open gaps. The measured exponent is k ≈ 0.107, not the 0.5 a random walk in calendar time would imply. See the problem for why.

The model's own error is deliberately not added on top. The residual sigma is what remains after applying the beta, so it already contains it; adding a drift term would double-count and break the validated coverage.

The floor exists because of a bug caught in testing: without it, the band collapsed the moment the session label flipped from CLOSED to PRE on Monday morning, even though the underlying data had not improved at all. A stale anchor does not become trustworthy because the opening bell rang.

Coverage

The band claims to be a 95% interval, so that claim is tested by replaying every historical gap and counting how many landed inside it. All eight instruments fall between 93.4% and 96.4%, across roughly 500 gaps each. Re-run npm run calibrate to reproduce.

Verifying a signature

import { verifyMessage } from "viem";

const r = await fetch("/api/quote/HOOD").then((r) => r.json());

const ok = await verifyMessage({
  address:   r.signer,
  message:   { raw: r.digest },
  signature: r.signature,
});

The digest is keccak256 over the abi-encoded tuple (string ticker, uint128 price, uint64 confidenceBps, uint8 session, uint8 provenance, uint8 sourceCount, uint64 maxDeviationBps, uint64 lastTradeTime, uint64 publishTime), with price scaled to 8 decimals. That is exactly the tuple the on-chain verifier reconstructs, so the band cannot be stripped from the price without invalidating the signature.

Limits