# Tickerz API

Every index, the Close and the Terminal, as JSON. No key.

## Start here

REST API **https://tickerz.com/api/v1** No key, no signup, CORS open. 120 requests a minute per IP. The same routes answer under `/api`.

OpenAPI **[/openapi.json](https://oracle.tickerz.com/openapi.json)** OpenAPI 3.1, every route and field.

MCP **https://tickerz.com/mcp** Streamable HTTP, no key. [Setup for each assistant](https://oracle.tickerz.com/connect).

## Base URL, limits and headers

- **Base URL**: `https://tickerz.com/api/v1`. The same routes answer under `/api` (versioning).
- **Access**: No key, no signup, CORS open.
- **Cache**: Responses are cached at the edge for 60 to 300 seconds.
- **Formats**: OpenAPI 3.1 at [/openapi.json](https://oracle.tickerz.com/openapi.json). Every page of this site answers `Accept: text/markdown` in Markdown.
- **Attribution**: If you publish these numbers, attribute them as "Tickerz Activity score" with a link.
- **Rate limit**: 120 requests per minute per IP, shared across the reads (indices, board, asset, base-rate, receipts, receipts/dataset, receipts/proof, indices/proof, status, changelog and the rest). The count is kept per server instance, so the limit is a ceiling and never stricter than stated.
- **Headers**: Every counted answer carries `RateLimit-Policy: "api";q=120;w=60`, the IETF RateLimit header fields. An answer made for you alone, an error or a 429 among them, also carries `RateLimit`: calls left and seconds until the window frees one. An answer the edge caches for everyone leaves it out, since its count would be another caller's.
- **Past the limit**: `429` with a `Retry-After` header.
- **Errors**: Problem details

## Indexes

GET `/api/indices`

Every Tickerz index with its latest reading, the newest complete period, its source and terms, its settlement rule, and 30 complete periods for a sparkline. A provisional period (the day still being counted) carries no score.

```
curl "https://tickerz.com/api/indices"
```

- **`indices[].ticker`**: the index, without the $
- **`indices[].latest`**: the newest period read, provisional or not: period, value, change_pct, score, z
- **`indices[].latest_complete`**: the newest complete period: period, value, score, z, band
- **`indices[].source`**: name, url, terms, attribution
- **`indices[].settlement`**: the settlement rule; see_only is true where a count of harm is published and never called
- **`indices[].spark`**: the last 30 complete periods

GET `/api/indices/{ticker}`

One index in full: every period with its settlement value (the number as first published) and any later revision shown beside it, never over it; the open round for calls; and the proof.

```
curl "https://tickerz.com/api/indices/mints"
```

- **`days[]`**: period, value, provisional, change_pct, band, z, settlement_value, revised
- **`days[].note`**: on $JOBS, $UNEMP, $CPI and $CORECPI only: set on a month loaded as history, which holds the Bureau's current figure in value and no settlement_value
- **`first_print`**: the newest complete period's number as first published, as recorded on-chain
- **`round`**: the open call, if any; points only, no money
- **`seal`**: the newest proof covering this index

GET `/api/indices/{ticker}/history.csv`

Every complete period of one index as CSV: the number as first published, revisions, the proof.

```
curl "https://tickerz.com/api/indices/mints/history.csv"
```

- **`columns`**: ticker, period, value, settlement_value, revised, revised_on, band, z, proof_day, bitcoin_height, proof_url
- **`note`**: a twelfth column on $JOBS, $UNEMP, $CPI and $CORECPI: why a month has no settlement_value

GET `/api/indices/{ticker}/rule`

The rule an index is counted under: source, query, unit, decimals, rounding, revision policy, and the source's settlement rights with the clause quoted. Its hash is in every signed print.

```
curl "https://tickerz.com/api/indices/jobs/rule"
```

- **`current`**: the rule, as JSON
- **`hash`**: sha256 of canonical, the exact bytes
- **`versions`**: each version and the date it applies from

GET `/api/indices/{ticker}/report`

The newest signed print of an index, or ?period=YYYY-MM-DD. Answers 404 no_report before the first one. How to check it: /.well-known/tickerz-signer.json and /methodology. Every signed print, with its recount status: /signed.

```
curl "https://tickerz.com/api/indices/jobs/report"
```

- **`report`**: ticker, period, value as an integer with decimals, status (provisional, final or corrected), rule hash, the reads behind it, settleable
- **`hash, signature`**: sha256 of the canonical report, and the publisher's Ed25519 signature
- **`cosignatures`**: the independent recount's signatures
- **`feed`**: the Solana account that holds the print

GET `/api/indices/{ticker}/listing.json`

A market on the index's next number, ready to paste. For LAYOFFS, MINTS, GIGS and WAGE; any other index answers 404 no_kit with the reason. Built from the public mirror when the record cannot be read.

```
curl "https://tickerz.com/api/indices/gigs/listing.json"
```

- **`question`**: one sentence to paste, with {strike} left to fill
- **`period`**: the next UTC day, or week ending Saturday, that has not begun
- **`strikes`**: the 10th, 30th, 50th, 70th and 90th percentiles of the last 30 numbers as first published, two significant digits, equal ones listed once; null under 14 of them
- **`settle_time_utc`**: when the period's number is expected to be published; null for the weekly index, where settle_rule gives the window
- **`settle_rule`**: the number as first published, in column settlement_value, settles it; a later revision never changes it
- **`tie_rule`**: a print equal to the strike resolves No
- **`recount`**: the commands that recount a print from the chain; null where none exists
- **`paste`**: the whole market as plain text, under 600 characters

GET `/api/indices/close?day=`

The Tickerz Close: each index's newest complete period, frozen once the day's proof is written, with the proof's digest. The newest Close when day is omitted.

```
curl "https://tickerz.com/api/indices/close"
```

- **`day`**: the Close day, UTC
- **`rows[]`**: ticker, period, value, score, change_pct
- **`seal`**: day, digest_sha256, bitcoin_height (null until Bitcoin confirms)
- **`attestation`**: the same Close attested on Base with EAS: chain, uid, tx, schema_uid, easscan (the attestation page), basescan (the transaction). Null until it is on Base, about ten minutes after the proof is written
- **`eas`**: the attestation page alone, the same link as attestation.easscan

## Terminal

GET `/api/board`

The full Terminal: every displayed asset with its 24h move and current activity score, sorted by activity score, highest first. Assets without a score follow, by market cap. No prices: the vendors' terms do not allow passing them on, so the site shows them and the API does not. HTTP 503 when halted.

```
curl https://tickerz.com/api/board
```

- **`updated_at`**: ISO timestamp of the latest snapshot
- **`halted`**: true when the Terminal cannot serve live scores (for example database not connected); UI shows HALTED
- **`assets[]`**: symbol, name, class (crypto \| equity), mcap_rank, move_24h, score (the activity score, 0-100, null until a 14-day baseline exists), score_1h (the score one hour earlier), vol_mult (24h volume over the asset's 30-day baseline mean, measured, one decimal, null until a 14-day baseline exists), ts, stale (true when ts is not current: crypto more than 2 hours behind, equities more than 2 hours behind the newest equity tick, or older than 4 days)
- **`assets[].heat, assets[].heat_1h`**: deprecated aliases of score and score_1h, same values, until at least 2026-12-31
- **`breadth`**: unusual, scored, share, band: how many scored, current coins are at 70 or more right now, the share, and its band (lone under 3%, mid, crowd at 30% or more). Null when halted

GET `/api/asset/{symbol}`

One asset in depth: latest reading, 30 days of activity score readings, any open event, past events with receipts, and where it trades. No price, volume or market cap, for the same reason as the board.

```
curl https://tickerz.com/api/asset/btc
```

- **`asset`**: symbol, name, class, mcap_rank and listing metadata
- **`latest`**: move_24h, ts
- **`vol_mult`**: measured volume multiple of the latest snapshot, one decimal, null under a 14-day baseline
- **`scores_30d[]`**: ts, score: activity score readings for the last 30 days, every fourth stored reading (hourly), oldest first; the last point is the latest score
- **`heat_7d[]`**: ts, heat: deprecated alias of scores_30d, the same readings in the old shape, until at least 2026-12-31. Each heat equals the score at the same ts
- **`open_event`**: the active event with score_at_open and peak_score, or null
- **`past_events[]`**: the latest 10 closed events with score_at_open, peak_score and 24h / 7d / 30d receipts. peak_heat is the deprecated alias of peak_score
- **`venues[]`**: where it trades: venue, name, kind (spot \| perp \| futures \| options \| prediction), venue_symbol, url, verified_at, trades_as (the venue's ticker when it differs, such as kPEPE or 1000PEPE), multiplier, us_available (false where the venue does not serve US users: Hyperliquid, Polymarket). Checked nightly against each venue's own product list: Binance.US, Coinbase, Kraken and Robinhood spot, Coinbase futures, Hyperliquid perpetuals, Kalshi and Polymarket. Plain links, not paid
- **`venues_checked_at`**: the oldest of the latest complete reads of every venue list for the asset's class. Null when any of them is more than 7 days old, when the asset was added after it, or when a venue could not confirm the asset either way. An empty venues[] means not listed only when this is set
- **`asset.active, asset.display`**: both true when the asset is on the Terminal. Otherwise (pegged, left out, or sharing a stock's ticker) the last reading stays readable, the nightly venue check skips the asset and venues_checked_at is null

GET `/api/base-rate/{symbol}`

What historically happened after a move like this asset's current one: the median, spread and share that beat the benchmark at 1, 7 and 30 days, next to an ordinary day. Only on days with an activity score of 70 or more, and only for groups that hold. Otherwise base_rate is null with a reason. Stocks are measured against SPY. Same as the MCP base_rate tool. HTTP 404 not_listed for an unknown symbol, 503 when halted.

```
curl https://tickerz.com/api/base-rate/sol
```

- **`(the rate)`**: symbol, move_24h, bucket, breadth, coin_in_study, n, n_dates, top_date_share, horizons (1d, 7d, 30d), ordinary, edge_7d_pts, edge_7d_ci, plain, caveat, source; benchmark on stock rates only
- **`base_rate, reason`**: when there is no rate the body is symbol, base_rate null and reason: a score below 70, a withheld group, a reading that is not current, or the stock study

GET `/api/receipts?limit=30`

The public record: closed events (cooling or resolved), newest first, each with receipts at 24h, 7d and 30d. A receipt not yet due has ret_pct and resolved_at null.

```
curl "https://tickerz.com/api/receipts?limit=50"
```

- **`events[]`**: id, opened_at, closed_at, open_price, assets (symbol, name), score_at_open (the activity score that opened the event), peak_score (the highest while open), trigger_z_vol, trigger_z_move, open_vol_mult (volume multiple measured at open), driver_tag, driver_confidence, driver_source_headline, driver_source_url (the stated cause and its source; unclassified reads Driver: not identified), receipts. peak_heat is the deprecated alias of peak_score
- **`receipts[]`**: horizon (24h \| 7d \| 30d), due_at, ret_pct and resolved_at (null until it resolves; resolved_at is the next Terminal tick at or after due_at), benchmark (BTC for crypto, SPY for stocks) and benchmark_ret_pct, its return over the same window (null until filled)
- **`proofs[]`**: OpenTimestamps rows: event_id, horizon (open \| 24h \| 7d \| 30d), digest_sha256, bitcoin_height, stamped_at. open is the event as called. New events go on-chain within about an hour of open. Events already on the record when that began on September 22 2026 went on-chain later, some after their outcome: compare stamped_at with opened_at. A receipt card says Called before the outcome only for an open record put on-chain within 2 hours of open and confirmed in Bitcoin
- **`limit`**: 1 to 100, default 30

GET `/api/card/{symbol}`

PNG share card for the asset, rendered with Satori. Cached at the edge. HTTP 404 for a ticker Tickerz does not track; an asset that is not on the Terminal gets a card that says so.

```
curl -OJ https://tickerz.com/api/card/btc
```

- **`Content-Type`**: image/png
- **`symbol`**: ticker, case-insensitive

GET `/api/status`

Public Terminal health: ok, degraded, or halted. Degraded when the newest snapshot is older than 45 minutes, a receipt is overdue, or a proof has no Bitcoin height after 24 hours. HTTP 503 when halted. HTML twin at /status.

```
curl https://tickerz.com/api/status
```

- **`state`**: ok \| degraded \| halted
- **`checked_at`**: ISO timestamp of this check
- **`board`**: halted, updated_at, age_minutes, asset_count, scored_count
- **`receipts`**: halted, recent_count, resolved_7d (receipts resolved in the last 7 days)
- **`proofs`**: pending, stuck, oldest_hours
- **`receipt_lag`**: overdue, oldest_overdue_min, late, resolved_checked
- **`checks[]`**: id, ok, detail

GET `/api/changelog`

Curated Terminal ship notes plus recent open and closed events. No token required.

```
curl https://tickerz.com/api/changelog
```

- **`generated_at`**: ISO timestamp
- **`ships[]`**: date, pr, title, summary
- **`score_events[]`**: id, kind (open \| closed; a closed event's receipts may still be pending), symbol, name, opened_at, score_at_open (the activity score that opened the event), peak_score (the highest while open)
- **`score_halted`**: true when the activity score feed is unavailable
- **`heat_events[], heat_halted`**: deprecated aliases of score_events and score_halted, until at least 2026-12-31. heat_events keeps the old kind value resolved where score_events says closed. Each event also carries peak_heat, equal to peak_score

GET `/api/receipts/dataset`

Open dataset of closed events (cooling or resolved), one flat row per event. Returns stay null until each receipt resolves. Includes hidden assets with display=false. Omits trigger z-scores. Paginate with limit and offset (max 5000 per page). First export window starts 2026-08-27. Free for personal and non-commercial use with attribution; see /terms section 04.

```
curl "https://tickerz.com/api/receipts/dataset?since=2026-08-27&format=csv&limit=1000"
```

- **`since`**: YYYY-MM-DD, clamped to a minimum of 2026-08-27
- **`format`**: json (default) or csv
- **`limit`**: 1 to 5000, default 1000
- **`offset`**: pagination offset, default 0
- **`rows[]`**: event_id, opened_at, symbol, name, class, display, heat_at_open, reference_price, ret_24h, resolved_24h, ret_7d, resolved_7d, ret_30d, resolved_30d, score_at_open, peak_score, benchmark, benchmark_ret_24h, benchmark_ret_7d, benchmark_ret_30d
- **`benchmark`**: BTC for crypto, SPY for stocks. benchmark_ret_24h, _7d and _30d are its returns over the same windows as ret_24h, ret_7d and ret_30d, null until filled
- **`score_at_open`**: activity score of the tick that opened the event
- **`peak_score`**: highest activity score while the event was open
- **`heat_at_open`**: deprecated: despite the name it is the peak, equal to peak_score. Use score_at_open for the opening score. Remains until at least 2026-12-31
- **`next_offset`**: next page offset, or null when done
- **`halted`**: true when the database is not connected

## Proofs and Base

GET `/api/receipts/proof?event_id=&horizon=`

OpenTimestamps proof for one event record. horizon=open is the event as called. New events go on-chain within about an hour of open. Events already on the record when that began on September 22 2026 went on-chain later, some after their outcome, so compare stamped_at with opened_at. 24h, 7d and 30d are the resolved receipts. Add format=ots to download the .ots file. Verify at opentimestamps.org or with the ots CLI.

```
curl "https://tickerz.com/api/receipts/proof?event_id=EVENT_ID&horizon=24h"
```

- **`digest_sha256`**: SHA-256 of canonical_json
- **`canonical_json`**: the exact bytes that were hashed: compact JSON with keys in the order below
- **`canonical`**: receipts: event_id, symbol, opened_at, open_price, horizon, resolved_at, ret_pct. open: event_id, symbol, opened_at, open_price, horizon, score_at_open, trigger_z_vol, trigger_z_move
- **`stamped_at`**: when the digest was sent to the OpenTimestamps calendars
- **`bitcoin_height`**: Bitcoin block height once the stamp upgrades, else null
- **`ots_url`**: same endpoint with format=ots

GET `/api/indices/proof?day=`

OpenTimestamps proof for one day of the Tickerz Index: every complete period written or revised since the last proof, hashed and stamped in Bitcoin. The newest proof when day is omitted. Add format=ots to download tickerz-seal-DAY.ots and verify it with the OpenTimestamps client or at opentimestamps.org.

```
curl "https://tickerz.com/api/indices/proof?day=2026-09-23"
```

- **`day`**: the proof day, UTC
- **`digest_sha256`**: SHA-256 of canonical_json
- **`canonical_json`**: the exact bytes that were hashed
- **`stamped_at`**: when the digest was sent to the OpenTimestamps calendars
- **`bitcoin_height`**: Bitcoin block height once the stamp upgrades, else null
- **`ots_proof_base64`**: the .ots file, base64

BASE `EAS.getAttestation(uid)`

Each day's Close is attested once on Base with EAS, holding the proof's digest and every reading. A contract reads it from EAS at `0x4200000000000000000000000000000000000021` and accepts it when the attester is the company wallet `0x2D4A1c7e1069aD62d45b7218524cf01f67A68F74` and the schema is `0xdf8161575c15391d8fa95e18a440548605db46cec95f843811cf89cbf204d48e`. The attestation cannot be revoked and never expires.

```
Attestation memory a = IEAS(0x4200000000000000000000000000000000000021).getAttestation(uid);
require(a.attester == 0x2D4A1c7e1069aD62d45b7218524cf01f67A68F74);
require(a.schema == 0xdf8161575c15391d8fa95e18a440548605db46cec95f843811cf89cbf204d48e);
(uint32 closeDay, bytes32 sealDigest, bytes32[] memory tickers, uint32[] memory periods,
 uint128[] memory valuesE6, uint8[] memory scores) =
  abi.decode(a.data, (uint32, bytes32, bytes32[], uint32[], uint128[], uint8[]));
```

- **`schema`**: uint32 closeDay, bytes32 sealDigest, bytes32[] tickers, uint32[] periods, uint128[] valuesE6, uint8[] scores
- **`closeDay`**: the Close day as yyyymmdd, 20261004
- **`sealDigest`**: the SHA-256 digest of the next day's proof (/api/indices/proof?day=), the one stamped in Bitcoin
- **`tickers[]`**: each index ticker as text, padded right to 32 bytes
- **`periods[]`**: each reading's own period as yyyymmdd; a weekly index keeps its week
- **`valuesE6[]`**: each reading in millionths: 51272000000 is 51,272
- **`scores[]`**: the Activity score, 0 to 100; 255 means none
- **`uid`**: the attestation field of /api/indices/close?day=, or the public index at base.easscan.org

## The referee

- **Question**: One on-chain attention question per crypto event: `$SYM reads 40 or more at` the event's open plus 24 hours, UTC.
- **Answers**: `at_or_above` or `below`. No login, one answer per caller per question and at most 3 per address.
- **Resolves**: From the first Activity score Tickerz stores at or after that minute. Void when none lands within 3 hours.
- **Nulls**: Three, frozen when it opens: the base rate, persistence and always below. Tickerz answers with the base rate and is graded too.
- **Closes**: Answers close 4 hours after the question opens, and the crowd split stays hidden until then. No ranking, no prizes.
- **For people**: [/questions](https://oracle.tickerz.com/questions)

GET `/api/questions?state=open&symbol=&limit=`

Every question, newest first, with calibration over every resolved question. state is open (still waiting on its reading), resolved (resolved or void) or all.

```
curl "https://tickerz.com/api/questions?state=open"
```

- **`questions[]`**: id, event_id, symbol, statement, threshold, answers (key to label), state (open \| closed \| resolved \| void), accepting_answers, event_opened_at, opens_at, closes_at, resolves_at, at_open (score, vol_mult)
- **`nulls`**: base_rate (answer, hits, n, share), persistence (answer, score, ts), always (answer). Frozen when the question opened
- **`tickerz`**: answer and rule (base_rate). Tickerz answers 40 or more when the base rate is at least half
- **`answers_count`**: answers from outside Tickerz so far, agents left out
- **`crowd`**: at_or_above, below, n, majority (null on a tie), mean_probability. Null until answers close. Agents never count in it
- **`agents_count, agents`**: answers from agents, counted apart from the crowd; agents is n and labeled[] (label, answer, probability), null until answers close
- **`outcome, grades`**: the reading it resolved on, and who was right: crowd (null without a majority), tickerz (null when the question was not recorded before answers closed), base_rate, persistence, always
- **`seal, answer_batches[]`**: OpenTimestamps state (pending \| stamped \| confirmed), sealed_before_close, digest_sha256, stamped_at, bitcoin_height, bitcoin_block_time
- **`calibration`**: resolved, void, and hits and n for crowd, tickerz, base_rate, persistence and always, over every resolved question

GET `/api/questions/{id}`

One question with proofs[]. The question's canonical_json and .ots proof are served at once. Each hourly answer batch's proof waits until answers close, so a batch cannot show the split early. sha256(canonical_json) equals digest_sha256.

```
curl https://tickerz.com/api/questions/QUESTION_ID
```

- **`proofs[]`**: id, kind (question \| answers), digest_sha256, canonical_json, n_answers, bitcoin_height, stamped_at, ots_base64
- **`question canonical`**: compact JSON, keys in this order: kind, question_id, event_id, symbol, statement, threshold, event_opened_at, opens_at, closes_at, resolves_at, score_at_open, vol_mult_at_open, base_rate_hits, base_rate_n, persistence_score, persistence_ts, null_base_rate, null_persistence, null_always, tickerz_answer
- **`answers canonical`**: kind, batch_id, question_id, sealed_at, answers[] (id, answer, probability, answered_at), sorted by answered_at then id. No caller is in it

POST `/api/questions/{id}/answer`

Answer an open question. No key, no login. One answer per caller per question: a repeat returns 200 with already_answered true and does not echo the first answer. At most 3 answers per question from one address, whatever the user agent (409 address_cap past that). 410 once answers close. 20 answers per minute per address, shared with the MCP tool submit_forecast. The body must be JSON. Unlike the reads, this route sends no CORS headers, so another site's page cannot answer from its visitors' browsers; curl, servers and agents are unaffected.

```
curl -X POST https://tickerz.com/api/questions/QUESTION_ID/answer \
  -H 'content-type: application/json' \
  -d '{"answer":"below","probability":0.35}'
```

- **`answer`**: at_or_above (it reads 40 or more) or below
- **`probability`**: optional, 0 to 1: the chance it reads 40 or more. Must agree with the answer; 0.5 fits either
- **`agent`**: optional: the name of an agent answering for someone, 1 to 32 letters, digits, spaces, dots, hyphens or underscores (400 bad_agent otherwise). The answer is stored as an agent's, never counts in the crowd split, and is shown by name beside the crowd once answers close. The one-answer rule still applies
- **`returns`**: 201: answer_id, question_id, answer, probability, answered_at, closes_at, already_answered false, split_shown_at. Keep answer_id: it is in the recorded batch. 200 on a repeat: question_id, closes_at, already_answered true
- **`caller`**: a keyed hash of the question, the address and the user agent for the one-answer rule, and a keyed hash of the question and the address (IPv6 by its /64) for the per-address cap. Neither is published

## Webhooks

- **When**: Push within the hour after an event opens or a receipt resolves.
- **Limit**: One HTTPS URL per email. No API key.
- **Challenge**: On subscribe Tickerz GETs your URL with `?challenge=`; echo the token as plain text or `{"challenge":"<token>"}`.
- **Signature**: Deliveries are signed with HMAC-SHA256 of the raw body (`X-Tickerz-Signature: sha256=...`). Three attempts with backoff.
- **Works with**: Any endpoint that can answer the challenge: your own script, a serverless function, or a Make scenario with a webhook response. Discord webhook URLs and Zapier catch hooks cannot answer it and need a relay.

POST `/api/webhooks/subscribe`

Register one URL per email. Confirms via GET challenge on the URL. A new email gets the signing secret once; an email already on file is left as it is and gets the same ok answer. Same-site JSON only: 403 cross_site, 415 not_json, 429 after five signups from one address in ten minutes.

```
curl -X POST https://tickerz.com/api/webhooks/subscribe \
  -H 'content-type: application/json' \
  -d '{"email":"you@example.com","url":"https://hooks.example.com/tickerz"}'
```

- **`email`**: contact address; unique; one URL
- **`url`**: HTTPS endpoint that echoes ?challenge=
- **`secret`**: HMAC key; shown once on confirm

POST `(your URL)`

Inbound delivery for event_opened and receipt_resolved. Verify the signature before acting.

```
{
  "id": "delivery-id",
  "type": "event_opened",
  "created_at": "2026-09-12T01:00:00.000Z",
  "data": {
    "symbol": "GME",
    "score": 85,
    "heat": 85,
    "event_id": "uuid",
    "horizon": null,
    "text": "$GME Activity score 85/100. Event opened. Volume is 2.6 times normal. Price +6.6% in 24h."
  }
}
```

- **`type`**: event_opened \| receipt_resolved
- **`data.symbol`**: ticker
- **`data.score`**: activity score, 0-100 or null. On receipt_resolved, the score that opened the event
- **`data.heat`**: deprecated alias of data.score, same value, until at least 2026-12-31
- **`data.event_id`**: event uuid
- **`data.horizon`**: 24h \| 7d \| 30d on receipts; else null
- **`headers`**: X-Tickerz-Signature, X-Tickerz-Delivery, X-Tickerz-Event

## MCP

- **Server**: `https://tickerz.com/mcp` (Streamable HTTP). No key. Free. Rate-limited like the public API. [Setup for each assistant](https://oracle.tickerz.com/connect)
- **Tools**: Fourteen read-only tools and one write tool. Same data as the JSON API.
- **Read-only**: `board`, `asset`, `base_rate`, `receipts`, `methodology`, `open_questions`, `get_question`, `arena`, `list_indices`, `get_index`, `get_listing_kit`, `get_rule`, `get_report`, `list_feeds`. Each marked readOnlyHint.
- **Writes**: `submit_forecast`, an answer to an open question, on the same rules as the answer endpoint.
- **Prompts**: Four, listed in a client's prompt or slash menu: `whats_unusual`, `check_asset`, `index_close`, `index_reading`. Each one names the tools to call, so the answer comes from the record.

```
# Cursor (mcp.json, Streamable HTTP)
{
  "mcpServers": {
    "tickerz": {
      "url": "https://tickerz.com/mcp"
    }
  }
}

# Desktop config files and other stdio-only clients via mcp-remote
npx -y mcp-remote https://tickerz.com/mcp
```

## Errors · RFC 9457

Every error from `/api` is `application/problem+json`: `type`, `title`, `status`, `detail` and `instance`, plus `error`, the short code older clients already read, a `hint` and `docs`. Fields a route has always sent stay beside them. An address with no endpoint is a 404 problem; a method an endpoint does not take is a 405 problem with `Allow`. A 402 from the machine tier keeps the x402 body its clients expect.

```
curl -i https://tickerz.com/api/v1/asset/nope
HTTP/2 404
content-type: application/problem+json

{"type":"https://tickerz.com/docs#error-not_listed","title":"Not listed","status":404,
 "detail":"No asset with that symbol is tracked by the Terminal.","instance":"/api/v1/asset/nope",
 "error":"not_listed","hint":"GET /api/board lists every symbol on the Terminal.",
 "docs":"https://tickerz.com/docs#errors"}
```

- **`not_found`**: Not found. Nothing is at this address. Every endpoint is listed in https://tickerz.com/openapi.json.
- **`method_not_allowed`**: Method not allowed. This endpoint does not take that method. The Allow header lists the methods it takes.
- **`bad_request`**: Bad request. The request could not be read. Check the parameters against https://tickerz.com/openapi.json.
- **`not_listed`**: Not listed. No asset with that symbol is tracked by the Terminal. GET /api/board lists every symbol on the Terminal.
- **`bad_ticker`**: Unknown index. No Tickerz index has that ticker. GET /api/indices lists every index.
- **`no_kit`**: No listing kit. This index offers no listing kit. A kit is offered for an index whose source's terms are read and allow settlement.
- **`bad_day`**: Bad day. day must be a real calendar day, YYYY-MM-DD. Leave day out for the newest.
- **`bad_ts`**: Bad time. ts must be an ISO 8601 time.
- **`halted`**: Halted. The record could not be read. Readings hold at their last value. Retry in a minute. GET /api/status says what is down.
- **`unavailable`**: Unavailable. The record could not be read just now. Retry in a minute.
- **`proof_unreadable`**: Proof unreadable. The stored proof could not be decoded. Write to desk@tickerz.com with the day or event.
- **`rate_limited`**: Too many requests. This address sent more requests than the endpoint takes in its window. Wait the number of seconds in Retry-After. RateLimit-Policy names the limit.
- **`tier_closed`**: Machine tier closed. The paid machine tier is closed for now. Paid endpoints are not open yet.
- **`cross_site`**: Cross-site request. This endpoint takes requests from tickerz.com, the API or the MCP server, not from another site's page.
- **`not_json`**: Not JSON. Send the body as JSON with content-type application/json.
- **`bad_answer`**: Bad answer. The answer is not one this question takes.
- **`bad_agent`**: Bad agent name. agent is 1 to 32 letters, digits, spaces, dots, hyphens or underscores.
- **`bad_side`**: Bad side. A call is higher or lower.
- **`predict_off`**: Calls off. This index takes no calls.
- **`address_cap`**: Address cap. This address has reached its cap for this item.
- **`bad_email`**: Bad email. That email address could not be read.
- **`invalid_url`**: Bad URL. The webhook URL must be HTTPS and public.
- **`challenge_failed`**: Challenge failed. The URL did not echo the challenge token.
- **`unauthorized`**: Unauthorized. This endpoint is not public.
- **`internal_error`**: Internal error. The server failed to answer this request. Retry once. If it repeats, write to desk@tickerz.com.

## Versions and deprecation · v1

`/api/v1` is the stable path of the API as it stands, declared in [openapi.json](https://oracle.tickerz.com/openapi.json). `/api` serves the same routes and stays. A new key or a new endpoint ships into v1 and is noted in the [changelog](https://oracle.tickerz.com/changelog). A change that would break a client, a key removed or renamed or a type changed, goes to a new version path, never into v1, with one exception announced on September 22 2026: the heat aliases below leave the API on or after `2026-12-31`. They are marked deprecated in openapi.json.

When a whole endpoint is to be retired, it answers with `Deprecation` (RFC 9745) and `Sunset` (RFC 8594) headers and a `Link` to this section at least 90 days before it stops. No endpoint is deprecated today, so no response carries them: the heat aliases are keys inside live endpoints, and a Sunset header there would say the endpoint itself ends.

## Key names · September 22 2026

Each old heat key stays beside its new name, with the same value, until at least `2026-12-31`. Read the new key.

- **`heat`**: `score`
- **`heat_1h`**: `score_1h`
- **`heat_7d`**: `scores_30d`: despite the old name it always held 30 days of readings, every fourth stored tick. Its points keep the old shape, ts and heat
- **`peak_heat`**: `peak_score`
- **`heat_events`**: `score_events`: the same events, with kind resolved where score_events says closed
- **`heat_halted`**: `score_halted`
- **`heat_at_open`**: `peak_score`: it was always the peak. score_at_open is the opening score
- **`data.heat`**: `data.score` in webhook deliveries
- **`HeatEvent`**: `ScoreEvent`: the webhook entry in openapi.json, operationId scoreWebhookDelivery. HeatEvent and heatWebhookDelivery stay beside it, marked deprecated

## Sources and terms

- **Model**: [Methodology](https://oracle.tickerz.com/methodology)
- **For machines**: `/llms.txt` and [/openapi.json](https://oracle.tickerz.com/openapi.json).
- **Data**: Crypto and stock prices via [Alchemy](https://www.alchemy.com/) (stocks through their xStocks, tokenized shares).
- **Terms**: Nothing served by this API is financial advice; see the [Terms of Use](https://oracle.tickerz.com/terms).
