Skip to content
Get an API key

Every record this API returns carries three fields that describe the data rather than the market. They exist because a normalized interface over eighteen different venues can either hide the differences between them or state them, and hiding them produces integrations that are quietly wrong.

{
"marketId": "",
"title": "",
"asOf": "2026-07-03T09:15:00.000Z",
"provenance": { "source": "venue-rest" },
"capabilities": { "read": true, "trade": false, "depth": true, "history": false }
}

asOf is the moment the data was captured, not the moment you asked. A cached catalog read and a live order-book read both return successfully; only asOf distinguishes a snapshot taken seconds ago from one taken minutes ago.

Use it rather than your own clock when displaying freshness. A timestamp you generate on receipt describes your request, not the data.

provenance.source records how the value was obtained. The values you will encounter include venue-rest (fetched from the venue’s own API), predictefy-live (served from our live engine), and fixture (test data — you should never see this in production).

This matters when values disagree. Two reads of the same market with different asOf and different provenance are not a contradiction; they are two different observations, and provenance tells you which pipeline produced each.

capabilities — what this venue actually supports

Section titled “capabilities — what this venue actually supports”

capabilities is a per-venue map: read, trade, depth, history. It is the field to branch on before assuming a verb will work.

The flags are conservative by design. history: false means a history lane has not been proven for that venue, not that no data could ever exist. trade: false on a catalog record does not mean trading is impossible — public execution availability is documented separately per venue in Trading & execution.

For the full per-verb picture, read the venue’s has map or the coverage matrix.

When a venue genuinely does not expose something — no public trades tape, no per-address order list — the API returns NOT_SUPPORTED rather than an empty array.

This distinction is the point:

  • An empty array means the query ran and found nothing. A market with no trades today returns an empty tape.
  • NOT_SUPPORTED means the query cannot run here. The venue has no tape at all.

Collapsing the two loses real information. An integration that treats NOT_SUPPORTED as “no results” will report “no recent trades” for a venue that has never published a single one, which is a different and more misleading statement.

Handle it explicitly:

try {
const trades = await client.gemini.fetchTrades(marketId);
render(trades); // may legitimately be empty
} catch (err) {
if (err instanceof NotSupportedError) {
renderUnavailable('This venue does not publish a public trades tape.');
} else {
throw err;
}
}

A venue without an order book — an automated market maker, or a pari-mutuel pool — still returns a book-shaped response so that one integration works everywhere. That response is labelled synthetic.

A synthetic book is a faithful representation of price. It is not executable depth, and must never be presented as orders a user could fill against, or fed into a sizing calculation as though it were. Venue coverage records which venues have a real book.

The same discipline applies to cross-venue output

Section titled “The same discipline applies to cross-venue output”

Price differences between venues are reported as indicative price discrepancies — observed gaps, not opportunities. Only fetchArbitrage performs a live executable assessment, against live asks, open status, real depth, the fee model, and resolution-equivalence. See Cross-venue data.

The rule underneath all of this is the same: the API states what it knows and how well it knows it, and expects the integration to preserve that rather than flatten it.