CantonCap WebSocket API
Connect to wss://api.cantoncap.cc/v1/stream in production or ws://localhost:3002/v1/stream locally. Server-side clients authenticate with the X-API-Key header. One connection supports multiple subscriptions; each has its own ID, cancellation and recovery cursor.
Subscribe
{
"type": "subscribe",
"request_id": "req_prices",
"channel": "asset_quote:ast_09fdff10fa834da7831fc92d1ac47f75",
"resume_from_event_id": null
}
Use asset IDs from the asset map and market IDs from market browsing. A duplicate channel on the same connection returns invalid_request without consuming another subscription slot.
Acknowledgement
{
"type": "subscribed",
"request_id": "req_prices",
"subscription_id": "sub_example",
"channel": "asset_quote:ast_09fdff10fa834da7831fc92d1ac47f75",
"schema_version": "1.0",
"delivery": "sampled_state",
"replay": {
"mode": "best_effort",
"max_age_ms": 900000
},
"heartbeat_interval_ms": 15000,
"poll_interval_ms": 1000
}
These values describe the default configuration. Use the settings returned by your subscription. Replay can end earlier through capacity eviction or server restart.
Data
{
"type": "event",
"subscription_id": "sub_example",
"channel": "asset_quote:ast_09fdff10fa834da7831fc92d1ac47f75",
"event_id": "evt_example",
"data": {
"asset_id": "ast_09fdff10fa834da7831fc92d1ac47f75",
"quotes": {
"USD": {
"price": "0.15",
"market_cap": null,
"fdv": null,
"volume_24h": null,
"volume": null,
"price_changes_pct": {
"1h": null,
"24h": null,
"7d": null,
"30d": null
},
"last_updated_at": "2026-09-07T20:00:00.000Z"
}
}
}
}
Prices and quantities are exact decimal strings. Null means unavailable. For aggregate asset quotes, last_updated_at is when the returned price was calculated. Venue observations use their source update time. Quote streams currently use USD. The data types match their REST counterparts.
Channels and schemas
| Channel | Purpose |
|---|---|
| control | Connection-local subscription commands, acknowledgements, heartbeats, and typed terminal errors. These frames use the same WebSocket session as the data channels and are not broker topics. |
| ticker:{market_id} | Latest normalized ticker observations for one canonical market. |
| asset_quote:{asset_id} | Aggregate quotes and calculated fields for one stable asset ID. |
| trades:{market_id} | Approved public canonical trades for one market. |
| orderbook:{market_id} | Full snapshots and resynchronization notices for one market. The data model also supports absolute updates; current sources deliver full resnapshots. A market with no book snapshot observed in the last 29 days has no current book and the subscription is refused with not_found. |
| candles:{market_id}:{interval} | Full candle replacements keyed by market, interval and open_time. Polls reconcile the current UTC period and the previous two periods; closing updates and recent corrections can follow newer periods. Intermediate revisions can coalesce and older corrections require REST. Empty periods are omitted. Boundaries are start-inclusive and end-exclusive. complete means the period has ended, not that corrections are impossible. |
| source_status:{venue_id} | Operational feed availability, independent of age-only classifications. last_updated_at is the last market-data measurement time. |
control
Connection-local subscription commands, acknowledgements, heartbeats, and typed terminal errors. These frames use the same WebSocket session as the data channels and are not broker topics.
Versioned market-data subscribe request
{
"type": "object",
"additionalProperties": false,
"required": [
"type",
"request_id",
"channel"
],
"properties": {
"type": {
"type": "string",
"const": "subscribe"
},
"request_id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,128}$"
},
"channel": {
"type": "string",
"pattern": "^(?:ticker:mkt_[A-Za-z0-9_-]+|asset_quote:ast_[A-Za-z0-9_-]+|trades:mkt_[A-Za-z0-9_-]+|orderbook:mkt_[A-Za-z0-9_-]+|candles:mkt_[A-Za-z0-9_-]+:(?:1m|5m|10m|15m|30m|1h|4h|1d|7d|1w)|source_status:[A-Za-z0-9_-]{1,128})$"
},
"resume_from_event_id": {
"type": [
"string",
"null"
],
"pattern": "^evt_[A-Za-z0-9_-]{1,128}$",
"description": "Last received event ID for this channel. Replay is best effort, bounded by age/capacity and lost on restart. An unavailable token returns resume_unavailable. Order books and source status reject non-null tokens.",
"default": null
}
}
}Unsubscribe request
{
"type": "object",
"additionalProperties": false,
"required": [
"type",
"request_id",
"subscription_id"
],
"properties": {
"type": {
"type": "string",
"const": "unsubscribe"
},
"request_id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,128}$"
},
"subscription_id": {
"type": "string",
"pattern": "^sub_[A-Za-z0-9_-]{1,128}$"
}
}
}Subscription acknowledgement
{
"type": "object",
"additionalProperties": false,
"required": [
"type",
"request_id",
"subscription_id",
"channel",
"schema_version",
"delivery",
"replay",
"heartbeat_interval_ms",
"poll_interval_ms"
],
"properties": {
"type": {
"type": "string",
"const": "subscribed"
},
"request_id": {
"type": "string"
},
"subscription_id": {
"type": "string",
"pattern": "^sub_[A-Za-z0-9_-]{1,128}$"
},
"channel": {
"type": "string"
},
"schema_version": {
"type": "string",
"const": "1.0"
},
"delivery": {
"type": "string",
"enum": [
"sampled_state",
"trade_journal",
"candle_updates",
"snapshots",
"latest_state"
]
},
"replay": {
"type": "object",
"additionalProperties": false,
"required": [
"mode",
"max_age_ms"
],
"properties": {
"mode": {
"type": "string",
"enum": [
"best_effort",
"none"
]
},
"max_age_ms": {
"type": [
"integer",
"null"
],
"minimum": 0,
"description": "Maximum replay age, not guaranteed retention; capacity eviction or restart can invalidate a token sooner."
}
}
},
"heartbeat_interval_ms": {
"type": "integer",
"minimum": 1,
"maximum": 60000
},
"poll_interval_ms": {
"type": "integer",
"minimum": 1
}
}
}Cancellation acknowledgement
{
"type": "object",
"additionalProperties": false,
"required": [
"type",
"request_id",
"subscription_id"
],
"properties": {
"type": {
"type": "string",
"const": "unsubscribed"
},
"request_id": {
"type": "string"
},
"subscription_id": {
"type": "string",
"pattern": "^sub_[A-Za-z0-9_-]{1,128}$"
}
}
}Application heartbeat
{
"type": "object",
"additionalProperties": false,
"required": [
"type",
"observed_at"
],
"properties": {
"type": {
"type": "string",
"const": "heartbeat"
},
"observed_at": {
"type": "string",
"format": "date-time"
}
}
}Typed stream error
{
"type": "object",
"additionalProperties": false,
"required": [
"type",
"request_id",
"subscription_id",
"code",
"message",
"retryable"
],
"properties": {
"type": {
"type": "string",
"const": "error"
},
"request_id": {
"type": [
"string",
"null"
]
},
"subscription_id": {
"type": [
"string",
"null"
]
},
"code": {
"type": "string",
"enum": [
"unauthenticated",
"forbidden",
"invalid_request",
"protocol_error",
"not_found",
"source_unavailable",
"rate_limited",
"quota_exceeded",
"resume_unavailable",
"connection_limit",
"subscription_limit",
"payload_too_large",
"slow_consumer",
"shutdown"
]
},
"message": {
"type": "string"
},
"retryable": {
"type": "boolean"
},
"retry_after_ms": {
"type": "integer",
"minimum": 0,
"maximum": 86400000,
"description": "Exact retry delay for rate and concurrent-stream quota failures."
}
}
}ticker:{market_id}
Latest normalized ticker observations for one canonical market.
Encoded ticker subscription frame
{
"allOf": [
{
"type": "object",
"allOf": [
{
"type": "object",
"required": [
"event_id"
],
"properties": {
"event_id": {
"type": "string",
"pattern": "^evt_[A-Za-z0-9_-]{1,128}$"
}
}
},
{
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "object",
"properties": {
"market_category": {
"anyOf": [
{
"type": "string",
"enum": [
"amm",
"clmm",
"orderbook",
"hybrid"
]
},
{
"type": "null"
}
]
},
"liquidity_score": {
"anyOf": [
{
"description": "Displayed liquidity score, 0–100. Simulated buys and sells at $100, $500, $1,000, $5,000 and $10,000; fees excluded. Null means insufficient inputs, never a hidden market.",
"type": "number",
"minimum": 0,
"maximum": 100
},
{
"type": "null"
}
]
},
"liquidity_score_methodology": {
"type": "string",
"enum": [
"execution-impact-v1"
]
},
"liquidity_score_updated_at": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"last_updated_at": {
"type": "string",
"format": "date-time"
},
"venue_id": {
"type": "string",
"minLength": 1
},
"market_id": {
"type": "string",
"pattern": "^mkt_[A-Za-z0-9_-]+$"
},
"price_origin": {
"type": "string",
"enum": [
"venue_pool",
"venue_book",
"venue_trade",
"external_reference",
"derived"
]
},
"last_price": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"best_bid": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"best_ask": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"mid_price": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"volume_base_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"volume_quote_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"trade_count_24h": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"open_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"high_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"low_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"close_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"vwap_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"price_change_abs_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"reference_price_usd": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"price_change_24h_pct": {
"anyOf": [
{
"type": "string",
"pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"volume_usd_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
}
},
"required": [
"last_updated_at",
"venue_id",
"market_id",
"price_origin",
"last_price",
"best_bid",
"best_ask",
"mid_price",
"volume_base_24h",
"volume_quote_24h",
"trade_count_24h",
"open_24h",
"high_24h",
"low_24h",
"close_24h",
"vwap_24h",
"price_change_abs_24h",
"reference_price_usd",
"price_change_24h_pct",
"volume_usd_24h"
],
"additionalProperties": false
}
}
}
]
},
{
"type": "object",
"required": [
"type",
"subscription_id",
"channel"
],
"properties": {
"type": {
"type": "string",
"const": "event"
},
"subscription_id": {
"type": "string",
"pattern": "^sub_[A-Za-z0-9_-]{1,128}$"
},
"channel": {
"type": "string",
"pattern": "^ticker:mkt_[A-Za-z0-9_-]+$"
}
}
}
]
}asset_quote:{asset_id}
Aggregate quotes and calculated fields for one stable asset ID.
Exact v1 asset-quote subscription frame
{
"allOf": [
{
"type": "object",
"allOf": [
{
"type": "object",
"required": [
"event_id"
],
"properties": {
"event_id": {
"type": "string",
"pattern": "^evt_[A-Za-z0-9_-]{1,128}$"
}
}
},
{
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "object",
"properties": {
"asset_id": {
"type": "string",
"pattern": "^ast_[A-Za-z0-9_-]+$"
},
"quotes": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"price": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
"market_cap": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"fdv": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"volume_24h": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"volume": {
"anyOf": [
{
"type": "object",
"properties": {
"selection_method": {
"description": "Actual selected method. The legacy method field keeps its reported/trades enum.",
"anyOf": [
{
"type": "string",
"enum": [
"venue_reported_aggregate",
"canonical_trades",
"activity"
]
},
{
"type": "null"
}
]
},
"methodology_version": {
"type": "string"
},
"interpretation": {
"description": "Completeness applies to the measurement's own window, not the current wall clock. A zero is a value, not unavailable activity.",
"type": "string",
"enum": [
"complete_total",
"partial_subtotal",
"unavailable",
"coverage_unknown"
]
},
"coverage_detail": {
"description": "Counts come from the selected evidence, never ticker nulls. Null means the detail was not recorded. Missing activity has no native or USD volume; unvalued activity has native volume but no selected USD. Partial and incomplete-time counts concern included markets and may overlap. Retained is null when retention status was not established. No restricted market identities are exposed.",
"type": "object",
"properties": {
"unit": {
"type": "string",
"enum": [
"USD",
"display_currency"
]
},
"window": {
"type": "string",
"enum": [
"24h"
]
},
"starts_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
{
"type": "null"
}
]
},
"ends_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
{
"type": "null"
}
]
},
"covered_seconds": {
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 86400
},
{
"type": "null"
}
]
},
"retained": {
"type": [
"boolean",
"null"
]
},
"eligible_market_count": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"included_market_count": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"missing_activity_market_count": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"unvalued_market_count": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"partial_market_count": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"incomplete_time_market_count": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
}
},
"required": [
"unit",
"window",
"starts_at",
"ends_at",
"covered_seconds",
"retained",
"eligible_market_count",
"included_market_count",
"missing_activity_market_count",
"unvalued_market_count",
"partial_market_count",
"incomplete_time_market_count"
],
"additionalProperties": false
},
"method": {
"anyOf": [
{
"type": "string",
"enum": [
"reported",
"trades"
]
},
{
"type": "null"
}
]
},
"coverage": {
"type": "string",
"enum": [
"complete",
"partial",
"unknown"
]
},
"as_of": {
"type": "string",
"format": "date-time"
},
"change_24h_pct": {
"anyOf": [
{
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$"
},
{
"type": "null"
}
]
}
},
"required": [
"method",
"coverage",
"change_24h_pct"
],
"additionalProperties": false
},
{
"type": "null"
}
]
},
"price_changes_pct": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string",
"pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
}
},
"last_updated_at": {
"type": "string",
"format": "date-time"
}
},
"required": [
"price",
"market_cap",
"fdv",
"volume_24h",
"volume",
"price_changes_pct",
"last_updated_at"
],
"additionalProperties": false,
"examples": [
{
"price": "1.025",
"market_cap": null,
"fdv": "1025000",
"volume_24h": "12500.50",
"volume": {
"method": "reported",
"coverage": "complete",
"change_24h_pct": "3.2"
},
"price_changes_pct": {
"1h": "-0.5",
"24h": "1.25",
"7d": null,
"30d": null
},
"last_updated_at": "2026-09-07T20:00:00.000Z"
}
]
}
}
},
"required": [
"asset_id",
"quotes"
],
"additionalProperties": false
}
}
}
]
},
{
"type": "object",
"required": [
"type",
"subscription_id",
"channel"
],
"properties": {
"type": {
"type": "string",
"const": "event"
},
"subscription_id": {
"type": "string",
"pattern": "^sub_[A-Za-z0-9_-]{1,128}$"
},
"channel": {
"type": "string",
"pattern": "^asset_quote:ast_[A-Za-z0-9_-]+$"
}
}
}
]
}trades:{market_id}
Approved public canonical trades for one market.
Encoded trade subscription frame
{
"allOf": [
{
"type": "object",
"allOf": [
{
"type": "object",
"required": [
"event_id"
],
"properties": {
"event_id": {
"type": "string",
"pattern": "^evt_[A-Za-z0-9_-]{1,128}$"
}
}
},
{
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "object",
"properties": {
"last_updated_at": {
"type": "string",
"format": "date-time"
},
"trade_id": {
"type": "string",
"pattern": "^trd_[A-Za-z0-9_-]+$"
},
"venue_id": {
"type": "string",
"minLength": 1
},
"market_id": {
"type": "string",
"pattern": "^mkt_[A-Za-z0-9_-]+$"
},
"trade_timestamp": {
"type": "string",
"format": "date-time"
},
"side": {
"type": "string",
"enum": [
"buy",
"sell",
"unknown"
]
},
"price": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
"base_amount": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
"quote_amount": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
"fee_amounts": {
"type": "array",
"items": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
}
}
},
"required": [
"last_updated_at",
"trade_id",
"venue_id",
"market_id",
"trade_timestamp",
"side",
"price",
"base_amount",
"quote_amount",
"fee_amounts"
],
"additionalProperties": false
}
}
}
]
},
{
"type": "object",
"required": [
"type",
"subscription_id",
"channel"
],
"properties": {
"type": {
"type": "string",
"const": "event"
},
"subscription_id": {
"type": "string",
"pattern": "^sub_[A-Za-z0-9_-]{1,128}$"
},
"channel": {
"type": "string",
"pattern": "^trades:mkt_[A-Za-z0-9_-]+$"
}
}
}
]
}orderbook:{market_id}
Full snapshots and resynchronization notices for one market. The data model also supports absolute updates; current sources deliver full resnapshots. A market with no book snapshot observed in the last 29 days has no current book and the subscription is refused with not_found.
Encoded order-book subscription frame
{
"allOf": [
{
"type": "object",
"allOf": [
{
"type": "object",
"required": [
"event_id"
],
"properties": {
"event_id": {
"type": "string",
"pattern": "^evt_[A-Za-z0-9_-]{1,128}$"
}
}
},
{
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"oneOf": [
{
"type": "object",
"allOf": [
{
"type": "object",
"required": [
"last_updated_at"
],
"properties": {
"last_updated_at": {
"type": "string",
"format": "date-time"
}
}
},
{
"type": "object",
"required": [
"kind",
"venue_id",
"network",
"market_id",
"sequence",
"bids",
"asks",
"best_bid",
"best_ask",
"spread",
"available_quantity_excludes_own_orders"
],
"properties": {
"kind": {
"type": "string",
"const": "snapshot"
},
"venue_id": {
"type": "string"
},
"network": {
"type": "string",
"enum": [
"mainnet",
"testnet",
"devnet"
]
},
"market_id": {
"type": "string"
},
"sequence": {
"type": "string"
},
"bids": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"price",
"amount",
"total_amount",
"available_amount",
"cumulative_amount",
"order_count"
],
"properties": {
"price": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"amount": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"total_amount": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"available_amount": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"cumulative_amount": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"order_count": {
"type": [
"integer",
"null"
],
"minimum": 0
}
}
}
},
"asks": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"price",
"amount",
"total_amount",
"available_amount",
"cumulative_amount",
"order_count"
],
"properties": {
"price": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"amount": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"total_amount": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"available_amount": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"cumulative_amount": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"order_count": {
"type": [
"integer",
"null"
],
"minimum": 0
}
}
}
},
"best_bid": {
"anyOf": [
{
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
{
"type": "null"
}
]
},
"best_ask": {
"anyOf": [
{
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
{
"type": "null"
}
]
},
"spread": {
"anyOf": [
{
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
{
"type": "null"
}
]
},
"available_quantity_excludes_own_orders": {
"type": "boolean"
}
}
}
]
},
{
"type": "object",
"allOf": [
{
"type": "object",
"required": [
"last_updated_at"
],
"properties": {
"last_updated_at": {
"type": "string",
"format": "date-time"
}
}
},
{
"type": "object",
"required": [
"kind",
"venue_id",
"market_id",
"sequence",
"previous_sequence",
"changes",
"available_quantity_excludes_own_orders"
],
"properties": {
"kind": {
"type": "string",
"const": "update"
},
"venue_id": {
"type": "string"
},
"market_id": {
"type": "string"
},
"sequence": {
"type": "string"
},
"previous_sequence": {
"type": "string"
},
"changes": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"required": [
"action",
"side",
"price",
"amount"
],
"properties": {
"action": {
"type": "string",
"const": "upsert"
},
"side": {
"type": "string",
"enum": [
"bid",
"ask"
]
},
"price": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
},
"amount": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
}
}
},
{
"type": "object",
"additionalProperties": false,
"required": [
"action",
"side",
"price"
],
"properties": {
"action": {
"type": "string",
"const": "delete"
},
"side": {
"type": "string",
"enum": [
"bid",
"ask"
]
},
"price": {
"type": "string",
"pattern": "^-?[0-9]+(?:\\.[0-9]+)?$",
"examples": [
"123.456"
]
}
}
}
]
}
},
"available_quantity_excludes_own_orders": {
"type": "boolean"
}
}
}
]
},
{
"type": "object",
"oneOf": [
{
"type": "object",
"required": [
"kind",
"venue_id",
"market_id",
"last_applied_sequence",
"observed_at",
"reason",
"received_sequence",
"received_previous_sequence"
],
"properties": {
"kind": {
"type": "string",
"const": "resync_required"
},
"venue_id": {
"type": "string"
},
"market_id": {
"type": "string"
},
"last_applied_sequence": {
"type": [
"string",
"null"
]
},
"observed_at": {
"type": "string",
"format": "date-time"
},
"reason": {
"type": "string",
"enum": [
"sequence_gap",
"out_of_order"
]
},
"received_sequence": {
"type": "string"
},
"received_previous_sequence": {
"type": "string"
}
}
},
{
"type": "object",
"required": [
"kind",
"venue_id",
"market_id",
"last_applied_sequence",
"observed_at",
"reason"
],
"properties": {
"kind": {
"type": "string",
"const": "resync_required"
},
"venue_id": {
"type": "string"
},
"market_id": {
"type": "string"
},
"last_applied_sequence": {
"type": [
"string",
"null"
]
},
"observed_at": {
"type": "string",
"format": "date-time"
},
"reason": {
"type": "string",
"const": "source_reset"
}
},
"not": {
"anyOf": [
{
"required": [
"received_sequence"
],
"properties": {
"received_sequence": {}
}
},
{
"required": [
"received_previous_sequence"
],
"properties": {
"received_previous_sequence": {}
}
}
]
}
},
{
"type": "object",
"required": [
"kind",
"venue_id",
"market_id",
"last_applied_sequence",
"observed_at",
"reason",
"received_sequence",
"received_previous_sequence"
],
"properties": {
"kind": {
"type": "string",
"const": "resync_required"
},
"venue_id": {
"type": "string"
},
"market_id": {
"type": "string"
},
"last_applied_sequence": {
"type": [
"string",
"null"
]
},
"observed_at": {
"type": "string",
"format": "date-time"
},
"reason": {
"type": "string",
"const": "buffer_overflow"
},
"received_sequence": {
"type": "string"
},
"received_previous_sequence": {
"type": "string"
}
}
}
]
}
]
}
}
}
]
},
{
"type": "object",
"required": [
"type",
"subscription_id",
"channel"
],
"properties": {
"type": {
"type": "string",
"const": "event"
},
"subscription_id": {
"type": "string",
"pattern": "^sub_[A-Za-z0-9_-]{1,128}$"
},
"channel": {
"type": "string",
"pattern": "^orderbook:mkt_[A-Za-z0-9_-]+$"
}
}
}
]
}candles:{market_id}:{interval}
Full candle replacements keyed by market, interval and open_time. Polls reconcile the current UTC period and the previous two periods; closing updates and recent corrections can follow newer periods. Intermediate revisions can coalesce and older corrections require REST. Empty periods are omitted. Boundaries are start-inclusive and end-exclusive. complete means the period has ended, not that corrections are impossible.
Exact v1 candle subscription frame
{
"allOf": [
{
"type": "object",
"allOf": [
{
"type": "object",
"required": [
"event_id"
],
"properties": {
"event_id": {
"type": "string",
"pattern": "^evt_[A-Za-z0-9_-]{1,128}$"
}
}
},
{
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "object",
"properties": {
"last_updated_at": {
"type": "string",
"format": "date-time"
},
"market_id": {
"type": "string",
"pattern": "^mkt_[A-Za-z0-9_-]+$"
},
"interval": {
"type": "string",
"enum": [
"1m",
"5m",
"10m",
"15m",
"30m",
"1h",
"4h",
"1d",
"7d",
"1w"
]
},
"open_time": {
"type": "string",
"format": "date-time"
},
"close_time": {
"type": "string",
"format": "date-time"
},
"open": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
"high": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
"low": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
"close": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
"volume_base": {
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
"volume_quote": {
"anyOf": [
{
"type": "string",
"pattern": "^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"
},
{
"type": "null"
}
]
},
"trade_count": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"volume_method": {
"type": "string",
"enum": [
"venue_reported",
"observed_trades",
"none"
]
},
"complete": {
"type": "boolean"
}
},
"required": [
"last_updated_at",
"market_id",
"interval",
"open_time",
"close_time",
"open",
"high",
"low",
"close",
"volume_base",
"volume_quote",
"trade_count",
"volume_method",
"complete"
],
"additionalProperties": false
}
}
}
]
},
{
"type": "object",
"required": [
"type",
"subscription_id",
"channel"
],
"properties": {
"type": {
"type": "string",
"const": "event"
},
"subscription_id": {
"type": "string",
"pattern": "^sub_[A-Za-z0-9_-]{1,128}$"
},
"channel": {
"type": "string",
"pattern": "^candles:mkt_[A-Za-z0-9_-]+:(?:1m|5m|10m|15m|30m|1h|4h|1d|7d|1w)$"
}
}
}
]
}source_status:{venue_id}
Operational feed availability, independent of age-only classifications. last_updated_at is the last market-data measurement time.
Encoded source-status subscription frame
{
"allOf": [
{
"type": "object",
"allOf": [
{
"type": "object",
"required": [
"event_id"
],
"properties": {
"event_id": {
"type": "string",
"pattern": "^evt_[A-Za-z0-9_-]{1,128}$"
}
}
},
{
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "object",
"properties": {
"venue_id": {
"type": "string",
"minLength": 1
},
"available": {
"type": "boolean"
},
"last_updated_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"venue_id",
"available",
"last_updated_at"
],
"additionalProperties": false
}
}
}
]
},
{
"type": "object",
"required": [
"type",
"subscription_id",
"channel"
],
"properties": {
"type": {
"type": "string",
"const": "event"
},
"subscription_id": {
"type": "string",
"pattern": "^sub_[A-Za-z0-9_-]{1,128}$"
},
"channel": {
"type": "string",
"pattern": "^source_status:[A-Za-z0-9_-]{1,128}$"
}
}
}
]
}Delivery and candle updates
Ticker and aggregate quotes are sampled latest state, so intermediate source changes may be coalesced. Trade streams tail admitted executions. Current order-book sources send full snapshots and resynchronization notices; invalidate your local book on resync_required.
Candles replace the entire record identified by market, interval and opening time. Polls reconcile the current and previous two periods; older corrections require REST history. Intermediate revisions can be coalesced. complete means the period ended, and does not rate observation coverage. Periods use UTC, inclusive start and exclusive end; empty buckets are omitted.
Recovery
Save each channel's last processed event ID. Reconnect with it in resume_from_event_id. resume_unavailable requires an explicit resynchronization: start a fresh subscription and buffer incoming events, fetch overlapping REST history, merge by trade ID or candle identity, then apply buffered updates. REST state snapshots cannot reconstruct every intermediate quote. Order books require a fresh snapshot instead of an event cursor.
{
"type": "error",
"request_id": "req_prices",
"subscription_id": null,
"code": "resume_unavailable",
"message": "The requested event is not retained",
"retryable": false
}
SDKs and limits
TypeScript: client.stream.subscribeAssetQuotes(ids) returns individual asset events. Use resumeFromEventId on a single subscription, cancel() to unsubscribe and client.stream.close() to close streams. Python: client.stream.subscribe_asset_quotes(ids), StreamSubscriptionOptions(resume_from_event_id=...), and aclose(). Both clients share their socket and maintain bounded queues.
The defaults allow 100 subscriptions per connection. Account plans also limit concurrent connections. The gateway emits heartbeats every 15 seconds by default, capped at 60 seconds; SDKs default to a 90-second deadline. Slow consumers receive a typed failure. Respect retry_after_ms on quota errors and use bounded backoff. Candle reconciliation has a separate global admission limit. Feed availability is independent of age-only health thresholds.