tickerbot-io ETF API

The ETF API from tickerbot-io — 2 operation(s) for etf.

Operations 2

GET /v2/etf/{ticker}/holdings Constituent holdings of an ETF, weight-ranked #
GET /v2/etf/{ticker}/sectors Sector allocation of an ETF, weight-ranked #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • 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.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/tickerbot-io:tickerbot-io-etf-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

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 Specification

tickerbot-io-etf-api-openapi.yml Raw ↑
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>`.'