tickerbot-io Universes API
Named ticker lists — customer-defined and system-managed (top_10, top_100).
Named ticker lists — customer-defined and system-managed (top_10, top_100).
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-universes-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 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>`.'