# 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://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://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://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 (none today)
- **`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 public 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, as /api/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://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://tickerz.com/connect)
- **Tools**: Fourteen read-only tools and two write tools. 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. `name_a_number`, a number to count, on the same rules as `POST /api/indices/requests`.
- **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://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://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://tickerz.com/methodology)
- **For machines**: `/llms.txt` and [/openapi.json](https://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://tickerz.com/terms).
