{"openapi":"3.1.0","info":{"title":"SoSoValue over Airnode","version":"2026-08-07","description":"SoSoValue is a crypto research platform: daily flows, assets and premiums of the spot ETFs that hold crypto assets, a crypto news feed gathered from publishers, research desks and social accounts, SoSoValue's own sector indices, and US macro releases, money-market rates and FOMC rate probabilities. This Airnode wraps reads from SoSoValue's v1 Open API, so a consumer receives each answer with a signature saying this Airnode obtained it from SoSoValue at this time. News items belong to the publishers they link to.\n\nEvery response carries an EIP-191 signature from the Airnode that served it, so the data can be attributed back to its source rather than trusted on reputation."},"servers":[{"url":"https://airnode-sosovalue.fly.dev"}],"paths":{"/":{"get":{"operationId":"getDocumentation","summary":"This document.","description":"Describes the operations this Airnode serves and how to verify what it returns. Free.","responses":{"200":{"description":"An OpenAPI document describing this Airnode.","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"performRequest","summary":"Perform an operation and attest to the response.","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"title":"getEtfMarketSnapshot","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"getEtfMarketSnapshot","description":"A crypto ETF's latest settled day: net inflow, net assets, price, premium and volume.","x-airnode-returns":{"code":"integer","message":"string","data":"object","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["ticker"],"properties":{"ticker":{"description":"ETF ticker, such as IBIT or FBTC, as listEtfs answers it.","type":"string"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"listEtfs","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"listEtfs","description":"The spot ETFs that hold a crypto asset in a country, with ticker, name and exchange.","x-airnode-returns":{"code":"integer","message":"string","data":"array","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["symbol","country_code"],"properties":{"symbol":{"description":"The crypto asset the ETFs hold, as its ticker, such as BTC, ETH or SOL. Case-insensitive. SoSoValue's documentation lists which assets have ETFs in which country, and an asset with none in the country asked for is a 400 from SoSoValue, which reaches a caller as a 502.","type":"string"},"country_code":{"description":"Country the ETFs are listed in, such as US or HK. Case-insensitive. Hong Kong lists fewer assets than the US.","type":"string"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"getEtfSummaryHistory","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"getEtfSummaryHistory","description":"Daily totals across every spot ETF for a crypto asset in a country: net inflow, assets, value traded.","x-airnode-returns":{"code":"integer","message":"string","data":"array","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["symbol","country_code"],"properties":{"symbol":{"description":"The crypto asset the ETFs hold, as its ticker, such as BTC, ETH or SOL. Case-insensitive. SoSoValue's documentation lists which assets have ETFs in which country, and an asset with none in the country asked for is a 400 from SoSoValue, which reaches a caller as a 502.","type":"string"},"country_code":{"description":"Country the ETFs are listed in, such as US or HK. Case-insensitive. Hong Kong lists fewer assets than the US.","type":"string"},"start_date":{"description":"First trading day to answer, as yyyy-MM-dd, inclusive. Only the most recent month is available, and an earlier date is refused with a 400, which reaches a caller as a 502.","type":"string"},"end_date":{"description":"Last trading day to answer, as yyyy-MM-dd, inclusive. Limited to the most recent month.","type":"string"},"limit":{"description":"How many days to answer, at most 300. Defaults to 50.","type":"integer"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"getEtfHistory","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"getEtfHistory","description":"One crypto ETF's daily flows, assets, premium and volume over the most recent month.","x-airnode-returns":{"code":"integer","message":"string","data":"array","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["ticker"],"properties":{"ticker":{"description":"ETF ticker, such as IBIT or FBTC, as listEtfs answers it.","type":"string"},"start_date":{"description":"First trading day to answer, as yyyy-MM-dd, inclusive. Only the most recent month is available, and an earlier date is refused with a 400, which reaches a caller as a 502.","type":"string"},"end_date":{"description":"Last trading day to answer, as yyyy-MM-dd, inclusive. Limited to the most recent month.","type":"string"},"limit":{"description":"How many days to answer counting from start_date, at most 300. Without start_date the whole available month comes back.","type":"integer"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"listNews","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"listNews","description":"The latest crypto news, research and social posts, filterable by category, currency and time.","x-airnode-returns":{"code":"integer","message":"string","data":"object","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":[],"properties":{"category":{"description":"Only items of one category. SoSoValue category code: 1 news, 2 research, 3 institution, 4 insights and KOL posts, 7 official announcements, 13 crypto stock news. Items also arrive with codes SoSoValue does not document, such as 5.","type":"string"},"language":{"description":"Language to answer titles and bodies in, such as en, zh, tc (traditional Chinese), ja, vi, es, pt, ru, tr or fr. Defaults to en. SoSoValue's documentation lists the current set.","type":"string"},"currency_id":{"description":"Only items matched to one currency, by the currency_id that matched_currencies and getIndexConstituents answer.","type":"string"},"project_id":{"description":"Only items about one project, by SoSoValue's project id.","type":"string"},"page":{"description":"Page number, from 1. Defaults to 1.","type":"integer"},"page_size":{"description":"Items per page, at most 100. Defaults to 20.","type":"integer"},"start_time":{"description":"Only items released at or after this time, as a millisecond Unix timestamp. SoSoValue accepts only the most recent 7 days and refuses an older value with a 400, which reaches a caller as a 502.","type":"integer"},"end_time":{"description":"Only items released at or before this time, as a millisecond Unix timestamp. Limited to the most recent 7 days like start_time.","type":"integer"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"listHotNews","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"listHotNews","description":"The crypto stories trending now, each a cluster SoSoValue drew from several reports.","x-airnode-returns":{"code":"integer","message":"string","data":"object","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":[],"properties":{"page":{"description":"Page number, from 1. Defaults to 1.","type":"integer"},"page_size":{"description":"Items per page, at most 100. Defaults to 20.","type":"integer"},"language":{"description":"Language to answer titles and bodies in, such as en, zh, tc (traditional Chinese), ja, vi, es, pt, ru, tr or fr. Defaults to en. SoSoValue's documentation lists the current set.","type":"string"},"start_time":{"description":"Only items released at or after this time, as a millisecond Unix timestamp. SoSoValue accepts only the most recent 7 days and refuses an older value with a 400, which reaches a caller as a 502.","type":"integer"},"end_time":{"description":"Only items released at or before this time, as a millisecond Unix timestamp. Limited to the most recent 7 days like start_time.","type":"integer"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"listPickedNews","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"listPickedNews","description":"SoSoValue's editorially picked crypto news and research.","x-airnode-returns":{"code":"integer","message":"string","data":"object","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["page","page_size"],"properties":{"page":{"description":"Page number, from 1.","type":"integer"},"page_size":{"description":"Items per page, from 20 to 100.","type":"integer"},"language":{"description":"Language to answer titles and bodies in, such as en, zh, tc (traditional Chinese), ja, vi, es, pt, ru, tr or fr. Defaults to en. SoSoValue's documentation lists the current set.","type":"string"},"category":{"description":"Only items of these categories, comma-separated. SoSoValue category code: 1 news, 2 research, 3 institution, 4 insights and KOL posts, 7 official announcements, 13 crypto stock news. Items also arrive with codes SoSoValue does not document, such as 5.","type":"string"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"searchNews","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"searchNews","description":"Crypto news, research and posts matching a keyword in the title, body or tags.","x-airnode-returns":{"code":"integer","message":"string","data":"object","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["keyword"],"properties":{"keyword":{"description":"What to search for, such as bitcoin ETF.","type":"string"},"page":{"description":"Page number, from 1. Defaults to 1.","type":"integer"},"page_size":{"description":"Items per page, at most 100. Defaults to 20.","type":"integer"},"category":{"description":"Only items of one category. SoSoValue category code: 1 news, 2 research, 3 institution, 4 insights and KOL posts, 7 official announcements, 13 crypto stock news. Items also arrive with codes SoSoValue does not document, such as 5.","type":"integer"},"language":{"description":"Language to answer titles and bodies in, such as en, zh, tc (traditional Chinese), ja, vi, es, pt, ru, tr or fr. Defaults to en. SoSoValue's documentation lists the current set.","type":"string"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"listIndices","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"listIndices","description":"The tickers of SoSoValue's crypto sector indices, such as ssiMAG7 or ssiDeFi.","x-airnode-returns":{"code":"integer","message":"string","data":"array","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":[],"properties":{}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"getIndexConstituents","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"getIndexConstituents","description":"The tokens a SoSoValue index holds and the weight of each.","x-airnode-returns":{"code":"integer","message":"string","data":"array","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["index_ticker"],"properties":{"index_ticker":{"description":"Index ticker as listIndices answers it, such as ssiMAG7. Case-insensitive.","type":"string"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"getIndexMarketSnapshot","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"getIndexMarketSnapshot","description":"A SoSoValue index's level now, with its 24-hour change and returns over a week to a year.","x-airnode-returns":{"code":"integer","message":"string","data":"object","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["index_ticker"],"properties":{"index_ticker":{"description":"Index ticker as listIndices answers it, such as ssiMAG7. Case-insensitive.","type":"string"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"listMacroEvents","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"listMacroEvents","description":"Upcoming US macroeconomic releases by date, such as CPI, PPI and payrolls.","x-airnode-returns":{"code":"integer","message":"string","data":"array","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":[],"properties":{}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"getMacroEventHistory","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"getMacroEventHistory","description":"A macroeconomic release's past values: actual, forecast and previous, newest first.","x-airnode-returns":{"code":"integer","message":"string","data":"array","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["event"],"properties":{"event":{"description":"Release name exactly as listMacroEvents answers it, such as CPI (YoY) or Nonfarm Payrolls.","type":"string"},"start_date":{"description":"First release date to answer, as yyyy-MM-dd, inclusive.","type":"string"},"end_date":{"description":"Last release date to answer, as yyyy-MM-dd, inclusive.","type":"string"},"limit":{"description":"How many releases to answer, at most 100. Defaults to 50.","type":"integer"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"listMacroRates","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"listMacroRates","description":"US money-market reference rates with their latest values, such as SOFR and ON RRP.","x-airnode-returns":{"code":"integer","message":"string","data":"array","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":[],"properties":{}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"getMacroRateHistory","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"getMacroRateHistory","description":"A US money-market rate's daily releases, newest first, each with the one before.","x-airnode-returns":{"code":"integer","message":"string","data":"array","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["code"],"properties":{"code":{"description":"Rate code as listMacroRates answers it, such as sofr or on-rrp.","type":"string"},"limit":{"description":"How many releases to answer, at most 1000. Defaults to 100.","type":"integer"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}},{"title":"getFomcProbabilities","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"getFomcProbabilities","description":"Market-implied probabilities of each Fed target rate range at the upcoming FOMC meetings.","x-airnode-returns":{"code":"integer","message":"string","data":"object","details":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":[],"properties":{}},"responseProjection":{"type":"object","additionalProperties":{"type":"string"},"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data then carries those names instead of the whole body, and the projection is part of the signed request identity. A pointer the response does not have is a 400."}}}]}}}},"responses":{"200":{"description":"The upstream response and the attestation over it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Attestation"}}}},"400":{"description":"The operation exists but the parameters or the projection are missing, unknown or malformed, or the projection names a path the response does not have."},"404":{"description":"No such operation."},"502":{"description":"The upstream API could not be reached or refused the request."}}}}},"components":{"schemas":{"Attestation":{"type":"object","required":["airnode","requestHash","timestamp","data","signature"],"properties":{"airnode":{"type":"string","description":"The address whose signature attests to this response."},"requestHash":{"type":"string","description":"Identifies the request this response answers."},"timestamp":{"type":"string","description":"Unix seconds at which the response was signed."},"data":{"description":"The upstream response body: the JSON value when it parses as JSON, the text as received otherwise. With a projection, an object keyed by the names it asked for."},"signature":{"type":"string","description":"The attestation itself."}}}}},"x-airnode":{"address":"0x1763D6F572cFFf8476e175Fd46766d5cA7A474a9","version":"0.1.4","attestation":{"scheme":"eip191-secp256k1","digest":"keccak256(abi.encodePacked(bytes32 requestHash, uint256 timestamp, bytes dataBytes))","dataBytes":"UTF-8 of data, or of its compact JSON when data is not a string","requestHash":"keccak256(utf8(JSON.stringify([operation, parameterEntriesSortedByName]))), where an object value is itself entries sorted by name, at any depth, and an array keeps its order. A request that carries a projection appends its entries, sorted the same way, as a third element","verify":"Recover the signer of the signature over the digest and check it equals the address above."},"passthrough":{"url":"https://airnode-sosovalue.fly.dev/api","routes":{"getEtfMarketSnapshot":{"method":"GET","path":"/etfs/{ticker}/market-snapshot","parameters":{"ticker":"path"}},"listEtfs":{"method":"GET","path":"/etfs","parameters":{"symbol":"query","country_code":"query"}},"getEtfSummaryHistory":{"method":"GET","path":"/etfs/summary-history","parameters":{"symbol":"query","country_code":"query","start_date":"query","end_date":"query","limit":"query"}},"getEtfHistory":{"method":"GET","path":"/etfs/{ticker}/history","parameters":{"ticker":"path","start_date":"query","end_date":"query","limit":"query"}},"listNews":{"method":"GET","path":"/news","parameters":{"category":"query","language":"query","currency_id":"query","project_id":"query","page":"query","page_size":"query","start_time":"query","end_time":"query"}},"listHotNews":{"method":"GET","path":"/news/hot","parameters":{"page":"query","page_size":"query","language":"query","start_time":"query","end_time":"query"}},"listPickedNews":{"method":"GET","path":"/news/pick","parameters":{"page":"query","page_size":"query","language":"query","category":"query"}},"searchNews":{"method":"GET","path":"/news/search","parameters":{"keyword":"query","page":"query","page_size":"query","category":"query","language":"query"}},"listIndices":{"method":"GET","path":"/indices","parameters":{}},"getIndexConstituents":{"method":"GET","path":"/indices/{index_ticker}/constituents","parameters":{"index_ticker":"path"}},"getIndexMarketSnapshot":{"method":"GET","path":"/indices/{index_ticker}/market-snapshot","parameters":{"index_ticker":"path"}},"listMacroEvents":{"method":"GET","path":"/macro/events","parameters":{}},"getMacroEventHistory":{"method":"GET","path":"/macro/events/{event}/history","parameters":{"event":"path","start_date":"query","end_date":"query","limit":"query"}},"listMacroRates":{"method":"GET","path":"/macro/rates","parameters":{}},"getMacroRateHistory":{"method":"GET","path":"/macro/rates/{code}/history","parameters":{"code":"path","limit":"query"}},"getFomcProbabilities":{"method":"GET","path":"/macro/fomc-probabilities","parameters":{}}},"parameters":{"x-airnode-sign":"false skips the signature: no attestation headers, and the body streamed through with no size cap.","x-airnode-project":"alias:pointer, once per field to keep, each pointer an RFC 6901 JSON Pointer into the upstream response. The body becomes an object of those aliases, the signature covers it, and a pointer the response does not have is a 400."},"flow":"Send the request the provider documents, method, path, query and body as they are, to url followed by the route's path. The body comes back as the upstream sent it, with the upstream's status, and on success the attestation is in the X-Airnode-Address, X-Airnode-Request-Hash, X-Airnode-Timestamp and X-Airnode-Signature headers, with the operation served in X-Airnode-Operation. Every query parameter starting with x-airnode- is this Airnode's own, listed under parameters, and never reaches the upstream.","requestHash":"keccak256(utf8(JSON.stringify([\"passthrough\", method, path, queryEntriesSortedByName, body]))), where method is upper case, path and query are what was sent after url with the Airnode's own parameters removed, and body is the request body as sent, or an empty string. A request that carries a projection appends its entries, sorted by name, as a sixth element","dataBytes":"UTF-8 of the response body exactly as received, or of the projected object as compact JSON"}}}