tickerbot-io Universes API

Named ticker lists — customer-defined and system-managed (top_10, top_100).

Operations 6

GET /v2/universes Get all universes: yours, the built-in system ones, or both #
POST /v2/universes Create a universe #
GET /v2/universes/system List system universes (top_10, top_100) #
GET /v2/universes/{id} Fetch a single universe #
PATCH /v2/universes/{id} Update a universe #
DELETE /v2/universes/{id} Delete a universe #

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-universes-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-universes-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Tickerbot Universes 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: Universes
  description: Named ticker lists — customer-defined and system-managed (top_10, top_100).
paths:
  /v2/universes:
    get:
      tags:
      - Universes
      summary: 'Get all universes: yours, the built-in system ones, or both'
      operationId: list_universes
      description: 'Every universe you can reference: your own named ticker lists and the built-in ones.


        Notes:

        - A universe is a named list of tickers you reference from `/v2/scan?universe=`, `/v2/signals/{signal}?universe=`, and `/v2/tickers?universe=`, or pass as `universe` in the body when subscribing on a resource.

        - Built-in and custom universes come from one list, filtered by `owner` — the same way the signal catalog unifies built-in and custom signals with `kind`. `owner=me` (the default) is your own, `owner=system` the built-ins (`top_10`, `top_100`), `owner=all` both. Every row carries `system: true|false` so you can tell them apart.

        - System universes are a small fixed set: returned in full on the first page, never repeated across your cursor pages.

        - Universe tickers are validated against the active tickers in our universe. Symbols we don''t track return `400 unknown_tickers` with a `disallowed` array. Every account gets the full ~23,383-ticker universe — no symbol restriction.'
      parameters:
      - name: owner
        in: query
        required: false
        description: 'Which universes to list: `me` (your own), `system` (built-ins), or `all` (both).'
        schema:
          type: string
          enum:
          - me
          - system
          - all
          default: me
      - name: limit
        in: query
        required: false
        description: Page size (applies to your own). Max 100.
        schema:
          type: integer
          default: 50
          example: 10
      - name: cursor
        in: query
        required: false
        description: Opaque cursor from the previous response.
        schema:
          type: string
      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).
                  count:
                    type:
                    - number
                    - 'null'
                    description: Rows in this page.
                  next_cursor:
                    description: Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.
                  universes:
                    type:
                    - array
                    - 'null'
                    description: 'The universes in scope. Every row carries `system: true|false`.'
        '400':
          description: Invalid owner value, malformed cursor, or a non-positive-integer limit.
        '401':
          description: Missing or invalid API key.
        '402':
          description: No active plan on the account (rare — new signups land on the Free plan automatically).
        '429':
          description: Rate limit exceeded for your plan.
    post:
      tags:
      - Universes
      summary: Create a universe
      operationId: create_universe
      description: 'Create a named ticker list owned by your account.


        Notes:

        - Body: `{ id?, name, description?, tickers }`. The `id` (slug) is the universe''s only handle — it is what you pass as `?universe=` on queries and `universe` on subscribes. `name` is a display label and never references the universe.

        - Pick a memorable `id`: omit it and a random slug (`u_…`) is generated, which you will be referencing forever.'
      parameters:
      - name: Idempotency-Key
        in: header
        required: false
        description: 'Optional unique string (≤255 chars). A retry carrying the same key within 24h replays the original response (`Idempotency-Replayed: true` header) instead of creating a duplicate; a concurrent duplicate gets `409 idempotency_in_flight`; reusing a key for a *different* request (another method or path) gets `422 idempotency_key_reused`. 5xx responses are not stored — those retries re-execute.'
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                tickers:
                  type: array
                  example: NVDA,AMD,AVGO
                  items:
                    type: string
                  description: Ticker symbols, up to 10,000. Validated against the active universe. `[]` is accepted — a shell universe you can fill later via PATCH.
                name:
                  type: string
                  example: My watchlist
                  description: Human-readable label, up to 80 characters. Display-only — never used to reference the universe.
                id:
                  type: string
                  example: my_watchlist
                  description: Optional slug — becomes the universe's permanent handle everywhere (`?universe=`, subscribe `universe`, CRUD path). Pattern `^[a-z][a-z0-9_]{0,62}$` — starts with a lowercase letter, then lowercase letters/digits/underscore, 63 chars max; the value is trimmed and lowercased before validation. `top_10` and `top_100` are reserved for system universes and rejected with 400. Must be unique within your account. Generated (`u_…`) if omitted.
                description:
                  type: string
                  example: Semis I follow
                  description: Free-form notes, up to 500 characters. Stored as `""` when omitted.
              required:
              - tickers
              - name
      responses:
        '201':
          description: Universe created. Returns the full universe doc.
          content:
            application/json:
              schema:
                type: object
                properties:
                  as_of:
                    type:
                    - string
                    - 'null'
                    description: Server time this response was assembled (ISO 8601).
                  id:
                    type:
                    - string
                    - 'null'
                    description: The slug — the universe's handle in `?universe=`.
                  name:
                    type:
                    - string
                    - 'null'
                    description: Display label.
                  description:
                    type:
                    - string
                    - 'null'
                    description: Free-form notes; `""` when unset.
                  tickers:
                    type:
                    - array
                    - 'null'
                    description: Members, after this call.
                  size:
                    type:
                    - number
                    - 'null'
                    description: Member count.
                  system:
                    type:
                    - boolean
                    - 'null'
                    description: '`false` — this is your universe.'
                  created_at:
                    type:
                    - number
                    - 'null'
                    description: Creation timestamp.
                  updated_at:
                    type:
                    - number
                    - 'null'
                    description: Last modification timestamp.
                  effective_at:
                    description: System universes only; absent on yours.
                  next_rebalance_at:
                    description: System universes only; absent on yours.
                  rebalance_method:
                    description: System universes only; absent on yours.
        '400':
          description: '`too_many_universes` — the account-level ceiling of 1,000 universes, a flat anti-abuse guard identical for every account.'
        '401':
          description: Missing or invalid API key.
        '402':
          description: No active plan on the account (rare — new signups land on the Free plan automatically).
        '409':
          description: '`slug_taken` when `id` collides with one of your existing universes; or `idempotency_in_flight` — a concurrent request with the same `Idempotency-Key` is still executing.'
        '422':
          description: '`idempotency_key_reused` — the `Idempotency-Key` was already used for a *different* request (another method or path). Use a fresh key per distinct request.'
        '429':
          description: Rate limit exceeded for your plan.
  /v2/universes/system:
    get:
      tags:
      - Universes
      summary: List system universes (top_10, top_100)
      operationId: list_system_universes
      description: 'The built-in ticker lists — read-only, rebalanced monthly.


        Notes:

        - Legacy alias: prefer `GET /v2/universes?owner=system`, which returns the same built-ins in the unified list.

        - Membership is rebalanced monthly by 30-day trailing dollar volume, and every account has them.

        - System universe rows always carry the full `tickers` array, whatever their size (elided in the example above).'
      responses:
        '200':
          description: List of system universes.
          content:
            application/json:
              schema:
                type: object
                properties:
                  as_of:
                    type:
                    - string
                    - 'null'
                    description: Server time this response was assembled (ISO 8601).
                  count:
                    type:
                    - number
                    - 'null'
                    description: Rows in this page.
                  next_cursor:
                    description: Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.
                  universes:
                    type:
                    - array
                    - 'null'
                    description: The built-in universes, each with its full `tickers` array.
        '401':
          description: Missing or invalid API key.
        '402':
          description: No active plan on the account (rare — new signups land on the Free plan automatically).
        '429':
          description: Rate limit exceeded for your plan.
  /v2/universes/{id}:
    get:
      tags:
      - Universes
      summary: Fetch a single universe
      operationId: get_universe
      description: 'Returns the universe doc. Use `top_10`/`top_100` to fetch a system universe; any other slug must be one your account owns.


        Notes:

        - A SYSTEM universe carries four fields your own do not: `effective_at` (when this membership took effect), `next_rebalance_at`, `rebalance_method`, and `system: true`. Built-ins are rebalanced monthly, so a scan scoped to `top_100` is scoped to that month''s members — pin membership by copying the list into a universe of your own.'
      parameters:
      - name: id
        in: path
        required: true
        description: Universe slug.
        schema:
          type: string
          example: top_100
      responses:
        '200':
          description: The universe doc.
          content:
            application/json:
              schema:
                type: object
                properties:
                  as_of:
                    type:
                    - string
                    - 'null'
                    description: Server time this response was assembled (ISO 8601).
                  id:
                    type:
                    - string
                    - 'null'
                    description: The slug — the universe's handle in `?universe=`.
                  name:
                    type:
                    - string
                    - 'null'
                    description: Display label.
                  description:
                    type:
                    - string
                    - 'null'
                    description: Free-form notes; `""` when unset.
                  tickers:
                    type:
                    - array
                    - 'null'
                    description: Members.
                  size:
                    type:
                    - number
                    - 'null'
                    description: Member count.
                  system:
                    type:
                    - boolean
                    - 'null'
                    description: '`true` for a built-in universe, `false` for one you created.'
                  effective_at:
                    type:
                    - number
                    - 'null'
                    description: 'System universes only: when this membership took effect.'
                  next_rebalance_at:
                    type:
                    - number
                    - 'null'
                    description: 'System universes only: when membership is next recomputed.'
                  created_at:
                    type:
                    - number
                    - 'null'
                    description: Creation timestamp.
                  updated_at:
                    type:
                    - number
                    - 'null'
                    description: Last modification timestamp.
                  rebalance_method:
                    type:
                    - string
                    - 'null'
                    description: 'System universes only: how membership is chosen.'
        '400':
          description: Malformed universe slug (must match `^[a-z][a-z0-9_]{0,62}$`).
        '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`.'
        '429':
          description: Rate limit exceeded for your plan.
    patch:
      tags:
      - Universes
      summary: Update a universe
      operationId: update_universe
      description: 'Update one of your universes: its name, description, or members.


        Notes:

        - To add or remove ticker subsets without replacing the full list, pass `{ add: [...], remove: [...] }` instead of `tickers`. The two forms do not combine — sending `tickers` alongside `add`/`remove` is a 400.

        - The body is strict: unknown keys are rejected with a 400 rather than ignored. Same caps as create — `name` 80 chars, `description` 500 chars, `tickers` 10,000 symbols.'
      parameters:
      - name: id
        in: path
        required: true
        description: Universe slug.
        schema:
          type: string
          example: my_watchlist
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                tickers:
                  type: array
                  example: NVDA,AMD,AVGO
                  items:
                    type: string
                  description: Replace the full ticker list (up to 10,000; validated against the active universe). Does not combine with `add`/`remove` (400).
                add:
                  type: array
                  example: MU
                  items:
                    type: string
                  description: Add these tickers (deduplicated).
                remove:
                  type: array
                  example: AVGO
                  items:
                    type: string
                  description: Remove these tickers.
                name:
                  type: string
                  example: My watchlist
                  description: New label. Non-empty, max 80 characters.
                description:
                  type: string
                  example: Semis I follow
                  description: New notes. Max 500 characters.
      responses:
        '200':
          description: Updated universe doc.
          content:
            application/json:
              schema:
                type: object
                properties:
                  as_of:
                    type:
                    - string
                    - 'null'
                    description: Server time this response was assembled (ISO 8601).
                  id:
                    type:
                    - string
                    - 'null'
                    description: The slug — the universe's handle in `?universe=`.
                  name:
                    type:
                    - string
                    - 'null'
                    description: Display label.
                  description:
                    type:
                    - string
                    - 'null'
                    description: Free-form notes; `""` when unset.
                  tickers:
                    type:
                    - array
                    - 'null'
                    description: Members, after this call.
                  size:
                    type:
                    - number
                    - 'null'
                    description: Member count.
                  system:
                    type:
                    - boolean
                    - 'null'
                    description: '`false` — this is your universe.'
                  created_at:
                    type:
                    - number
                    - 'null'
                    description: Creation timestamp.
                  updated_at:
                    type:
                    - number
                    - 'null'
                    description: Last modification timestamp.
                  effective_at:
                    description: System universes only; absent on yours.
                  next_rebalance_at:
                    description: System universes only; absent on yours.
                  rebalance_method:
                    description: System universes only; absent on yours.
        '400':
          description: Malformed universe slug; an unknown body key (strict — unknown fields are rejected, not ignored); a non-array `tickers`/add/remove field; `tickers` combined with add/remove; an over-cap name (80 chars) or description (500 chars); an oversized universe (10,000); or `unknown_tickers` (with a `disallowed` array) for symbols we don't track.
        '401':
          description: Missing or invalid API key.
        '402':
          description: No active plan on the account (rare — new signups land on the Free plan automatically).
        '403':
          description: Cannot edit a system universe.
        '404':
          description: '`not_found`.'
        '429':
          description: Rate limit exceeded for your plan.
    delete:
      tags:
      - Universes
      summary: Delete a universe
      operationId: delete_universe
      description: 'Permanently delete one of your universes.


        Notes:

        - System universes (`top_10`, `top_100`) cannot be deleted and return `403 system_universe_immutable`.

        - If webhooks still reference the universe the delete is refused with `409 universe_referenced`, listing them, unless you pass `?force=true`. A forced delete leaves those webhooks matching nothing — each eval records a `last_error` on the webhook — until they are re-pointed or deleted.'
      parameters:
      - name: id
        in: path
        required: true
        description: Universe slug.
        schema:
          type: string
          example: my_watchlist
      - name: force
        in: query
        required: false
        description: A universe still referenced by live webhooks refuses to delete with `409 universe_referenced`. Pass `force=true` to delete anyway — those webhooks will match nothing until re-pointed or deleted.
        schema:
          type: boolean
          default: false
          example: true
      responses:
        '204':
          description: Deleted.
        '400':
          description: Invalid universe slug format.
        '401':
          description: Missing or invalid API key.
        '402':
          description: No active plan on the account (rare — new signups land on the Free plan automatically).
        '403':
          description: '`system_universe_immutable` — system universes are read-only.'
        '404':
          description: '`not_found` — slug doesn''t match any of your universes.'
        '409':
          description: '`universe_referenced` — webhooks still reference this universe; re-point or delete them, or pass `?force=true`.'
        '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>`.'