Public API · MCP Server · Watchlist

BullAlert API & MCP

Our top momentum picks, served as a REST endpoint and an MCP server. Ranked live by a proprietary algorithm, refreshed every minute. Build your own bot, spreadsheet, dashboard, or AI agent on the same data the BullAlert app runs on.

Endpoint

1

No sprawl. Just /watchlist.

Live

~60s

Recomputed each request by our proprietary algorithm; 60s server cache.

Top N

10–100

Caller picks; default 10.

Auth

1 key

One key powers your bot, sheet, and AI agent.

Quick start

Generate a key from your dashboard, then pick how you want to plug it in. MCP is the easiest path if you already use Claude, Cursor, or ChatGPT — no code required. REST is the path for custom bots, spreadsheets, and dashboards.

One config block turns the BullAlert watchlist into a native tool your AI agent can call. No glue code, no scraping, no prompt-engineering the JSON shape.

Claude Desktop / Claude Code

~/.config/claude/mcp.json · %APPDATA%\Claude\mcp.json
{
  "mcpServers": {
    "bullalert": {
      "type": "http",
      "url": "https://api.bullalert.ai/v1/mcp",
      "headers": { "x-ba-api-key": "ba_live_..." }
    }
  }
}

Cursor / Windsurf

Same JSON block, dropped into the IDE's MCP server settings. Restart the IDE and your agent can call list_watchlist natively.

ChatGPT (custom GPT)

Point a custom GPT's “Actions” at https://api.bullalert.ai/v1/mcp with the same header. Useful for non-developers who want a packaged bot inside ChatGPT.

Try it: “What's on the BullAlert watchlist right now?” · “Show me the top 25 after-hours picks.” · “Walk me through the #1 ticker.”

One endpoint, one header, JSON in — no SDK, no setup. Same payload the in-app dashboard hits.

curl

curl -H "x-ba-api-key: ba_live_..." \
  "https://api.bullalert.ai/v1/watchlist?session=current&limit=10"

Python

import requests

r = requests.get(
    "https://api.bullalert.ai/v1/watchlist",
    headers={"x-ba-api-key": "ba_live_..."},
    params={"session": "current", "limit": 10},
)
for row in r.json()["data"]["watchlist"]:
    print(row["rank"], row["ticker"], row["score"])

JavaScript / Node

const res = await fetch(
  "https://api.bullalert.ai/v1/watchlist?session=current&limit=10",
  { headers: { "x-ba-api-key": "ba_live_..." } },
);
const { data } = await res.json();
console.table(data.watchlist);

Authentication

Every request requires an x-ba-api-key header. Generate one from your dashboard in a single click — no support ticket in the loop.

1. Create

Generate a key in one click from your dashboard. Copy it right away — we hash it on our side, so the full key is shown once and never again.

2. Use

Send x-ba-api-key on every request. Header only — never query-param in prod.

3. Manage

Everything lives in your dashboard — your active key, usage, and the controls to roll it if you ever need to. Changes take effect within 60s.

The endpoint

GEThttps://api.bullalert.ai/v1/watchlist

Query parameters

Param Default Description
session current pre_market | market | after_hours | all | current (auto-resolves to the active ET session).
limit 10 Integer 1–100. Same cap on every plan.
as_of UTC ISO8601 timestamp for historical replay (e.g. 2026-05-19T18:30:00Z). Returns the watchlist the way it looked at that moment. Earliest data: alerts back to 2026-02-19, full firehose back to 2026-04-20. Omit for live behavior.

// historical replay

Pass as_of to replay the watchlist at any past moment — same shape, same scoring, just bucketed by the timestamp's session window. Useful for backtests, post-mortem analysis, and reproducing what your agent saw at a given minute.

curl -H "x-ba-api-key: ba_live_..." \
  "https://api.bullalert.ai/v1/watchlist?as_of=2026-05-19T18:30:00Z&limit=25"

Response

