Alert schema
One alert is the object terminal.alert.v1. The events feed, GET /v1/alerts/{id}, a terminal webhook, and a test built from a real alert all use it. sequence, sent_at, and the via on links.alert are what change between copies. On a read or a feed event, sequence is null and via is api. On a webhook, via is webhook.
Times are UTC, ISO 8601, with milliseconds and Z. A missing price is null. Null means unavailable. It does not mean zero. Prices are US dollars.
The labeled example further down uses fixed figures so you can see the shape. Those figures are not a live quote. A live read of your own alert follows the same field names.
Price
A Price is an object.
- Field:
value. Type: number. Null: no. Meaning: US dollars, as stored. Above zero on a price that fired an alert. - Field:
currency. Type: string. Null: no. Meaning:USDin version 1. - Field:
source. Type: string. Null: yes. Meaning:coinbaseorkraken. Null only where a measured price had no source recorded. - Field:
at. Type: time. Null: yes. Meaning: For a trade, the trade time. For a 1-minute candle, the end of that minute.
Event
- Field:
schema. Type: string. Null: no. Meaning: Alwaysterminal.alert.v1. - Field:
id. Type: string. Null: no. Meaning:alert_<alert id>for an alert.test_<delivery id>for a test. Stable across retries. Drop duplicates by this id. - Field:
type. Type: string. Null: no. Meaning:alert.fired, oralert.testfor a test. - Field:
alert_id. Type: integer. Null: yes. Meaning:alerts.id. Null on a test that is not tied to an alert. - Field:
sequence. Type: integer. Null: yes. Meaning: Per webhook destination, in the order Terminal first tried to send. Null on the feed, on reads, and on tests. - Field:
fired_at. Type: time. Null: no. Meaning: When the check found the condition met. - Field:
sent_at. Type: time. Null: no. Meaning: When Terminal built this copy. - Field:
rule. Type: object. Null: no. Meaning: The rule that fired. - Field:
service. Type: object. Null: yes. Meaning: Null for a rule on your account. Set when the alert arrived through an exchange subscription. - Field:
asset. Type: object. Null: no. Meaning:symbolandname.namefalls back to the symbol when the name is unknown. - Field:
price. Type: Price. Null: no. Meaning: The last trade when the condition was met. - Field:
measured. Type: object. Null: no. Meaning: What the check measured. The fields depend onrule.kind. - Field:
headline. Type: string. Null: no. Meaning: The event line, plain text, at most 300 characters. - Field:
context. Type: object. Null: no. Meaning: Other numbers recorded at fire time. - Field:
note. Type: object. Null: no. Meaning: The note and its state. - Field:
receipts. Type: object. Null: no. Meaning: The price 1 hour, 4 hours, 24 hours, and 7 days later. - Field:
links. Type: object. Null: no. Meaning: Where to open the alert. - Field:
notice. Type: string. Null: no. Meaning: The notice. - Field:
terms. Type: object. Null: no. Meaning:versionandurl.
Rule and condition
- Field:
rule.id. Type: integer. Null: no. Meaning: The rule id. - Field:
rule.name. Type: string. Null: no. Meaning: The current name, text you wrote, 1 to 80 characters. - Field:
rule.kind. Type: string. Null: no. Meaning:price_above,price_below,percent_change,volume_spike, orunusual_move. - Field:
rule.scope. Type: string. Null: no. Meaning:symbolfor one coin, orwatchlistfor every coin on the watchlist. - Field:
rule.condition. Type: object. Null: no. Meaning: The condition as it was when the alert fired. A later edit of the rule does not change it. - Field:
rule.cooldown_seconds. Type: integer. Null: no. Meaning: The rule's current wait before it can fire again, in seconds.
Requests and responses use the public condition names.
- Kind:
price_above,price_below. Public condition:level(US dollars, above 0, at most 10,000,000).rearm_pct(0.1 to 10, default 1).. Units: Responses also includerearm_level, in US dollars. - Kind:
percent_change. Public condition:threshold_pct(0.1 to 100, required).window:15m,1h,4h, or24h, default1h.direction:up,down, oreither, defaulteither.. Units:threshold_pcthas no sign.directionsays which way. - Kind:
volume_spike. Public condition:threshold_multiple(1.5 to 20, default 3).window, default1h.. Units: Responses also includemin_usd, 10000 US dollars, the least trading in the window that can fire it. - Kind:
unusual_move. Public condition:sigmas(2 to 6, default 3).window, default1h.
Measured
percent_change and the move half of unusual_move:
- Field:
change_pct. Type: number. Meaning: Signed percent,(to.value / from.value - 1) × 100. - Field:
from. Type: Price. Meaning: Reference price at the start of the window. - Field:
to. Type: Price. Meaning: The last trade at the check. Equal to the eventprice.
unusual_move also has range_pct (percent), sigma_pct (percent), and samples (integer count of earlier windows).
price_above uses high (Price) and from_minute (time). price_below uses low (Price) and from_minute.
volume_spike:
- Field:
ratio. Type: number. Unit: Window volume against the 20-day average. - Field:
window_volume. Type: number. Unit: Units of the coin traded in the minutes that exist. - Field:
window_minutes. Type: integer. Unit: How many of the window's minutes exist. - Field:
window_usd. Type: number. Unit: US dollars. - Field:
baseline_per_minute. Type: number. Unit: Average units per minute. - Field:
baseline_days. Type: number. Unit: Days behind that average. - Field:
from_minute,to_minute. Type: time. Unit: First and last minute counted.
A minute the feed did not record is left out. It is not counted as zero.
Context
- Field:
change_pct. Type: object. Null: no. Meaning: The coin's own signed percent over15m,1h,4h, and24h. Each key is present. Each value is a number or null. - Field:
volume_1h. Type: object. Null: yes. Meaning:ratio,window_volume,window_minutes,baseline_per_minute,baseline_days. Null when the hour or the baseline was not recorded. - Field:
market. Type: object. Null: no. Meaning: KeysBTCandETH, except the alert's own coin. Each value is null, or{ "price": Price, "change_pct": { "15m", "1h", "4h", "24h" } }.
Note
- Field:
status. Type: string. Null: no. Meaning:none(no note requested),pending,ready,facts_only, orfailed. - Field:
text. Type: string. Null: yes. Meaning: The note, only whenstatusisready. Otherwise null. At most two sentences. - Field:
ai_written. Type: boolean. Null: no. Meaning: True only whentextis set. - Field:
label. Type: string. Null: yes. Meaning:AI-written · numbers from market datawhenai_writtenis true. Otherwise null. Show this label withtext. - Field:
reason. Type: string. Null: yes. Meaning: Why there is no note:off,failed,rejected,no_facts,cap, orpaused. Null when status isready,pending, ornone.
A fresh alert with no note request has status none. A webhook often leaves while the note is pending. Read GET /v1/alerts/{alert_id} for the later state. note_facts on that response is null unless status is ready and a fact sheet was stored. When it is set, it is { "at": time, "lines": [ ... ] }.
Receipts
The object always has the keys 1h, 4h, 24h, and 7d.
- Field:
status. Type: string. Null: no. Meaning:pending,done, ormissing.missingmeans no price was recorded. It is not zero. - Field:
due_at. Type: time. Null: yes. Meaning:fired_atplus the horizon. Null on a test, and if the receipt row is gone. - Field:
price. Type: Price. Null: yes. Meaning: Set only whendone. - Field:
change_pct. Type: number. Null: yes. Meaning: Set only whendone. Signed percent against the event price. - Field:
recorded_at. Type: time. Null: yes. Meaning: When Terminal recorded it. Null unlessdoneormissing.
Receipts are a price record. Terminal does not score them or rank them.
Links
- Field:
alert. Type: string. Null: no. Meaning: The alert page for the owner:/app/alerts/<id>?via=apiorvia=webhook. A test points at notifications settings. - Field:
api. Type: string. Null: yes. Meaning:/v1/alerts/<id>. Null on a test. - Field:
share. Type: string. Null: yes. Meaning:/s/<slug>when you shared it. Otherwise null. - Field:
proof. Type: string. Null: yes. Meaning: Where the anchor can be checked. Null while anchoring is off, before the minute is anchored, and on a test.
The record
GET /v1/rules/{id}/record lists alerts for one rule inside the plan's history. summary is null while summary totals are off. Each horizon count has recorded, pending, and missing. next_before is an alert id when another page exists, otherwise null.
Names Terminal does not write
Terminal does not put these names on an object it writes: action, side, signal, recommendation, target, confidence, bullish, bearish.
Strings Terminal writes do not tell you to buy, sell, or hold. Text you wrote yourself is kept as you wrote it: a rule name, a destination label, and a template stored as a string. The notice is the product sentence on Notice and terms.
Example
Example. These are not live prices.
{
"schema": "terminal.alert.v1",
"id": "alert_9001",
"type": "alert.fired",
"alert_id": 9001,
"sequence": 42,
"fired_at": "2026-10-12T14:03:00.000Z",
"sent_at": "2026-10-12T14:03:01.215Z",
"rule": {
"id": 41,
"name": "SOL falls 5% in 1 hour",
"kind": "percent_change",
"scope": "symbol",
"condition": { "threshold_pct": 5, "window": "1h", "direction": "down" },
"cooldown_seconds": 3600
},
"service": null,
"asset": { "symbol": "SOL", "name": "Solana" },
"price": { "value": 142.5, "currency": "USD", "source": "coinbase", "at": "2026-10-12T14:02:59.412Z" },
"measured": {
"change_pct": -5.0,
"from": { "value": 150, "currency": "USD", "source": "coinbase", "at": "2026-10-12T13:03:00.000Z" },
"to": { "value": 142.5, "currency": "USD", "source": "coinbase", "at": "2026-10-12T14:02:59.412Z" }
},
"headline": "Solana (SOL) fell 5.0% in 1 hour.",
"context": {
"change_pct": { "15m": -1.2, "1h": -5.0, "4h": -6.1, "24h": -4.0 },
"volume_1h": { "ratio": 2.13, "window_volume": 210000, "window_minutes": 60, "baseline_per_minute": 1640, "baseline_days": 20 },
"market": {
"BTC": {
"price": { "value": 100000, "currency": "USD", "source": "coinbase", "at": "2026-10-12T14:02:58.100Z" },
"change_pct": { "15m": -0.3, "1h": -1.8, "4h": -2.0, "24h": -1.1 }
},
"ETH": null
}
},
"note": { "status": "pending", "text": null, "ai_written": false, "label": null, "reason": null },
"receipts": {
"1h": { "status": "pending", "due_at": "2026-10-12T15:03:00.000Z", "price": null, "change_pct": null, "recorded_at": null },
"4h": { "status": "pending", "due_at": "2026-10-12T18:03:00.000Z", "price": null, "change_pct": null, "recorded_at": null },
"24h": { "status": "pending", "due_at": "2026-10-13T14:03:00.000Z", "price": null, "change_pct": null, "recorded_at": null },
"7d": { "status": "pending", "due_at": "2026-10-19T14:03:00.000Z", "price": null, "change_pct": null, "recorded_at": null }
},
"links": {
"alert": "https://terminal.tokensmarketcap.com/app/alerts/9001?via=webhook",
"api": "https://terminal.tokensmarketcap.com/v1/alerts/9001",
"share": null,
"proof": null
},
"notice": "Terminal reports market events for conditions you set. It does not tell you to buy, sell, or hold, and it does not place trades.",
"terms": { "version": "2026-10-draft", "url": "https://terminal.tokensmarketcap.com/api-terms" }
}
Read one alert
A live read wraps the event in alert and adds note_facts. The note on an alert with no note request is none.
Example. These are not live prices.
GET /v1/alerts/$ALERT_ID HTTP/1.1
Authorization: Bearer $TERMINAL_API_KEY
HTTP/1.1 200 OK
{
"alert": {
"schema": "terminal.alert.v1",
"type": "alert.fired",
"sequence": null,
"fired_at": "2026-10-12T14:03:00.000Z",
"headline": "Solana (SOL) fell 5.0% in 1 hour.",
"service": null,
"asset": { "symbol": "SOL", "name": "Solana" },
"price": { "value": 142.5, "currency": "USD", "source": "coinbase", "at": "2026-10-12T14:02:59.412Z" },
"rule": {
"name": "SOL falls 5% in 1 hour",
"kind": "percent_change",
"scope": "symbol",
"cooldown_seconds": 3600,
"condition": { "threshold_pct": 5, "window": "1h", "direction": "down" }
},
"note": { "status": "none", "text": null, "ai_written": false }
},
"note_facts": null
}
Read the record
Example. These are not live prices.
GET /v1/rules/$RULE_ID/record HTTP/1.1
Authorization: Bearer $TERMINAL_API_KEY
HTTP/1.1 200 OK
{
"record": {
"summary": null,
"fired": 1,
"first_fired_at": "2026-10-12T14:03:00.000Z",
"last_fired_at": "2026-10-12T14:03:00.000Z",
"horizons": {
"1h": { "recorded": 0, "pending": 1, "missing": 0 },
"4h": { "recorded": 0, "pending": 1, "missing": 0 },
"24h": { "recorded": 0, "pending": 1, "missing": 0 },
"7d": { "recorded": 0, "pending": 1, "missing": 0 }
},
"alerts": [
{
"headline": "Solana (SOL) fell 5.0% in 1 hour.",
"asset": { "symbol": "SOL", "name": "Solana" },
"price": { "value": 142.5, "currency": "USD", "source": "coinbase" }
}
],
"next_before": null
}
}
All developer pages
Terminal reports market events for conditions you set. It does not tell you to buy, sell, or hold, and it does not place trades.