tickerbot-io ETF API
The ETF API from tickerbot-io — 2 operation(s) for etf.
The ETF API from tickerbot-io — 2 operation(s) for etf.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/tickerbot-io:tickerbot-io-etf-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Tickerbot ETF API
version: 2.69.6
summary: The stock market API designed for agents.
description: 'Tickerbot is the stock market API designed for agents. We serve real-time and historical market data as one queryable table. You and your agents can ask it anything, without building anything custom. Every ticker is a row. Every data point is a column. 23,000+ tickers, covering US stocks and ETFs, FX, crypto, rates and metals. 452+ columns, covering raw data, calculations and conditions: price, volume, price action, technicals, fundamentals, events, profile, analyst ratings and news. Refreshed every minute, historized back to 2003. The table is the API: /v2/tickers/ returns one ticker''s whole row, /v2/signals/ returns every ticker that matches one column, /v2/scan returns every ticker that matches a SQL WHERE clause. Every read runs live or as of any date. The power is in the columns: every ticker gets the same columns, query any of them, in any combination. Ask any question: anything you want to know about the market is a query over the table. Build any trading tool: anything you want to build is a few queries in sequence. Get a free API key, or paste our setup prompt and your agent connects over MCP. Free plan: 10,000 calls a month, no card required.
All responses carry a top-level `as_of` ISO timestamp indicating data vintage. List and history responses use opaque cursor pagination — treat `next_cursor` as a black-box token and pass it back via `?cursor=` on the next request.'
contact:
name: Tickerbot Support
url: https://tickerbot.io/support
email: support@tickerbot.io
license:
name: Proprietary
url: https://tickerbot.io/terms
servers:
- url: https://api.tickerbot.io
description: Production
security:
- apiBearer: []
tags:
- name: ETF
paths:
/v2/etf/{ticker}/holdings:
get:
tags:
- ETF
summary: Constituent holdings of an ETF, weight-ranked
operationId: get_etf_holdings
description: 'Returns an ETF''s constituents and their weights, heaviest first.
Notes:
- `is_etf` reports whether the symbol is an ETF, from the instrument type on its ticker record. For a non-ETF it is false and `holdings` is empty; `is_etf: true` with `count: 0` means a real ETF whose holdings have not been ingested yet.
- The reverse lookup — "which ETFs hold NVDA" — is a `/v2/scan` filter on the `etf_holders` signal, not an endpoint.
- The sector breakdown of the same ETF is the sibling call, `GET /v2/etf/{ticker}/sectors`.
- Holdings data comes from a nightly post-close refresh of ETF profile data, so expect it to be up to a day behind.
- Path history: this was `/v2/tickers/{ticker}/holdings` until 2026-09-14. That spelling keeps serving forever as an alias — same handler, same response, no deprecation headers.'
parameters:
- name: ticker
in: path
required: true
description: ETF symbol. Case-insensitive.
schema:
type: string
example: SPY
- name: limit
in: query
required: false
description: 'Max holdings returned. Max 5000. When the cap cuts the list, the response sets `truncated: true` and `total` (the ETF''s full holding count) — raise `limit` to at least `total` to get the full set, possible whenever `total` is within the 5000 cap (an over-cap `limit` is clamped to 5000, not an error). No `truncated` in the response means the list is complete.'
schema:
type: integer
default: 500
example: 10
responses:
'200':
description: Success.
content:
application/json:
schema:
type: object
properties:
as_of:
type:
- string
- 'null'
description: Server time this response was assembled (ISO 8601).
ticker:
type:
- string
- 'null'
description: The ETF you asked for.
is_etf:
type:
- boolean
- 'null'
description: Whether the symbol is an ETF, from the instrument type on its ticker record.
count:
type:
- number
- 'null'
description: Holdings in this page.
total:
type:
- number
- 'null'
description: Total constituents held, before `limit`.
truncated:
type:
- boolean
- 'null'
description: '`true` when `limit` cut the list short.'
holdings:
type:
- array
- 'null'
description: Constituents, heaviest first, each with its weight.
'400':
description: Invalid ticker (malformed symbol).
'401':
description: Missing or invalid API key.
'402':
description: No active plan on the account (rare — new signups land on the Free plan automatically).
'404':
description: '`not_found` — the symbol is not in the tracked universe. A tracked non-ETF answers 200 with `is_etf: false` instead.'
'429':
description: Rate limit exceeded for your plan.
/v2/etf/{ticker}/sectors:
get:
tags:
- ETF
summary: Sector allocation of an ETF, weight-ranked
operationId: get_etf_sectors
description: 'Returns an ETF''s sector weights, heaviest first. Always complete, since sector breakdowns are small.
Notes:
- `is_etf` reports whether the symbol is an ETF, from the instrument type on its ticker record. For a non-ETF it is false and `sectors` is empty; `is_etf: true` with `count: 0` means a real ETF whose sector data has not been ingested yet.
- These sector NAMES are the vendor''s ETF-profile vocabulary (`INFORMATION TECHNOLOGY`, `CONSUMER DISCRETIONARY`, `MATERIALS`), NOT the values the `sector` signal carries on a ticker row (`Technology`, `Consumer Cyclical`, `Basic Materials`). The two taxonomies line up conceptually but not as strings, so passing a value from here into `?sector=` on All symbols — or into a `q=` filter — matches nothing and returns an empty result rather than an error.
- Sector data comes from a nightly post-close refresh of ETF profile data, so expect it to be up to a day behind.
- Path history: this was `/v2/tickers/{ticker}/sectors` until 2026-09-14. That spelling keeps serving forever as an alias — same handler, same response, no deprecation headers.'
parameters:
- name: ticker
in: path
required: true
description: ETF symbol. Case-insensitive.
schema:
type: string
example: SPY
responses:
'200':
description: Success.
content:
application/json:
schema:
type: object
properties:
as_of:
type:
- string
- 'null'
description: Server time this response was assembled (ISO 8601).
ticker:
type:
- string
- 'null'
description: The ETF you asked for.
is_etf:
type:
- boolean
- 'null'
description: Whether the symbol is an ETF, from the instrument type on its ticker record.
count:
type:
- number
- 'null'
description: Sectors returned.
sectors:
type:
- array
- 'null'
description: Sector weights, heaviest first, in the vendor's ETF-profile vocabulary.
'400':
description: Invalid ticker (malformed symbol).
'401':
description: Missing or invalid API key.
'402':
description: No active plan on the account (rare — new signups land on the Free plan automatically).
'404':
description: '`not_found` — the symbol is not in the tracked universe. A tracked non-ETF answers 200 with `is_etf: false` instead.'
'429':
description: Rate limit exceeded for your plan.
components:
securitySchemes:
apiBearer:
type: http
scheme: bearer
bearerFormat: API key (tb_live_… or tb_test_…)
description: 'API keys are minted in the dashboard. Send as `Authorization: Bearer <key>`.'