{
  "data": {
    "watchlist": [
      { "rank": 1, "ticker": "WOLF", "score": 95 }
    ]
  },
  "meta": {
    "timestamp": "2026-05-20T18:05:32Z",
    "api_version": "v1",
    "algorithm_version": "v1.0.0",
    "session": "market",
    "count": 1,
    "data_freshness_seconds": 23,
    "rate_limit_remaining": 59,
    "rate_limit_reset": "2026-05-20T18:06:00Z"
  }
}

v1 row shape is intentionally minimal — rank + ticker + score only. Dynamic, session-aware, computed live on every request by our proprietary algorithm. We give you the ranked tickers and the score; for prices, % moves, charts, news, and anything else, plug in the market-data API of your choice.

Outside trading hours (weekends, holidays, overnight 8 PM – 4 AM ET) the response returns data.watchlist: [] plus meta.market_status: "closed" and a human-readable meta.message. Cached longer in that state.

Field reference

rank
1-based ranking. Rank 1 is the strongest pick in the response.
ticker
US small-cap symbol (sub-$20 universe). Every ticker returned has cleared the full BullAlert pipeline — 20 hard gates plus a live momentum check by our proprietary algorithm. One row per ticker per response (deduped across internal lists).
score
Composite on a normalized 0–100 scale, produced by our proprietary algorithm. Sort order matches `rank` exactly. v1 surface is intentionally minimal — for prices, % moves, news, and charts, plug in the market-data API of your choice.
meta.timestamp
UTC ISO8601 timestamp the response was computed.
meta.algorithm_version
Version of the underlying algorithm. Bumps when we ship improvements.
meta.session
Resolved session — what "current" turned into, or what you asked for. Can also be "closed" when the market is shut.
meta.count
Number of rows actually returned (≤ limit).
meta.data_freshness_seconds
Age in seconds of the freshest market data used by the momentum eval. Live calls typically 30–90s; null when market is closed.
meta.rate_limit_remaining
Calls left in your current per-minute window (mirrors the X-RateLimit-Remaining header). Per-day and per-month budgets are reported on the X-RateLimit-Daily-* and X-RateLimit-Monthly-* response headers.
meta.rate_limit_reset
UTC ISO8601 timestamp at which the per-minute window resets. Mirrors X-RateLimit-Reset. After this point, your per-minute budget refills.
meta.market_status (optional)
Present only when the market is closed. Value: "closed".
meta.message (optional)
Human-readable explanation, present only on market-closed responses.

Caching & freshness

Responses are recomputed by our proprietary algorithm and cached server-side for 60 seconds. Polling faster than once a minute returns the cached payload; once a minute is the sweet spot for live use.

Rate limits

Every paid plan includes API access. Headers x-ratelimit-limit, x-ratelimit-remaining, and x-ratelimit-reset ship on every response.

Plan Per minute Per day Per month
Weekly / Monthly 30 5K 50K
Yearly 60 20K 500K
B2B / Custom 300+ 100K+ 2M+

Need higher? Talk to us — we build custom plans for partners and trading platforms.

Security & privacy

Every external request flows through the same controls we use ourselves.

  • Header-only authentication. Keys travel in the x-ba-api-key header — never as a query parameter, never in URLs. Server-side only, never embed in client code.
  • One active key per account. Manage everything from your dashboard. Changes take effect within ~60s.
  • Read-only. No public endpoint mutates BullAlert state. Your key can't affect other members or the underlying data.
  • Minimal surface. The response is exactly the fields documented above — nothing else.
  • TLS + HSTS in production. Plain HTTP is upgraded; certificates rotated automatically.

Build your own agent on the BullAlert watchlist

The same primitive that powers our in-app chatbot is public. Wire it into your own trading bot, spreadsheet, agent, or dashboard. No exclusivity, no rev-share — one API key per account, included with every paid plan.

Three persona starters

Same one-tool API, three different personas. Click through for the full sample prompt for each.

BullAlert is a data and information tool. The API delivers data, not financial advice. Past performance is not indicative of future results. Trading involves risk. You make the final decisions.