{"openapi":"3.1.0","info":{"title":"substreams-websocket","version":"0.4.2","description":"Substreams-to-WebSocket fan-out server. HTTP GET routes for discovery, health, metrics, and WebSocket upgrade. On-wire message contract: `/SKILL.md`."},"paths":{"/":{"get":{"summary":"Landing page","description":"Interactive browser client (Scalar-style API reference + try-it panel).","responses":{"200":{"description":"HTML page","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/streams":{"get":{"summary":"List configured streams","description":"JSON array of every configured Substreams source: `(network, package_name, package_version, module_hash, manifest, module, description, tables)`.","responses":{"200":{"description":"Stream list","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Stream"}}}}}}}},"/openapi":{"get":{"summary":"OpenAPI document","description":"This document. Also served at `/openapi.json`.","responses":{"200":{"description":"OpenAPI 3.1 JSON","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/SKILL.md":{"get":{"summary":"Agent-oriented reference","description":"Canonical client contract: on-wire JSON, command envelope, error shapes.","responses":{"200":{"description":"Markdown","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/llms.txt":{"get":{"summary":"Short llms.txt for AI crawlers","responses":{"200":{"description":"Plain text","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/favicon.png":{"get":{"summary":"Favicon (PNG). Also served at `/favicon.ico`.","responses":{"200":{"description":"PNG","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}}}}},"/healthz":{"get":{"summary":"Health check","description":"`200 ok` if live, `503 draining` during shutdown drain.","responses":{"200":{"description":"Live","content":{"text/plain":{"schema":{"type":"string","example":"ok"}}}},"503":{"description":"Draining","content":{"text/plain":{"schema":{"type":"string","example":"draining"}}}}}}},"/metrics":{"get":{"summary":"Prometheus metrics","description":"Text exposition format (`text/plain; version=0.0.4`).","responses":{"200":{"description":"Prometheus text","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/ws":{"get":{"summary":"WebSocket upgrade (no streams — error)","description":"Bare `/ws` returns HTTP 400. Use `/ws/<network>@<table>` or `/stream?streams=...`.","responses":{"400":{"description":"Missing stream selector"},"101":{"description":"Switching Protocols (never reached on this exact path)"}}}},"/ws/{streams}":{"get":{"summary":"WebSocket upgrade (path mode)","description":"Single (`/ws/<a>`) or combined (`/ws/<a>/<b>/...`) channel subscription. Multi-channel wraps payloads in `{\"stream\":\"...\",\"data\":...}`. Wire contract: `/SKILL.md`.","parameters":[{"name":"streams","in":"path","required":true,"description":"One or more `<network>@<table>` selectors joined by `/`. `*` is a wildcard on either side.","schema":{"type":"string"},"example":"solana-mainnet@swaps/ethereum-mainnet@transfers"},{"name":"from_timestamp","in":"query","required":false,"description":"Resume from this Unix epoch seconds value or `YYYY-MM-DD HH:MM:SS` UTC. Replays buffered blocks for explicit selectors.","schema":{"type":"string"}},{"name":"filter","in":"query","required":false,"description":"URL-encoded JSON `{field: value|[values]}`. Server-side row filter, fields AND, values OR.","schema":{"type":"string"}}],"responses":{"101":{"description":"Switching Protocols — WebSocket open"},"400":{"description":"Invalid selector / filter / from_timestamp"},"503":{"description":"max_clients reached"}}}},"/stream":{"get":{"summary":"WebSocket upgrade (query mode)","description":"Combined-streams form. Payloads always wrapped in `{\"stream\":\"...\",\"data\":...}`.","parameters":[{"name":"streams","in":"query","required":true,"description":"One or more `<network>@<table>` selectors joined by `/`.","schema":{"type":"string"},"example":"solana-mainnet@swaps/ethereum-mainnet@transfers"},{"name":"from_timestamp","in":"query","required":false,"schema":{"type":"string"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"101":{"description":"Switching Protocols — WebSocket open"},"400":{"description":"Invalid `streams` / filter / from_timestamp"},"503":{"description":"max_clients reached"}}}}},"components":{"schemas":{"Stream":{"type":"object","required":["network","module","manifest","module_hash","package_name","package_version"],"properties":{"network":{"type":"string"},"module":{"type":"string"},"manifest":{"type":"string"},"module_hash":{"type":"string"},"package_name":{"type":"string"},"package_version":{"type":"string"},"description":{"type":"string"},"tables":{"type":"array","items":{"type":"string"}}}}}}}