Opens one authenticated WebSocket that receives normalized Chainlink
Data Streams prices.
symbols and variants select the initial feeds. Omit both for all
18 feeds, or use symbols=none to start empty. Subscriptions can then
be changed atomically with text JSON frames:
The server sends welcome, an initial snapshot, live price
updates, and idle heartbeat frames. A successful subscribe is
acknowledged before its snapshot and before any live update for the
newly added feed. No update for a removed feed is queued after the
unsubscribed acknowledgement. Prices are exact decimal strings.
Chainlink’s live stream can occasionally omit an event. This endpoint
performs no REST reconciliation or backfill, so events missing from the
upstream stream or dropped from Edge’s bounded source queue are not
replayed or forwarded later.
The number of concurrent connections is assigned per API key; the service
default is one. Browser clients may authenticate
with api_key; other clients should use the Authorization header.
New handshakes receive 503 while the upstream feed is stale.
GET
/
api
/
v1
/
streams
/
crypto-prices
WebSocket stream of Chainlink crypto prices
curl --request GET \ --url https://data.gravia.trade/api/v1/streams/crypto-prices \ --header 'Authorization: <api-key>'
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Gravia Data API","colors":{"primary":"#9FFBFE","light":"#B8F7F8","dark":"#52CCD0"},"logo":{"light":"https://mintcdn.com/gravia-trade/q65mj9SyvyR5CJGQ/images/Gravia-black-logo.svg?fit=max\u0026auto=format\u0026n=q65mj9SyvyR5CJGQ\u0026q=85\u0026s=d20027ef4daf7f22158c1c43c271a664","dark":"https://mintcdn.com/gravia-trade/q65mj9SyvyR5CJGQ/images/Gravia-White-logo.svg?fit=max\u0026auto=format\u0026n=q65mj9SyvyR5CJGQ\u0026q=85\u0026s=ea11483c2fba835a236dce5eaafc0971"},"favicon":{"light":"https://mintcdn.com/gravia-trade/q65mj9SyvyR5CJGQ/images/Favicon-black.svg?fit=max\u0026auto=format\u0026n=q65mj9SyvyR5CJGQ\u0026q=85\u0026s=7592a349f8a038bd79006469a83390b7","dark":"https://mintcdn.com/gravia-trade/q65mj9SyvyR5CJGQ/images/Favicon-black.svg?fit=max\u0026auto=format\u0026n=q65mj9SyvyR5CJGQ\u0026q=85\u0026s=7592a349f8a038bd79006469a83390b7"},"background":{"color":{"light":"#ffffff","dark":"#09090B"}},"navbar":{"links":[{"href":"mailto:[email protected]","label":"Support"},{"href":"https://discord.gg/REeFwe5HyN","label":"Discord"}]},"footer":{"socials":{"x":"https://x.com/graviahq","discord":"https://discord.gg/REeFwe5HyN"}},"fonts":{"family":"DM Sans"},"styling":{"codeblocks":"system","latex":false},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"markdown":{"schema":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"gravia-trade","hasAudioNarration":false,"actualSubdomain":"gravia-trade","customDomains":["docs.gravia.trade"],"gitSource":{"type":"github","owner":"mintlify-community","repo":"docs-gravia-trade-52698928","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"collectionId":"5160409f-d378-44bb-8ff7-93078be2816f","liveDeploymentHistoryId":"6abcdb7489c801142748f92e","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6abcdb7489c801142748f92e"},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6abcdb7489c801142748f92e","clientVersion":"0.0.4043","searchFilterCounts":[{"language":"default","tag":"API Reference","count":22},{"language":"default","tag":"Webhooks","count":9},{"language":"default","tag":"Users","count":7},{"language":"default","tag":"Documentation","count":5},{"language":"default","tag":"Getting Started","count":5},{"language":"default","tag":"Markets","count":3},{"language":"default","tag":"Streams","count":2},{"language":"default","tag":"Operational","count":1}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":true},"customCss":[],"page":{"pagePath":"api-reference/streams/websocket-stream-of-chainlink-crypto-prices","slug":"/api-reference/streams/websocket-stream-of-chainlink-crypto-prices","pageMetadata":{"title":"WebSocket stream of Chainlink crypto prices","description":"Opens one authenticated WebSocket that receives normalized Chainlink\nData Streams prices.\n\n`symbols` and `variants` select the initial feeds. Omit both for all\n18 feeds, or use `symbols=none` to start empty. Subscriptions can then\nbe changed atomically with text JSON frames:\n\n```json\n{\"action\":\"subscribe\",\"subscriptions\":[{\"symbol\":\"btc\",\"variant\":\"spot\"}]}\n{\"action\":\"unsubscribe\",\"subscriptions\":[{\"symbol\":\"btc\",\"variant\":\"spot\"}]}\n{\"action\":\"subscription.list\"}\n{\"action\":\"ping\"}\n```\n\nThe server sends `welcome`, an initial `snapshot`, live `price`\nupdates, and idle `heartbeat` frames. A successful subscribe is\nacknowledged before its snapshot and before any live update for the\nnewly added feed. No update for a removed feed is queued after the\n`unsubscribed` acknowledgement. Prices are exact decimal strings.\n\nChainlink's live stream can occasionally omit an event. This endpoint\nperforms no REST reconciliation or backfill, so events missing from the\nupstream stream or dropped from Edge's bounded source queue are not\nreplayed or forwarded later.\n\nThe number of concurrent connections is assigned per API key; the service\ndefault is one. Browser clients may authenticate\nwith `api_key`; other clients should use the `Authorization` header.\nNew handshakes receive `503` while the upstream feed is stale.\n","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/streams/crypto-prices","href":"/api-reference/streams/websocket-stream-of-chainlink-crypto-prices","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n p: \"p\",\n pre: \"pre\",\n span: \"span\",\n ..._provideComponents(),\n ...props.components\n }, {CodeBlock} = _components;\n if (!CodeBlock) _missingMdxReference(\"CodeBlock\", true);\n return _jsxs(_Fragment, {\n children: [_jsx(_components.p, {\n children: \"Opens one authenticated WebSocket that receives normalized Chainlink\\nData Streams prices.\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.code, {\n children: \"symbols\"\n }), \" and \", _jsx(_components.code, {\n children: \"variants\"\n }), \" select the initial feeds. Omit both for all\\n18 feeds, or use \", _jsx(_components.code, {\n children: \"symbols=none\"\n }), \" to start empty. Subscriptions can then\\nbe changed atomically with text JSON frames:\"]\n }), \"\\n\", _jsx(CodeBlock, {\n numberOfLines: \"4\",\n language: \"json\",\n children: _jsx(_components.pre, {\n className: \"shiki shiki-themes github-light-default dark-plus\",\n style: {\n backgroundColor: \"#ffffff\",\n \"--shiki-dark-bg\": \"#0B0C0E\",\n color: \"#1f2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n language: \"json\",\n children: _jsxs(_components.code, {\n language: \"json\",\n numberOfLines: \"4\",\n children: [_jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"{\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"action\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":\"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"subscribe\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \",\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"subscriptions\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":[{\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"symbol\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":\"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"btc\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \",\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"variant\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":\"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"spot\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"}]}\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"{\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"action\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":\"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"unsubscribe\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \",\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"subscriptions\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":[{\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"symbol\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":\"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"btc\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \",\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"variant\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":\"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"spot\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"}]}\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"{\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"action\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":\"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"subscription.list\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"}\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"{\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"action\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \":\"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"ping\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"}\"\n })]\n }), \"\\n\"]\n })\n })\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"The server sends \", _jsx(_components.code, {\n children: \"welcome\"\n }), \", an initial \", _jsx(_components.code, {\n children: \"snapshot\"\n }), \", live \", _jsx(_components.code, {\n children: \"price\"\n }), \"\\nupdates, and idle \", _jsx(_components.code, {\n children: \"heartbeat\"\n }), \" frames. A successful subscribe is\\nacknowledged before its snapshot and before any live update for the\\nnewly added feed. No update for a removed feed is queued after the\\n\", _jsx(_components.code, {\n children: \"unsubscribed\"\n }), \" acknowledgement. Prices are exact decimal strings.\"]\n }), \"\\n\", _jsx(_components.p, {\n children: \"Chainlink’s live stream can occasionally omit an event. This endpoint\\nperforms no REST reconciliation or backfill, so events missing from the\\nupstream stream or dropped from Edge’s bounded source queue are not\\nreplayed or forwarded later.\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"The number of concurrent connections is assigned per API key; the service\\ndefault is one. Browser clients may authenticate\\nwith \", _jsx(_components.code, {\n children: \"api_key\"\n }), \"; other clients should use the \", _jsx(_components.code, {\n children: \"Authorization\"\n }), \" header.\\nNew handshakes receive \", _jsx(_components.code, {\n children: \"503\"\n }), \" while the upstream feed is stale.\"]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\nfunction _missingMdxReference(id, component) {\n throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");\n}\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"codeStyling":"system","config":{},"pageMetadata":{"title":"WebSocket stream of Chainlink crypto prices","description":"Opens one authenticated WebSocket that receives normalized Chainlink\nData Streams prices.\n\n`symbols` and `variants` select the initial feeds. Omit both for all\n18 feeds, or use `symbols=none` to start empty. Subscriptions can then\nbe changed atomically with text JSON frames:\n\n```json\n{\"action\":\"subscribe\",\"subscriptions\":[{\"symbol\":\"btc\",\"variant\":\"spot\"}]}\n{\"action\":\"unsubscribe\",\"subscriptions\":[{\"symbol\":\"btc\",\"variant\":\"spot\"}]}\n{\"action\":\"subscription.list\"}\n{\"action\":\"ping\"}\n```\n\nThe server sends `welcome`, an initial `snapshot`, live `price`\nupdates, and idle `heartbeat` frames. A successful subscribe is\nacknowledged before its snapshot and before any live update for the\nnewly added feed. No update for a removed feed is queued after the\n`unsubscribed` acknowledgement. Prices are exact decimal strings.\n\nChainlink's live stream can occasionally omit an event. This endpoint\nperforms no REST reconciliation or backfill, so events missing from the\nupstream stream or dropped from Edge's bounded source queue are not\nreplayed or forwarded later.\n\nThe number of concurrent connections is assigned per API key; the service\ndefault is one. Browser clients may authenticate\nwith `api_key`; other clients should use the `Authorization` header.\nNew handshakes receive `503` while the upstream feed is stale.\n","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/streams/crypto-prices","href":"/api-reference/streams/websocket-stream-of-chainlink-crypto-prices","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":[],"openApiReferenceData":{"operation":{"summary":"WebSocket stream of Chainlink crypto prices","description":"Opens one authenticated WebSocket that receives normalized Chainlink\nData Streams prices.\n\n`symbols` and `variants` select the initial feeds. Omit both for all\n18 feeds, or use `symbols=none` to start empty. Subscriptions can then\nbe changed atomically with text JSON frames:\n\n```json\n{\"action\":\"subscribe\",\"subscriptions\":[{\"symbol\":\"btc\",\"variant\":\"spot\"}]}\n{\"action\":\"unsubscribe\",\"subscriptions\":[{\"symbol\":\"btc\",\"variant\":\"spot\"}]}\n{\"action\":\"subscription.list\"}\n{\"action\":\"ping\"}\n```\n\nThe server sends `welcome`, an initial `snapshot`, live `price`\nupdates, and idle `heartbeat` frames. A successful subscribe is\nacknowledged before its snapshot and before any live update for the\nnewly added feed. No update for a removed feed is queued after the\n`unsubscribed` acknowledgement. Prices are exact decimal strings.\n\nChainlink's live stream can occasionally omit an event. This endpoint\nperforms no REST reconciliation or backfill, so events missing from the\nupstream stream or dropped from Edge's bounded source queue are not\nreplayed or forwarded later.\n\nThe number of concurrent connections is assigned per API key; the service\ndefault is one. Browser clients may authenticate\nwith `api_key`; other clients should use the `Authorization` header.\nNew handshakes receive `503` while the upstream feed is stale.\n","operationId":"subscribeCryptoPriceStream","x-feature-stage":"stable","tags":["Streams"],"security":["ecfc47cb-39a9-41d4-8d23-828e5216dc75","1261a4e1-c47b-4f01-8aa0-1b717b9d4094"],"x-websocket":{"connect":"wss://data.gravia.trade/api/v1/streams/crypto-prices","encoding":"json","discriminator":"type","clientActions":["subscribe","unsubscribe","subscription.list","ping"],"serverMessages":{"welcome":"#/components/schemas/CryptoPriceStreamMessage","snapshot":"#/components/schemas/CryptoPriceStreamMessage","price":"#/components/schemas/CryptoPriceStreamMessage","heartbeat":"#/components/schemas/CryptoPriceStreamMessage","subscribed":"#/components/schemas/CryptoPriceStreamMessage","unsubscribed":"#/components/schemas/CryptoPriceStreamMessage","subscription_snapshot":"#/components/schemas/CryptoPriceStreamMessage","error":"#/components/schemas/CryptoPriceStreamMessage","pong":"#/components/schemas/CryptoPriceStreamMessage"}},"parameters":["26fb2404-d12c-4ec5-b0b3-8985b7cf2248","9d657a9c-78e0-4d28-a49d-8925cbaf744f","a1d9047d-056e-404f-8a47-e37871436ceb"],"responses":{"101":"b84e5aa6-8e4f-4ec0-912d-5434bb778760","400":"6510f728-dbac-4098-a35e-f429c082f3e8","401":"9ae96523-8e55-4312-a735-25d04441342b","404":"67ecc3a9-12ad-4b92-a19b-40c383ced2a8","429":"29ffeb09-6408-45b3-bc1b-e6c476e90858","503":"ec425d8c-f668-47a5-85b0-7d20fb38f6aa"},"method":"get","type":"path","servers":["95aa4c4e-3c2a-41df-afae-71836d5c0fa7"],"path":"/api/v1/streams/crypto-prices","baseUrlOptions":["https://data.gravia.trade"],"title":"WebSocket stream of Chainlink crypto prices","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"26fb2404-d12c-4ec5-b0b3-8985b7cf2248":{"name":"symbols","in":"query","required":false,"description":"Comma-separated `btc`, `eth`, `sol`, `xrp`, `doge`, and `bnb`; omit for all or use `none` for no initial subscription.","schema":{"type":"string","isRequired":false,"description":"Comma-separated `btc`, `eth`, `sol`, `xrp`, `doge`, and `bnb`; omit for all or use `none` for no initial subscription.","uniqueKey":"","typeLabel":"string"},"example":"btc,eth"},"9d657a9c-78e0-4d28-a49d-8925cbaf744f":{"name":"variants","in":"query","required":false,"description":"Comma-separated `spot`, `twap_30s`, and `twap_60s`; omit for all. Cannot be combined with `symbols=none`.","schema":{"type":"string","isRequired":false,"description":"Comma-separated `spot`, `twap_30s`, and `twap_60s`; omit for all. Cannot be combined with `symbols=none`.","uniqueKey":"","typeLabel":"string"},"example":"spot,twap_60s"},"a1d9047d-056e-404f-8a47-e37871436ceb":{"name":"api_key","in":"query","required":false,"description":"API key for browser WebSocket handshakes. The Authorization header takes precedence and this value is redacted from logs.","schema":{"type":"string","isRequired":false,"description":"API key for browser WebSocket handshakes. The Authorization header takes precedence and this value is redacted from logs.","uniqueKey":"","typeLabel":"string"}}},"responses":{"b84e5aa6-8e4f-4ec0-912d-5434bb778760":{"description":"WebSocket established; subsequent text frames use the schema below.","content":{"application/json":{"schema":{"type":"object","description":"A WebSocket text frame. Fields not applicable to its `type` are omitted.","required":["type"],"properties":{"type":{"type":"string","enum":["welcome","snapshot","price","heartbeat","subscribed","unsubscribed","subscription_snapshot","error","pong"],"isRequired":true,"uniqueKey":"type","typeLabel":"enum\u003cstring>"},"server_time":{"type":"string","format":"date-time","uniqueKey":"server_time","typeLabel":"string\u003cdate-time>"},"sequence":{"type":"integer","format":"int64","uniqueKey":"sequence","typeLabel":"integer\u003cint64>"},"subscriptions":{"type":"array","items":{"type":"object","required":["symbol","variant"],"properties":{"symbol":{"type":"string","enum":["btc","eth","sol","xrp","doge","bnb"],"isRequired":true,"uniqueKey":"subscriptions.items.[INDEX].symbol","typeLabel":"enum\u003cstring>"},"variant":{"type":"string","enum":["spot","twap_30s","twap_60s"],"isRequired":true,"uniqueKey":"subscriptions.items.[INDEX].variant","typeLabel":"enum\u003cstring>"}},"uniqueKey":"subscriptions.items.[INDEX]","typeLabel":"object"},"uniqueKey":"subscriptions","typeLabel":"object[]"},"added":{"type":"array","items":{"type":"object","required":["symbol","variant"],"properties":{"symbol":{"type":"string","enum":["btc","eth","sol","xrp","doge","bnb"],"isRequired":true,"uniqueKey":"added.items.[INDEX].symbol","typeLabel":"enum\u003cstring>"},"variant":{"type":"string","enum":["spot","twap_30s","twap_60s"],"isRequired":true,"uniqueKey":"added.items.[INDEX].variant","typeLabel":"enum\u003cstring>"}},"uniqueKey":"added.items.[INDEX]","typeLabel":"object"},"uniqueKey":"added","typeLabel":"object[]"},"removed":{"type":"array","items":{"type":"object","required":["symbol","variant"],"properties":{"symbol":{"type":"string","enum":["btc","eth","sol","xrp","doge","bnb"],"isRequired":true,"uniqueKey":"removed.items.[INDEX].symbol","typeLabel":"enum\u003cstring>"},"variant":{"type":"string","enum":["spot","twap_30s","twap_60s"],"isRequired":true,"uniqueKey":"removed.items.[INDEX].variant","typeLabel":"enum\u003cstring>"}},"uniqueKey":"removed.items.[INDEX]","typeLabel":"object"},"uniqueKey":"removed","typeLabel":"object[]"},"prices":{"type":"array","items":{"type":"object","required":["sequence","source","feed_id","symbol","asset","quote","variant","price","valid_from_ms","observed_at_ms","received_at_ms"],"properties":{"sequence":{"type":"integer","format":"int64","isRequired":true,"uniqueKey":"prices.items.[INDEX].sequence","typeLabel":"integer\u003cint64>"},"source":{"type":"string","enum":["chainlink_data_streams"],"isRequired":true,"uniqueKey":"prices.items.[INDEX].source","typeLabel":"enum\u003cstring>"},"feed_id":{"type":"string","pattern":"^0x[0-9a-f]{64}$","isRequired":true,"uniqueKey":"prices.items.[INDEX].feed_id","typeLabel":"string"},"symbol":{"type":"string","example":"btc/usd_twap_60s","isRequired":true,"uniqueKey":"prices.items.[INDEX].symbol","typeLabel":"string"},"asset":{"type":"string","example":"BTC","isRequired":true,"uniqueKey":"prices.items.[INDEX].asset","typeLabel":"string"},"quote":{"type":"string","enum":["USD"],"isRequired":true,"uniqueKey":"prices.items.[INDEX].quote","typeLabel":"enum\u003cstring>"},"variant":{"type":"string","enum":["spot","twap_30s","twap_60s"],"isRequired":true,"uniqueKey":"prices.items.[INDEX].variant","typeLabel":"enum\u003cstring>"},"price":{"type":"string","pattern":"^-?[0-9]+(?:\\.[0-9]+)?$","example":"65432.123456789012345678","isRequired":true,"uniqueKey":"prices.items.[INDEX].price","typeLabel":"string"},"valid_from_ms":{"type":"integer","format":"int64","isRequired":true,"uniqueKey":"prices.items.[INDEX].valid_from_ms","typeLabel":"integer\u003cint64>"},"observed_at_ms":{"type":"integer","format":"int64","isRequired":true,"uniqueKey":"prices.items.[INDEX].observed_at_ms","typeLabel":"integer\u003cint64>"},"received_at_ms":{"type":"integer","format":"int64","isRequired":true,"uniqueKey":"prices.items.[INDEX].received_at_ms","typeLabel":"integer\u003cint64>"},"twap_window_seconds":{"type":"integer","enum":[30,60],"uniqueKey":"prices.items.[INDEX].twap_window_seconds","typeLabel":"enum\u003cinteger>"}},"uniqueKey":"prices.items.[INDEX]","typeLabel":"object"},"uniqueKey":"prices","typeLabel":"object[]"},"missing":{"type":"array","items":{"type":"object","required":["symbol","variant"],"properties":{"symbol":{"type":"string","enum":["btc","eth","sol","xrp","doge","bnb"],"isRequired":true,"uniqueKey":"missing.items.[INDEX].symbol","typeLabel":"enum\u003cstring>"},"variant":{"type":"string","enum":["spot","twap_30s","twap_60s"],"isRequired":true,"uniqueKey":"missing.items.[INDEX].variant","typeLabel":"enum\u003cstring>"}},"uniqueKey":"missing.items.[INDEX]","typeLabel":"object"},"uniqueKey":"missing","typeLabel":"object[]"},"source":{"type":"object","required":["connected","dropped_total","decode_failures","reconnects"],"properties":{"connected":{"type":"boolean","isRequired":true,"uniqueKey":"source.connected","typeLabel":"boolean"},"dropped_total":{"type":"integer","format":"int64","isRequired":true,"uniqueKey":"source.dropped_total","typeLabel":"integer\u003cint64>"},"decode_failures":{"type":"integer","format":"int64","isRequired":true,"uniqueKey":"source.decode_failures","typeLabel":"integer\u003cint64>"},"reconnects":{"type":"integer","format":"int64","isRequired":true,"uniqueKey":"source.reconnects","typeLabel":"integer\u003cint64>"},"last_message_at":{"type":"string","format":"date-time","uniqueKey":"source.last_message_at","typeLabel":"string\u003cdate-time>"},"last_message_age_ms":{"type":"integer","format":"int64","uniqueKey":"source.last_message_age_ms","typeLabel":"integer\u003cint64>"}},"uniqueKey":"source","typeLabel":"object"},"supported":{"type":"object","required":["symbols","variants"],"properties":{"symbols":{"type":"array","items":{"type":"string","uniqueKey":"supported.symbols.items.[INDEX]","typeLabel":"string"},"isRequired":true,"uniqueKey":"supported.symbols","typeLabel":"string[]"},"variants":{"type":"array","items":{"type":"string","uniqueKey":"supported.variants.items.[INDEX]","typeLabel":"string"},"isRequired":true,"uniqueKey":"supported.variants","typeLabel":"string[]"}},"uniqueKey":"supported","typeLabel":"object"},"limits":{"type":"object","required":["max_subscriptions","max_command_batch"],"properties":{"max_subscriptions":{"type":"integer","enum":[18],"isRequired":true,"uniqueKey":"limits.max_subscriptions","typeLabel":"enum\u003cinteger>"},"max_command_batch":{"type":"integer","enum":[18],"isRequired":true,"uniqueKey":"limits.max_command_batch","typeLabel":"enum\u003cinteger>"}},"uniqueKey":"limits","typeLabel":"object"},"code":{"type":"string","uniqueKey":"code","typeLabel":"string"},"message":{"type":"string","uniqueKey":"message","typeLabel":"string"},"feed_id":{"type":"string","uniqueKey":"feed_id","typeLabel":"string"},"symbol":{"type":"string","uniqueKey":"symbol","typeLabel":"string"},"asset":{"type":"string","uniqueKey":"asset","typeLabel":"string"},"quote":{"type":"string","uniqueKey":"quote","typeLabel":"string"},"variant":{"type":"string","uniqueKey":"variant","typeLabel":"string"},"twap_window_seconds":{"type":"integer","uniqueKey":"twap_window_seconds","typeLabel":"integer"},"price":{"type":"string","uniqueKey":"price","typeLabel":"string"},"valid_from_ms":{"type":"integer","format":"int64","uniqueKey":"valid_from_ms","typeLabel":"integer\u003cint64>"},"observed_at_ms":{"type":"integer","format":"int64","uniqueKey":"observed_at_ms","typeLabel":"integer\u003cint64>"},"received_at_ms":{"type":"integer","format":"int64","uniqueKey":"received_at_ms","typeLabel":"integer\u003cint64>"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"type":"welcome","server_time":"2023-11-07T05:31:56Z","sequence":123,"subscriptions":[{"symbol":"btc","variant":"spot"}],"added":[{"symbol":"btc","variant":"spot"}],"removed":[{"symbol":"btc","variant":"spot"}],"prices":[{"sequence":123,"source":"chainlink_data_streams","feed_id":"\u003cstring>","symbol":"btc/usd_twap_60s","asset":"BTC","quote":"USD","variant":"spot","price":"65432.123456789012345678","valid_from_ms":123,"observed_at_ms":123,"received_at_ms":123,"twap_window_seconds":30}],"missing":[{"symbol":"btc","variant":"spot"}],"source":{"connected":true,"dropped_total":123,"decode_failures":123,"reconnects":123,"last_message_at":"2023-11-07T05:31:56Z","last_message_age_ms":123},"supported":{"symbols":["\u003cstring>"],"variants":["\u003cstring>"]},"limits":{"max_subscriptions":18,"max_command_batch":18},"code":"\u003cstring>","message":"\u003cstring>","feed_id":"\u003cstring>","symbol":"\u003cstring>","asset":"\u003cstring>","quote":"\u003cstring>","variant":"\u003cstring>","twap_window_seconds":123,"price":"\u003cstring>","valid_from_ms":123,"observed_at_ms":123,"received_at_ms":123}}},"exampleType":"generated"}},"headers":{"X-Request-ID":{"description":"Correlation ID supplied by the client or generated by the server.","schema":{"type":"string"}},"X-API-Version":{"description":"API version that handled this request.","schema":{"type":"string","enum":["v1"]}},"RateLimit-Limit":{"description":"Request limit for the currently most restrictive policy tier.","schema":{"type":"integer","minimum":1}},"RateLimit-Remaining":{"description":"Requests remaining in the currently most restrictive policy tier.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Whole seconds until capacity returns in the reported policy tier.","schema":{"type":"integer","minimum":0}}},"exampleType":"generated"},"6510f728-dbac-4098-a35e-f429c082f3e8":{"description":"The request could not be completed.","headers":{"X-Request-ID":{"description":"Correlation ID supplied by the client or generated by the server.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code. Branch on this rather than on\n`message`, which may be reworded at any time.\n\n| Code | Status | Meaning |\n| --- | --- | --- |\n| `invalid_request` | 400 | A parameter is missing, malformed, or out of range. |\n| `unauthorized` | 401 | The API key is missing, unknown, or revoked. |\n| `cors_origin_denied` | 403 | The browser origin is not on the deployment's allowlist. |\n| `not_found` | 404 | The requested resource does not exist. |\n| `profile_not_found` | 404 | The `user` value did not resolve to a known profile. |\n| `method_not_allowed` | 405 | The path exists but not for this HTTP method. |\n| `rate_limit_exceeded` | 429 | A sliding-window rate limit was exceeded; honor `Retry-After`. |\n| `stream_limit_reached` | 429 | This API key reached its concurrent allowance for the stream; close an existing connection instead of retrying. |\n| `internal_error` | 500 | Unexpected server-side failure. |\n| `service_unavailable` | 503 | A required backend is not configured or reachable. |\n| `temporarily_unavailable` | 503 | A backend is briefly degraded; retry after a short pause. |\n","example":"invalid_request","isRequired":true,"uniqueKey":"error.code","typeLabel":"string"},"message":{"type":"string","description":"Human-readable error description. Not a stable contract.","example":"user is required","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"request_id":{"type":"string","description":"Correlation ID for support and log lookup, mirroring the\n`X-Request-ID` response header.\n","example":"01f6c90f31d24db3a25c7dba6ca071ee","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"invalid_request","message":"user is required","request_id":"01f6c90f31d24db3a25c7dba6ca071ee"}}}},"exampleType":"generated"}},"exampleType":"generated"},"9ae96523-8e55-4312-a735-25d04441342b":{"description":"The request could not be completed.","headers":{"X-Request-ID":{"description":"Correlation ID supplied by the client or generated by the server.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code. Branch on this rather than on\n`message`, which may be reworded at any time.\n\n| Code | Status | Meaning |\n| --- | --- | --- |\n| `invalid_request` | 400 | A parameter is missing, malformed, or out of range. |\n| `unauthorized` | 401 | The API key is missing, unknown, or revoked. |\n| `cors_origin_denied` | 403 | The browser origin is not on the deployment's allowlist. |\n| `not_found` | 404 | The requested resource does not exist. |\n| `profile_not_found` | 404 | The `user` value did not resolve to a known profile. |\n| `method_not_allowed` | 405 | The path exists but not for this HTTP method. |\n| `rate_limit_exceeded` | 429 | A sliding-window rate limit was exceeded; honor `Retry-After`. |\n| `stream_limit_reached` | 429 | This API key reached its concurrent allowance for the stream; close an existing connection instead of retrying. |\n| `internal_error` | 500 | Unexpected server-side failure. |\n| `service_unavailable` | 503 | A required backend is not configured or reachable. |\n| `temporarily_unavailable` | 503 | A backend is briefly degraded; retry after a short pause. |\n","example":"invalid_request","isRequired":true,"uniqueKey":"error.code","typeLabel":"string"},"message":{"type":"string","description":"Human-readable error description. Not a stable contract.","example":"user is required","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"request_id":{"type":"string","description":"Correlation ID for support and log lookup, mirroring the\n`X-Request-ID` response header.\n","example":"01f6c90f31d24db3a25c7dba6ca071ee","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"invalid_request","message":"user is required","request_id":"01f6c90f31d24db3a25c7dba6ca071ee"}}}},"exampleType":"generated"}},"exampleType":"generated"},"67ecc3a9-12ad-4b92-a19b-40c383ced2a8":{"description":"The request could not be completed.","headers":{"X-Request-ID":{"description":"Correlation ID supplied by the client or generated by the server.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code. Branch on this rather than on\n`message`, which may be reworded at any time.\n\n| Code | Status | Meaning |\n| --- | --- | --- |\n| `invalid_request` | 400 | A parameter is missing, malformed, or out of range. |\n| `unauthorized` | 401 | The API key is missing, unknown, or revoked. |\n| `cors_origin_denied` | 403 | The browser origin is not on the deployment's allowlist. |\n| `not_found` | 404 | The requested resource does not exist. |\n| `profile_not_found` | 404 | The `user` value did not resolve to a known profile. |\n| `method_not_allowed` | 405 | The path exists but not for this HTTP method. |\n| `rate_limit_exceeded` | 429 | A sliding-window rate limit was exceeded; honor `Retry-After`. |\n| `stream_limit_reached` | 429 | This API key reached its concurrent allowance for the stream; close an existing connection instead of retrying. |\n| `internal_error` | 500 | Unexpected server-side failure. |\n| `service_unavailable` | 503 | A required backend is not configured or reachable. |\n| `temporarily_unavailable` | 503 | A backend is briefly degraded; retry after a short pause. |\n","example":"invalid_request","isRequired":true,"uniqueKey":"error.code","typeLabel":"string"},"message":{"type":"string","description":"Human-readable error description. Not a stable contract.","example":"user is required","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"request_id":{"type":"string","description":"Correlation ID for support and log lookup, mirroring the\n`X-Request-ID` response header.\n","example":"01f6c90f31d24db3a25c7dba6ca071ee","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"invalid_request","message":"user is required","request_id":"01f6c90f31d24db3a25c7dba6ca071ee"}}}},"exampleType":"generated"}},"exampleType":"generated"},"29ffeb09-6408-45b3-bc1b-e6c476e90858":{"description":"The key reached its crypto-price connection limit or exceeded its handshake rate limit.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code. Branch on this rather than on\n`message`, which may be reworded at any time.\n\n| Code | Status | Meaning |\n| --- | --- | --- |\n| `invalid_request` | 400 | A parameter is missing, malformed, or out of range. |\n| `unauthorized` | 401 | The API key is missing, unknown, or revoked. |\n| `cors_origin_denied` | 403 | The browser origin is not on the deployment's allowlist. |\n| `not_found` | 404 | The requested resource does not exist. |\n| `profile_not_found` | 404 | The `user` value did not resolve to a known profile. |\n| `method_not_allowed` | 405 | The path exists but not for this HTTP method. |\n| `rate_limit_exceeded` | 429 | A sliding-window rate limit was exceeded; honor `Retry-After`. |\n| `stream_limit_reached` | 429 | This API key reached its concurrent allowance for the stream; close an existing connection instead of retrying. |\n| `internal_error` | 500 | Unexpected server-side failure. |\n| `service_unavailable` | 503 | A required backend is not configured or reachable. |\n| `temporarily_unavailable` | 503 | A backend is briefly degraded; retry after a short pause. |\n","example":"invalid_request","isRequired":true,"uniqueKey":"error.code","typeLabel":"string"},"message":{"type":"string","description":"Human-readable error description. Not a stable contract.","example":"user is required","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"request_id":{"type":"string","description":"Correlation ID for support and log lookup, mirroring the\n`X-Request-ID` response header.\n","example":"01f6c90f31d24db3a25c7dba6ca071ee","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"invalid_request","message":"user is required","request_id":"01f6c90f31d24db3a25c7dba6ca071ee"}}}},"exampleType":"generated"}},"exampleType":"generated"},"ec425d8c-f668-47a5-85b0-7d20fb38f6aa":{"description":"The request could not be completed.","headers":{"X-Request-ID":{"description":"Correlation ID supplied by the client or generated by the server.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code. Branch on this rather than on\n`message`, which may be reworded at any time.\n\n| Code | Status | Meaning |\n| --- | --- | --- |\n| `invalid_request` | 400 | A parameter is missing, malformed, or out of range. |\n| `unauthorized` | 401 | The API key is missing, unknown, or revoked. |\n| `cors_origin_denied` | 403 | The browser origin is not on the deployment's allowlist. |\n| `not_found` | 404 | The requested resource does not exist. |\n| `profile_not_found` | 404 | The `user` value did not resolve to a known profile. |\n| `method_not_allowed` | 405 | The path exists but not for this HTTP method. |\n| `rate_limit_exceeded` | 429 | A sliding-window rate limit was exceeded; honor `Retry-After`. |\n| `stream_limit_reached` | 429 | This API key reached its concurrent allowance for the stream; close an existing connection instead of retrying. |\n| `internal_error` | 500 | Unexpected server-side failure. |\n| `service_unavailable` | 503 | A required backend is not configured or reachable. |\n| `temporarily_unavailable` | 503 | A backend is briefly degraded; retry after a short pause. |\n","example":"invalid_request","isRequired":true,"uniqueKey":"error.code","typeLabel":"string"},"message":{"type":"string","description":"Human-readable error description. Not a stable contract.","example":"user is required","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"request_id":{"type":"string","description":"Correlation ID for support and log lookup, mirroring the\n`X-Request-ID` response header.\n","example":"01f6c90f31d24db3a25c7dba6ca071ee","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"invalid_request","message":"user is required","request_id":"01f6c90f31d24db3a25c7dba6ca071ee"}}}},"exampleType":"generated"}},"exampleType":"generated"}},"security":{"ecfc47cb-39a9-41d4-8d23-828e5216dc75":{"APIKey":{"type":"apiKey","in":"header","name":"Authorization","description":"Raw database-backed API key.","scopes":[]}},"1261a4e1-c47b-4f01-8aa0-1b717b9d4094":{"APIKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"Raw API key supplied as a query parameter. Accepted only on stream endpoints, because browsers cannot set request headers on a WebSocket handshake. The value is redacted from access logs and usage records. Prefer the Authorization header wherever headers can be set.\n","scopes":[]}}},"servers":{"95aa4c4e-3c2a-41df-afae-71836d5c0fa7":{"url":"https://data.gravia.trade","description":"Production server"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"apiKey","in":"header","name":"Authorization","description":"Raw database-backed API key.","scopes":[]},"schema":{"title":"Authorization","type":"string","description":"Raw database-backed API key.","isRequired":true,"typeLabel":"string","deprecated":false},"schemeName":"APIKey","name":"Authorization"}],"title":"APIKey"},{"schemes":[{"scheme":{"type":"apiKey","in":"query","name":"api_key","description":"Raw API key supplied as a query parameter. Accepted only on stream endpoints, because browsers cannot set request headers on a WebSocket handshake. The value is redacted from access logs and usage records. Prefer the Authorization header wherever headers can be set.\n","scopes":[]},"schema":{"title":"api_key","type":"string","description":"Raw API key supplied as a query parameter. Accepted only on stream endpoints, because browsers cannot set request headers on a WebSocket handshake. The value is redacted from access logs and usage records. Prefer the Authorization header wherever headers can be set.\n","isRequired":true,"typeLabel":"string","deprecated":false},"schemeName":"APIKeyQuery","name":"api_key"}],"title":"APIKeyQuery"}]},"originalFileLocation":"https://data.gravia.trade/"},"subdomain":"gravia-trade","siteName":"Gravia Data API","title":"WebSocket stream of Chainlink crypto prices - Gravia Data API","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-09-27T11:39:29.563Z","originalFileLocation":"api-reference/streams/websocket-stream-of-chainlink-crypto-prices.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Opens one authenticated WebSocket that receives normalized Chainlink Data Streams prices. symbols and variants select the initial feeds. Omit both for all 18 feeds, or use symbols=none to start empty. Subscriptions can then be changed atomically with text JSON frames: json {\u0026quot;action\u0026quot;:\u0026quot;subscribe\u0026quot;,\u0026quot;subscriptions\u0026quot;:[{\u0026quot;symbol\u0026quot;:\u0026quot;btc\u0026quot;,\u0026quot;variant\u0026quot;:\u0026quot;spot\u0026quot;}]} {\u0026quot;action\u0026quot;:\u0026quot;unsubscribe\u0026quot;,\u0026quot;subscriptions\u0026quot;:[{\u0026quot;symbol\u0026quot;:\u0026quot;btc\u0026quot;,\u0026quot;variant\u0026quot;:\u0026quot;spot\u0026quot;}]} {\u0026quot;action\u0026quot;:\u0026quot;subscription.list\u0026quot;} {\u0026quot;action\u0026quot;:\u0026quot;ping\u0026quot;} The server sends welcome, an initial snapshot, live price updates, and idle heartbeat frames. A successful subscribe is acknowledged before its snapshot and before any live update for the newly added feed. No update for a removed feed is queued after the unsubscribed acknowledgement. Prices are exact decimal strings. Chainlink\u0026#x27;s live stream can occasionally omit an event. This endpoint performs no REST reconciliation or backfill, so events missing from the upstream stream or dropped from Edge\u0026#x27;s bounded source queue are not replayed or forwarded later. The number of concurrent connections is assigned per API key; the service default is one. Browser clients may authenticate with api_key; other clients should use the Authorization header. New handshakes receive 503 while the upstream feed is stale.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Gravia Data API\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"WebSocket stream of Chainlink crypto prices - Gravia Data API\">\u003cmeta data-mint-head property=\"og:description\" content=\"Opens one authenticated WebSocket that receives normalized Chainlink Data Streams prices. symbols and variants select the initial feeds. Omit both for all 18 feeds, or use symbols=none to start empty. Subscriptions can then be changed atomically with text JSON frames: json {\u0026quot;action\u0026quot;:\u0026quot;subscribe\u0026quot;,\u0026quot;subscriptions\u0026quot;:[{\u0026quot;symbol\u0026quot;:\u0026quot;btc\u0026quot;,\u0026quot;variant\u0026quot;:\u0026quot;spot\u0026quot;}]} {\u0026quot;action\u0026quot;:\u0026quot;unsubscribe\u0026quot;,\u0026quot;subscriptions\u0026quot;:[{\u0026quot;symbol\u0026quot;:\u0026quot;btc\u0026quot;,\u0026quot;variant\u0026quot;:\u0026quot;spot\u0026quot;}]} {\u0026quot;action\u0026quot;:\u0026quot;subscription.list\u0026quot;} {\u0026quot;action\u0026quot;:\u0026quot;ping\u0026quot;} The server sends welcome, an initial snapshot, live price updates, and idle heartbeat frames. A successful subscribe is acknowledged before its snapshot and before any live update for the newly added feed. No update for a removed feed is queued after the unsubscribed acknowledgement. Prices are exact decimal strings. Chainlink\u0026#x27;s live stream can occasionally omit an event. This endpoint performs no REST reconciliation or backfill, so events missing from the upstream stream or dropped from Edge\u0026#x27;s bounded source queue are not replayed or forwarded later. The number of concurrent connections is assigned per API key; the service default is one. Browser clients may authenticate with api_key; other clients should use the Authorization header. New handshakes receive 503 while the upstream feed is stale.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Gravia Data API\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://gravia-trade.mintlify.app/_mintlify/api/og/v2?division=Streams\u0026amp;title=WebSocket+stream+of+Chainlink+crypto+prices\u0026amp;description=Opens+one+authenticated+WebSocket+that+receives+normalized+Chainlink%0AData+Streams+prices.%0A%0A%60symbols%60+and+%60variants%60+select+the+initial+feeds.+Omit+both+for+all%0A\u0026amp;theme=8c421f2e72c1c7001e92ec31\u0026amp;signature=e7064f3456106e7bb381abb05eaf0222323a581c6c2ce796b0f3a94121a6b113\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"WebSocket stream of Chainlink crypto prices - Gravia Data API\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Opens one authenticated WebSocket that receives normalized Chainlink Data Streams prices. symbols and variants select the initial feeds. Omit both for all 18 feeds, or use symbols=none to start empty. Subscriptions can then be changed atomically with text JSON frames: json {\u0026quot;action\u0026quot;:\u0026quot;subscribe\u0026quot;,\u0026quot;subscriptions\u0026quot;:[{\u0026quot;symbol\u0026quot;:\u0026quot;btc\u0026quot;,\u0026quot;variant\u0026quot;:\u0026quot;spot\u0026quot;}]} {\u0026quot;action\u0026quot;:\u0026quot;unsubscribe\u0026quot;,\u0026quot;subscriptions\u0026quot;:[{\u0026quot;symbol\u0026quot;:\u0026quot;btc\u0026quot;,\u0026quot;variant\u0026quot;:\u0026quot;spot\u0026quot;}]} {\u0026quot;action\u0026quot;:\u0026quot;subscription.list\u0026quot;} {\u0026quot;action\u0026quot;:\u0026quot;ping\u0026quot;} The server sends welcome, an initial snapshot, live price updates, and idle heartbeat frames. A successful subscribe is acknowledged before its snapshot and before any live update for the newly added feed. No update for a removed feed is queued after the unsubscribed acknowledgement. Prices are exact decimal strings. Chainlink\u0026#x27;s live stream can occasionally omit an event. This endpoint performs no REST reconciliation or backfill, so events missing from the upstream stream or dropped from Edge\u0026#x27;s bounded source queue are not replayed or forwarded later. The number of concurrent connections is assigned per API key; the service default is one. Browser clients may authenticate with api_key; other clients should use the Authorization header. New handshakes receive 503 while the upstream feed is stale.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://gravia-trade.mintlify.app/_mintlify/api/og/v2?division=Streams\u0026amp;title=WebSocket+stream+of+Chainlink+crypto+prices\u0026amp;description=Opens+one+authenticated+WebSocket+that+receives+normalized+Chainlink%0AData+Streams+prices.%0A%0A%60symbols%60+and+%60variants%60+select+the+initial+feeds.+Omit+both+for+all%0A\u0026amp;theme=8c421f2e72c1c7001e92ec31\u0026amp;signature=e7064f3456106e7bb381abb05eaf0222323a581c6c2ce796b0f3a94121a6b113\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/gravia-trade/UCUg-2SVPMUpHKiA/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Gravia Data API\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#9FFBFE\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/streams/websocket-stream-of-chainlink-crypto-prices.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.gravia.trade/#organization\",\"name\":\"Gravia Data API\",\"url\":\"https://docs.gravia.trade\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/gravia-trade/q65mj9SyvyR5CJGQ/images/Gravia-black-logo.svg?fit=max\u0026auto=format\u0026n=q65mj9SyvyR5CJGQ\u0026q=85\u0026s=d20027ef4daf7f22158c1c43c271a664\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.gravia.trade#website\",\"name\":\"Gravia Data API\",\"url\":\"https://docs.gravia.trade\",\"publisher\":{\"@id\":\"https://docs.gravia.trade/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices#webpage\",\"url\":\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices\",\"name\":\"WebSocket stream of Chainlink crypto prices\",\"description\":\"Opens one authenticated WebSocket that receives normalized Chainlink Data Streams prices. symbols and variants select the initial feeds. Omit both for all 18 feeds, or use symbols=none to start empty. Subscriptions can then be changed atomically with text JSON frames: json {\\\"action\\\":\\\"subscribe\\\",\\\"subscriptions\\\":[{\\\"symbol\\\":\\\"btc\\\",\\\"variant\\\":\\\"spot\\\"}]} {\\\"action\\\":\\\"unsubscribe\\\",\\\"subscriptions\\\":[{\\\"symbol\\\":\\\"btc\\\",\\\"variant\\\":\\\"spot\\\"}]} {\\\"action\\\":\\\"subscription.list\\\"} {\\\"action\\\":\\\"ping\\\"} The server sends welcome, an initial snapshot, live price updates, and idle heartbeat frames. A successful subscribe is acknowledged before its snapshot and before any live update for the newly added feed. No update for a removed feed is queued after the unsubscribed acknowledgement. Prices are exact decimal strings. Chainlink's live stream can occasionally omit an event. This endpoint performs no REST reconciliation or backfill, so events missing from the upstream stream or dropped from Edge's bounded source queue are not replayed or forwarded later. The number of concurrent connections is assigned per API key; the service default is one. Browser clients may authenticate with api_key; other clients should use the Authorization header. New handshakes receive 503 while the upstream feed is stale.\",\"dateModified\":\"2026-09-27T11:39:29.563Z\",\"isPartOf\":{\"@id\":\"https://docs.gravia.trade#website\"},\"breadcrumb\":{\"@id\":\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Gravia Data API\",\"item\":\"https://docs.gravia.trade\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"WebSocket stream of Chainlink crypto prices\",\"item\":\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices#apireference\",\"headline\":\"WebSocket stream of Chainlink crypto prices\",\"name\":\"WebSocket stream of Chainlink crypto prices\",\"description\":\"Opens one authenticated WebSocket that receives normalized Chainlink Data Streams prices. symbols and variants select the initial feeds. Omit both for all 18 feeds, or use symbols=none to start empty. Subscriptions can then be changed atomically with text JSON frames: json {\\\"action\\\":\\\"subscribe\\\",\\\"subscriptions\\\":[{\\\"symbol\\\":\\\"btc\\\",\\\"variant\\\":\\\"spot\\\"}]} {\\\"action\\\":\\\"unsubscribe\\\",\\\"subscriptions\\\":[{\\\"symbol\\\":\\\"btc\\\",\\\"variant\\\":\\\"spot\\\"}]} {\\\"action\\\":\\\"subscription.list\\\"} {\\\"action\\\":\\\"ping\\\"} The server sends welcome, an initial snapshot, live price updates, and idle heartbeat frames. A successful subscribe is acknowledged before its snapshot and before any live update for the newly added feed. No update for a removed feed is queued after the unsubscribed acknowledgement. Prices are exact decimal strings. Chainlink's live stream can occasionally omit an event. This endpoint performs no REST reconciliation or backfill, so events missing from the upstream stream or dropped from Edge's bounded source queue are not replayed or forwarded later. The number of concurrent connections is assigned per API key; the service default is one. Browser clients may authenticate with api_key; other clients should use the Authorization header. New handshakes receive 503 while the upstream feed is stale.\",\"url\":\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices\",\"mainEntityOfPage\":{\"@id\":\"https://docs.gravia.trade/api-reference/streams/websocket-stream-of-chainlink-crypto-prices#webpage\"},\"dateModified\":\"2026-09-27T11:39:29.563Z\",\"publisher\":{\"@id\":\"https://docs.gravia.trade/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.gravia.trade#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Gravia Data API\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Gravia Data API","nav":{"global":null,"tabs":[{"tab":"Documentation","icon":"book","pages":[{"title":"Documentation","href":""}]},{"tab":"API Reference","icon":"code","groups":[{"group":"Webhooks","pages":[{"title":"List owned webhooks","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /v1/webhooks","href":"/api-reference/webhooks/list-owned-webhooks"},{"title":"Create a webhook","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ post /v1/webhooks","href":"/api-reference/webhooks/create-a-webhook"},{"title":"List supported webhook events","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /v1/webhooks/events","href":"/api-reference/webhooks/list-supported-webhook-events"},{"title":"Get an owned webhook","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /v1/webhooks/{id}","href":"/api-reference/webhooks/get-an-owned-webhook"},{"title":"Update a webhook","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ put /v1/webhooks/{id}","href":"/api-reference/webhooks/update-a-webhook"},{"title":"Delete a webhook","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ delete /v1/webhooks/{id}","href":"/api-reference/webhooks/delete-a-webhook"},{"title":"Rotate signing secret","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ post /v1/webhooks/{id}/rotate-secret","href":"/api-reference/webhooks/rotate-signing-secret"},{"title":"Send a test callback","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ post /v1/webhooks/{id}/test","href":"/api-reference/webhooks/send-a-test-callback"},{"title":"List terminal delivery logs","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /v1/webhooks/{id}/logs","href":"/api-reference/webhooks/list-terminal-delivery-logs"}]},{"group":"Operational","pages":[{"title":"Health check","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /health","href":"/api-reference/operational/health-check"}]},{"group":"Markets","pages":[{"title":"Get the current crypto up/down market","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/markets/crypto/current","href":"/api-reference/markets/get-the-current-crypto-updown-market"},{"title":"List market categories","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/markets/categories/list","href":"/api-reference/markets/list-market-categories"},{"title":"Get a market's price to beat","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/markets/crypto/price-to-beat","href":"/api-reference/markets/get-a-markets-price-to-beat"}]},{"group":"Users","pages":[{"title":"Get a user's trades and on-chain activities","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/users/activities","href":"/api-reference/users/get-a-users-trades-and-on-chain-activities"},{"title":"Get a user's trades with markouts","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/users/trades/markouts","href":"/api-reference/users/get-a-users-trades-with-markouts"},{"title":"Get markouts grouped by counterparty","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/users/trades/counterparties","href":"/api-reference/users/get-markouts-grouped-by-counterparty"},{"title":"Get one profile's category metrics","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/users/categories","href":"/api-reference/users/get-one-profiles-category-metrics"},{"title":"Get a user's positions","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/users/positions","href":"/api-reference/users/get-a-users-positions"},{"title":"Get a concise user profile","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/users/profile","href":"/api-reference/users/get-a-concise-user-profile"},{"title":"Get a user's taker tier","description":"Resolves a wallet address or Polymarket username to its canonical data\naddress and returns rolling 30-day weighted taker volume, current tier,\nand progress toward the next tier.\n","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/users/taker-tier","href":"/api-reference/users/get-a-users-taker-tier"}]},{"group":"Streams","pages":[{"title":"WebSocket stream of Chainlink crypto prices","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/streams/crypto-prices","href":"/api-reference/streams/websocket-stream-of-chainlink-crypto-prices"},{"title":"WebSocket stream of live trades, activities and conversions","description":"A WebSocket channel, not a request/response endpoint. Connect, and the\nserver pushes rows as they are decoded — confirmed on-chain trades,\nactivities and conversions, plus unconfirmed mempool trades if you ask\nfor them.\n\n```\nwss://data.gravia.trade/api/v1/streams/transactions?streams=trades,activities,conversions\u0026mempool=false\n```\n\nThe `101` below is the handshake and carries no HTTP body. Everything\nthe server says afterwards is a WebSocket text frame holding one JSON\nobject. Your WebSocket client performs the upgrade, so `Upgrade`,\n`Connection` and the `Sec-WebSocket-*` headers are never yours to set,\nand the query parameters are read once, at connect time.\n\nBrowsers cannot set request headers on a handshake, so authenticate\nthere with `?api_key=\u003cyour-api-key>` and with the `Authorization`\nheader everywhere else.\n\n```js\nconst socket = new WebSocket(\n \"wss://data.gravia.trade/api/v1/streams/transactions\" +\n \"?streams=trades\u0026api_key=\" + apiKey,\n);\n\nsocket.addEventListener(\"message\", (frame) => {\n const message = JSON.parse(frame.data);\n switch (message.type) {\n case \"trade\":\n // status is \"confirmed\", or \"pending\" for a mempool trade\n break;\n case \"retraction\":\n // drop whatever you hold for message.tx_hash on message.stream\n break;\n }\n});\n\n// Filters are managed in band, once the socket is open.\nsocket.send(JSON.stringify({action: \"filter.add\", wallets: [wallet]}));\n```\n\n**Concurrent connections are limited per API key.** The service default is\none, but a key may be assigned a different allowance. Exceeding it\nreturns `429` with the `stream_limit_reached` code, which is distinct\nfrom ordinary rate limiting: close an existing stream rather than\nbacking off.\n\n**Fixed at connect.** `streams` and `mempool` cannot be changed in\nband. `wallet` and `market` only seed the filters, which are then\nmanaged with the client messages below, so a caller holding\nthousands of selectors is not limited by URL length.\n\n**Filters.** Both sets are optional; omitting them streams\neverything. They are ANDed, and selectors within each are ORed.\n`wallet` matches the row subject (`user_address`) only — the\ncounterparty of a fill appears as the subject of its own row, so\nmatching `taker_address` as well would deliver the same fill\nseveral times. A filter change is not retroactive.\n\n**Liveness.** The server sends a protocol ping every 20 seconds,\nand a `heartbeat` frame on any tick where it wrote nothing else, so\na quiet stream stays visibly alive to application code that cannot\nobserve protocol pings. A connection that sends nothing at all for\n60 seconds is closed; the automatic pong your client already sends\nis enough to hold it open.\n\n**Delivery is at-most-once with no replay.** `sequence` is a\nserver-global ordinal, so a filtered client sees gaps by design; it\nis not a gap detector, and it is absent from a control frame sent\nbefore the server has decoded anything. `source.dropped_total` in\neach heartbeat counts rows the server discarded because it was\nbehind, which is the only loss a client cannot otherwise detect.\nRead the REST endpoints when completeness matters.\n\nRetractions ignore the wallet and market filters, because a reorg\nretraction carries no rows and therefore no wallet or market;\nstream selection still applies. Ignore one for a `tx_hash` you hold\nno state for. Pending trades are never retracted, and a pending\ntrade may never land — time out your own pending state. With\n`mempool=true` a landed trade is delivered twice, once pending and\nonce confirmed; deduplicate on `(tx_hash, order_hash)`.\n\n**Close codes.** `1008` with `client is too slow` means the server\ngave up writing to you and dropped the connection rather than\nwaiting; reconnect with tighter filters or a faster reader. `1001`\nwith `server is shutting down` is a deploy — reconnect. Anything\nthat fails before the upgrade is ordinary HTTP, listed under\nResponses below.\n\n### Client messages\n\nOne JSON object per text frame, discriminated by `action`. Unknown\nkeys are rejected, and every frame — `ping` included — is counted\nagainst a budget of 20 commands per second with a burst of 40.\n\n```json\n{\"action\": \"filter.add\", \"wallets\": [\"0x674887d1ac838099a48b629dff53f25b7b87ee08\"]}\n{\"action\": \"filter.remove\", \"markets\": [\"67568438763601610729831023256910933987242052537121118642143709840881218761985\"]}\n{\"action\": \"filter.set\", \"markets\": [\"0xb4386b7dacda0f3148be799de8d992e1f3cb3646ecb42b6c09485ed7d6feffc7\"]}\n{\"action\": \"filter.clear\", \"target\": \"wallets\"}\n{\"action\": \"filter.list\", \"include_values\": true}\n{\"action\": \"ping\"}\n```\n\n`wallets` entries are `0x`-prefixed 20-byte addresses; usernames are\nrejected. `markets` entries are classified by shape: `0x` followed\nby 64 hex is a condition id, a decimal string is a CLOB token id.\nMarket slugs and `category:` selectors are not accepted here.\n`target` is `wallets`, `markets` or `all`, and defaults to `all`. A\nbatch applies atomically: one malformed entry rejects the whole\nmessage and leaves the filter set untouched. At most 5,000 entries\nper message; `welcome` reports the standing caps in `limits`.\n\n### Server messages\n\nEvery frame carries a `type`, and `type` is the only field to\ndispatch on.\n\n| `type` | Sent when | Structure |\n| --- | --- | --- |\n| `welcome` | Once, immediately after the handshake. | `TransactionStreamWelcome` |\n| `trade` | A trade was decoded. `status` is `confirmed`, or `pending` for a mempool trade. | `TransactionStreamTrade` |\n| `activity` | A split, merge or redemption was decoded. | `TransactionStreamActivity` |\n| `conversion` | A NegRisk conversion was decoded. | `TransactionStreamConversion` |\n| `retraction` | A transaction was reorged out. | `TransactionStreamRetraction` |\n| `heartbeat` | A ping tick passed with nothing else to write. | `TransactionStreamHeartbeat` |\n| `filter.updated` | A filter command was applied. | `TransactionStreamFilterUpdated` |\n| `filter.rejected` | A filter command was refused and nothing changed. | `TransactionStreamFilterRejected` |\n| `filter.snapshot` | Reply to `filter.list`. | `TransactionStreamFilterSnapshot` |\n| `error` | A frame could not be handled. The socket stays open. | `TransactionStreamError` |\n| `pong` | Reply to `{\"action\": \"ping\"}`. | `TransactionStreamPong` |\n\nA `trade`, `activity` or `conversion` frame is the decoded upstream\nrow forwarded whole, with `type` and `sequence` added in front, so\ntreat unrecognized fields as forward-compatible additions rather\nthan errors. `v` is the upstream row schema version, currently `2`.\nMoney, size and price fields cross as decimal **strings**, and so do\ntoken ids: they are 256-bit, and a JSON number would silently lose\nprecision. `partial` marks a row where the fields named in\n`missing` read as unknown rather than zero.\n\n`welcome` — once, immediately after the handshake:\n\n```json\n{\n \"type\": \"welcome\",\n \"server_time\": \"2026-08-17T12:00:00.123456789Z\",\n \"sequence\": 918473,\n \"streams\": [\"trades\", \"activities\", \"conversions\"],\n \"mempool\": false,\n \"filters\": {\"wallets\": 1, \"condition_ids\": 0, \"token_ids\": 0},\n \"limits\": {\"max_wallets\": 25000, \"max_markets\": 25000, \"max_filter_batch\": 5000},\n \"source\": {\n \"connected\": true,\n \"last_message_at\": \"2026-08-17T12:00:00.031000000Z\",\n \"dropped_total\": 0\n }\n}\n```\n\n`trade` — a confirmed fill:\n\n```json\n{\n \"type\": \"trade\",\n \"sequence\": 918501,\n \"v\": 2,\n \"stream\": \"trades\",\n \"status\": \"confirmed\",\n \"block_number\": 91937590,\n \"block_hash\": \"0x7c1b9f3a2d8e4c5b6a0f9e8d7c6b5a4938271605f4e3d2c1b0a9f8e7d6c5b4a3\",\n \"block_timestamp\": 1786924800,\n \"tx_hash\": \"0x3f8c1d9b7a5e4c2b0d9f8e7a6c5b4d3e2f1a09b8c7d6e5f4a3b2c1d0e9f8a7b6\",\n \"tx_row_index\": 1,\n \"tx_row_count\": 3,\n \"partial\": false,\n \"missing\": [],\n \"published_at\": 1786924801.312,\n \"log_index\": 42,\n \"order_hash\": \"0x5e4d3c2b1a09f8e7d6c5b4a3928170615f4e3d2c1b0a9f8e7d6c5b4a39281706\",\n \"order_hash_alt\": null,\n \"user_address\": \"0x674887d1ac838099a48b629dff53f25b7b87ee08\",\n \"taker_address\": \"0x9c1a5f3b2d8e4c6b7a0f9e8d7c6b5a4938271605\",\n \"side\": \"BUY\",\n \"token_id\": \"67568438763601610729831023256910933987242052537121118642143709840881218761985\",\n \"canonical_token_id\": \"67568438763601610729831023256910933987242052537121118642143709840881218761985\",\n \"condition_id\": \"0xb4386b7dacda0f3148be799de8d992e1f3cb3646ecb42b6c09485ed7d6feffc7\",\n \"shares\": \"20000\",\n \"usdc_amount\": \"9800.5\",\n \"share_price\": \"0.49\",\n \"fee_amount\": \"0\",\n \"fee_refund_amount\": \"0\",\n \"trade_timestamp\": 1786924800,\n \"contract_version\": 2,\n \"is_taker_order\": true,\n \"builder\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"metadata\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n}\n```\n\nA pending mempool trade is the same frame with `status: \"pending\"`.\nIt has no block yet, so `block_number` and `log_index` are `0`,\n`block_hash` and `block_timestamp` are `null`, and\n`canonical_token_id` is `null`; `order_hash_alt` may carry the\nNegRisk candidate order hash, so match a pending trade against its\nconfirmation on either hash.\n\n`activity` — a split, merge or redemption:\n\n```json\n{\n \"type\": \"activity\",\n \"sequence\": 918502,\n \"v\": 2,\n \"stream\": \"activities\",\n \"status\": \"confirmed\",\n \"block_number\": 91937590,\n \"block_hash\": \"0x7c1b9f3a2d8e4c5b6a0f9e8d7c6b5a4938271605f4e3d2c1b0a9f8e7d6c5b4a3\",\n \"block_timestamp\": 1786924800,\n \"tx_hash\": \"0x3f8c1d9b7a5e4c2b0d9f8e7a6c5b4d3e2f1a09b8c7d6e5f4a3b2c1d0e9f8a7b6\",\n \"tx_row_index\": 2,\n \"tx_row_count\": 3,\n \"partial\": false,\n \"missing\": [],\n \"published_at\": 1786924801.312,\n \"event_type\": \"RedeemPosition\",\n \"log_index\": 7,\n \"user_address\": \"0x674887d1ac838099a48b629dff53f25b7b87ee08\",\n \"token_id\": \"67568438763601610729831023256910933987242052537121118642143709840881218761985\",\n \"canonical_token_id\": \"34460519301295595556376203968565021162434252843477398085423120621766516073216\",\n \"condition_id\": \"0xb4386b7dacda0f3148be799de8d992e1f3cb3646ecb42b6c09485ed7d6feffc7\",\n \"price\": \"1\",\n \"amount\": \"20000\",\n \"collateral_token\": \"0x2791bca1f2de4661ed88a30c99a7a9449aa84174\",\n \"parent_collection_id\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"activity_timestamp\": 1786924800,\n \"is_neg_ctf\": false,\n \"contract_version\": 2,\n \"auto_redeem\": false\n}\n```\n\n`conversion` — a NegRisk conversion leg:\n\n```json\n{\n \"type\": \"conversion\",\n \"sequence\": 918503,\n \"v\": 2,\n \"stream\": \"conversions\",\n \"status\": \"confirmed\",\n \"block_number\": 91937590,\n \"block_hash\": \"0x7c1b9f3a2d8e4c5b6a0f9e8d7c6b5a4938271605f4e3d2c1b0a9f8e7d6c5b4a3\",\n \"block_timestamp\": 1786924800,\n \"tx_hash\": \"0x3f8c1d9b7a5e4c2b0d9f8e7a6c5b4d3e2f1a09b8c7d6e5f4a3b2c1d0e9f8a7b6\",\n \"tx_row_index\": 3,\n \"tx_row_count\": 3,\n \"partial\": false,\n \"missing\": [],\n \"published_at\": 1786924801.312,\n \"log_index\": 3,\n \"user_address\": \"0x674887d1ac838099a48b629dff53f25b7b87ee08\",\n \"token_id\": \"67568438763601610729831023256910933987242052537121118642143709840881218761985\",\n \"canonical_token_id\": \"34460519301295595556376203968565021162434252843477398085423120621766516073216\",\n \"condition_id\": \"0xb4386b7dacda0f3148be799de8d992e1f3cb3646ecb42b6c09485ed7d6feffc7\",\n \"negrisk_market_id\": \"0x0b8f7e6d5c4b3a29180706f5e4d3c2b1a0f9e8d7c6b5a4938271605f4e3d2c1b\",\n \"amount\": \"250\",\n \"conversion_timestamp\": 1786924800,\n \"contract_version\": 2\n}\n```\n\n`retraction` — the transaction was reorged out. It carries no row\nfields at all, so undo state by `tx_hash` and `stream`:\n\n```json\n{\n \"type\": \"retraction\",\n \"sequence\": 918504,\n \"v\": 2,\n \"stream\": \"trades\",\n \"status\": \"retracted\",\n \"tx_hash\": \"0x3f8c1d9b7a5e4c2b0d9f8e7a6c5b4d3e2f1a09b8c7d6e5f4a3b2c1d0e9f8a7b6\",\n \"block_number\": 91937590,\n \"block_hash\": \"0x7c1b9f3a2d8e4c5b6a0f9e8d7c6b5a4938271605f4e3d2c1b0a9f8e7d6c5b4a3\",\n \"published_at\": 1786924802.881\n}\n```\n\n`heartbeat` — nothing else was written on this tick:\n\n```json\n{\n \"type\": \"heartbeat\",\n \"server_time\": \"2026-08-17T12:00:20.001002003Z\",\n \"sequence\": 918504,\n \"source\": {\n \"connected\": true,\n \"last_message_at\": \"2026-08-17T12:00:19.900000000Z\",\n \"dropped_total\": 12\n }\n}\n```\n\n`filter.updated` — the command was applied. `added` and `removed`\nare net count deltas, not the values applied, so a `filter.set` that\nswaps one wallet for another reports zero of each:\n\n```json\n{\n \"type\": \"filter.updated\",\n \"filters\": {\"wallets\": 2, \"condition_ids\": 0, \"token_ids\": 1},\n \"added\": {\"wallets\": 1, \"condition_ids\": 0, \"token_ids\": 1},\n \"removed\": {\"wallets\": 0, \"condition_ids\": 0, \"token_ids\": 0}\n}\n```\n\n`filter.rejected` — nothing was applied. A validation failure names\nevery entry it refused; a cap failure carries only `code` and\n`message`:\n\n```json\n{\n \"type\": \"filter.rejected\",\n \"code\": \"invalid_filter\",\n \"message\": \"no changes were applied\",\n \"rejected\": [\n {\"value\": \"polymarket-btc-up-or-down\", \"reason\": \"market slugs are not supported; use a condition id or CLOB token id\"},\n {\"value\": \"@trader\", \"reason\": \"usernames are not supported; use a 0x-prefixed 20-byte address\"}\n ]\n}\n```\n\n```json\n{\n \"type\": \"filter.rejected\",\n \"code\": \"filter_limit_reached\",\n \"message\": \"txstream: filter limit reached: at most 25000 wallets\"\n}\n```\n\n`filter.snapshot` — the reply to `filter.list`. `values` is present\nonly when the request set `include_values: true`, each list is\ncapped at 1,000 entries, and `truncated` says whether any list was\ncut short:\n\n```json\n{\n \"type\": \"filter.snapshot\",\n \"sequence\": 918505,\n \"filters\": {\"wallets\": 1, \"condition_ids\": 1, \"token_ids\": 0},\n \"values\": {\n \"wallets\": [\"0x674887d1ac838099a48b629dff53f25b7b87ee08\"],\n \"condition_ids\": [\"0xb4386b7dacda0f3148be799de8d992e1f3cb3646ecb42b6c09485ed7d6feffc7\"],\n \"token_ids\": [],\n \"truncated\": false\n }\n}\n```\n\n`error` — the frame could not be handled. Non-fatal: the socket\nstays open and the filters are untouched:\n\n```json\n{\n \"type\": \"error\",\n \"code\": \"unsupported_message\",\n \"message\": \"action must be filter.add, filter.remove, filter.set, filter.clear, filter.list or ping\"\n}\n```\n\n`pong` — the reply to `{\"action\": \"ping\"}`, and nothing more:\n\n```json\n{\"type\": \"pong\"}\n```\n","deprecated":null,"version":null,"openapi":"https://data.gravia.trade/ get /api/v1/streams/transactions","href":"/api-reference/streams/websocket-stream-of-live-trades-activities-and-conversions"}]}]}]},"basePath":"","title":"WebSocket stream of Chainlink crypto prices - Gravia Data API","buildId":"dpl_G9nrg4qeJSZtah1Ziwbc2n6WkLch","deploymentId":"dpl_G9nrg4qeJSZtah1Ziwbc2n6WkLch","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-B7XKH4J3.js","utils-lOYzL7z-.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-DF6jUUIM.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-Dpsj5f7C.js","snippetPresets-CYeiDe8v.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","ApiExamples-CUFz1YZ_.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-D8H_iLS4.js","shallow-DdluZBHX.js","getApiPlaygroundDisplay-B9922vev.js","CodeSnippet-CMoRNGYs.js","CodeSnippets-DwyrPHuw.js","Page-DSVu9Ucl.js","getPastedJson-G-zIvlHh.js","icon-B03fnEy0.js","MethodPill-CW7teklc.js","DuplicateIcon-CtO8eekd.js","createIcon-DZTKdM_A.js","DynamicMarkdown-D5M2At0B.js","SectionHeading-C_2NaA2U.js","axios-vUo_bRtp.js","Markdown-D7QRHV3m.js","clsx-D1Z-ELXV.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-lvhuD9Du.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-CKfC4ywL.js"]}