WebSocket
Public and private real-time streams — subscribe/unsubscribe, snapshot/delta, envelope, sequencing, heartbeats, resume, and schema evolution.
Draft v0.1 — design contract, not yet a live service
This documentation set defines a proposed Time Seventeen protocol for review and implementation planning. https://api.t17.capital is the approved and reserved REST origin, but neither that origin nor any documented endpoint is claimed to be live. The WebSocket origin remains unspecified. Credentials, chain IDs, contract addresses, rate limits, and SLAs remain unapproved; IDs, prices, and timestamps shown throughout are illustrative, not real production data.
Connection
wss://YOUR_APPROVED_STREAM_HOST/v1/wsPrivate topics require the same canonical request authentication used for private REST endpoints, applied to the connection/subscription handshake. Public topics require no identity.
Topics
| Scope | Topic | Payload |
|---|---|---|
| Public | index.price | New IndexPriceObservation |
| Public | index.status | Index/version status transition (active, suspended, degraded, archived) |
| Public | index.rebalance | New IndexVersion published |
| Public | market.ticker | Latest normalized market price view |
| Public | market.trade | Public trade tape entries |
| Public | market.orderbook | Order-book snapshot/delta |
| Public | market.rating | New/updated MarketRating |
| Public | event.severity | New/updated SeverityAssessment |
| Public | severity_index.value | New SeverityIndex value |
| Private | account.order | Order state transitions |
| Private | account.fill | New fills |
| Private | account.position | Position projection updates |
| Private | account.balance | Balance projection updates |
| Private | account.settlement | Settlement state transitions |
| Private | account.risk | Risk-limit changes |
market.rating and event.severity/severity_index.value remain independent topics: a market.rating message never carries severity fields, and a severity message never carries rating fields.
Envelope
Every stream message shares one envelope:
{
"type": "market.orderbook.delta",
"version": "1.0",
"event_id": "evtmsg_demo_001",
"subscription_id": "sub_demo_001",
"sequence": 42,
"resource_time": "2026-08-31T12:00:00.123Z",
"published_at": "2026-08-31T12:00:00.130Z",
"resume_cursor": "opaque",
"data": {}
}| Field | Meaning |
|---|---|
type | Event type/version qualifier, for example market.orderbook.snapshot or market.orderbook.delta |
version | Schema version of this event type, independent of the REST /v1 path version |
event_id | Unique per message; used to detect and ignore duplicates |
subscription_id | The client’s subscription this message satisfies |
sequence | Monotonic per subscription/resource partition, used for gap detection |
resource_time | When the underlying resource changed |
published_at | When Time Seventeen published this message |
resume_cursor | Opaque cursor a client can present to resume after a disconnect |
data | The topic-specific payload |
Subscribe / unsubscribe
{
"action": "subscribe",
"topic": "market.orderbook",
"params": { "market_id": "mkt_demo_001", "outcome_id": "out_demo_001" },
"subscription_id": "sub_demo_001"
}{
"action": "unsubscribe",
"subscription_id": "sub_demo_001"
}A new subscription receives an initial snapshot message before any delta messages for the same resource, unless the client explicitly opts into delta-only mode for a resource it has already snapshotted through REST.
Sequence gaps, resume, and recovery
- Clients track the monotonic
sequenceper subscription/resource partition and ignore any message whoseevent_idhas already been seen. - On a detected sequence gap, the client discards local state for that resource and either resumes with
resume_cursoror requests a fresh snapshot. - Resume is best-effort within a production-configured retention window. A resume request outside that window returns
STREAM_RESUME_UNAVAILABLE, and the client MUST fall back to a fresh REST/stream snapshot rather than assume continuity. - Heartbeat/ping cadence and subscription quotas are production configuration, not fixed by Draft v0.1.
Snapshot then delta example
{
"type": "market.orderbook.snapshot",
"version": "1.0",
"event_id": "evtmsg_demo_100",
"subscription_id": "sub_demo_001",
"sequence": 88213,
"resource_time": "2026-08-31T12:00:00.000Z",
"published_at": "2026-08-31T12:00:00.010Z",
"resume_cursor": "opaque_cursor_snap_1",
"data": {
"market_id": "mkt_demo_001",
"outcome_id": "out_demo_001",
"bids": [["0.6300", "500.00"]],
"asks": [["0.6400", "400.00"]]
}
}{
"type": "market.orderbook.delta",
"version": "1.0",
"event_id": "evtmsg_demo_101",
"subscription_id": "sub_demo_001",
"sequence": 88214,
"resource_time": "2026-08-31T12:00:00.120Z",
"published_at": "2026-08-31T12:00:00.130Z",
"resume_cursor": "opaque_cursor_delta_1",
"data": {
"market_id": "mkt_demo_001",
"outcome_id": "out_demo_001",
"side": "bid",
"price": "0.6300",
"quantity": "350.00"
}
}A client applies the delta to the snapshot’s book by price level; a zero quantity removes the level.
Private stream example
{
"type": "account.order.updated",
"version": "1.0",
"event_id": "evtmsg_demo_200",
"subscription_id": "sub_demo_002",
"sequence": 17,
"resource_time": "2026-08-31T12:01:12.041Z",
"published_at": "2026-08-31T12:01:12.055Z",
"resume_cursor": "opaque_cursor_ord_1",
"data": {
"order_id": "ord_demo_001",
"status": "partially_filled",
"filled_quantity": "60.00",
"remaining_quantity": "90.00"
}
}Schema evolution
Stream messages carry their own version field, independent of the REST /v1 path version, so a topic’s payload schema can evolve without forcing a REST major-version bump. Clients ignore unknown additive fields but MUST NOT ignore an unrecognized type or an unrecognized enum value inside data that changes economic or state meaning.