Signal API · v2026-09

Connect Your Own Software or AI

Every alert you are entitled to, delivered to your own endpoint the moment it ships, signed so you can prove it came from us, and available again from a REST API with its graded outcome. The same shape carries the fields a bot needs to decide whether to act at all. Included with Pro. Create a key and add an endpoint in Dashboard › Settings › API.

What we do not do: place orders, hold a brokerage login, or take your holdings as an input. The feed is the same impersonal broadcast every entitled subscriber receives. Your system decides what, if anything, to do with it.

Authentication

One key per account. Send it as a bearer token. Sharing a key ends access.

curl https://insiderwatch.ai/api/v1/me \
  -H "Authorization: Bearer iw_live_..."

Webhook

We POST one JSON event per alert to the HTTPS URL you save. Reply with any 2xx within 5 seconds. If we cannot, we retry 3 more times over about 8 minutes, then drop that event and count a failure. After 10 consecutive failures the endpoint is paused and you get an email; saving the URL again resumes it. Delivery is at-least-once, so dedupe on the id.

Every request carries three headers in the Standard Webhooks format: webhook-id, webhook-timestamp (Unix seconds) and webhook-signature. Verify it with your signing secret before trusting the body:

// Node.js
import { createHmac, timingSafeEqual } from 'crypto'

function verify(secret, headers, rawBody) {
  const id = headers['webhook-id']
  const ts = headers['webhook-timestamp']
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false   // replay window
  const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64')
  const expected = createHmac('sha256', key).update(`${id}.${ts}.${rawBody}`).digest('base64')
  const given = (headers['webhook-signature'] || '').split(' ')
    .map(s => s.split(',')[1]).filter(Boolean)
  return given.some(sig => sig.length === expected.length &&
    timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))
}

The event

This is a test event, with the shape a real one has. The alert is invented; the fields are not.

{
  "type": "signal.created",
  "version": "2026-09",
  "id": "sig_mtso0nhc_e530f8d9",
  "publishedAt": "2026-09-08T12:48:12.000Z",
  "staleAfter": "2026-09-08T13:18:12.000Z",
  "title": "TEST: Test Corp CEO buys $1.2M of stock on the open market",
  "summary": "This is a test event from InsiderWatch. The shape is real; the alert is not.",
  "link": "https://insiderwatch.ai/docs/api",
  "source": "SEC EDGAR Form 4",
  "category": "sec_insider",
  "ticker": "TEST",
  "tickers": [
    "TEST"
  ],
  "companies": [
    "Test Corp"
  ],
  "sectors": [],
  "direction": "BULLISH",
  "impact": "LIKELY",
  "confidence": "HIGH",
  "eventType": "insider_buy",
  "eventStatus": "decided",
  "callStrength": "call",
  "informational": false,
  "score": 54,
  "scoreBand": "Lean",
  "plan": {
    "refPrice": 12.34,
    "targetPct": 6.1,
    "stopPct": 6.1,
    "windowDays": 21,
    "basis": "next_close"
  },
  "liquidity": {
    "advUsd": 4100000,
    "marketCap": 310000000,
    "preMovePct": -1.2,
    "preMove5dPct": 3.4,
    "rvol": 1.8,
    "spyTrend": "up",
    "spy5dPct": 0.6
  },
  "classRecord": null,
  "market": {
    "session": "pre",
    "etTime": "Tue 08:48 ET"
  },
  "outcome": null,
  "disclaimer": "Impersonal information published to every InsiderWatch subscriber entitled to it. Not a recommendation, not personalised to any account, not investment advice. Your system decides what, if anything, to do with it. Past results do not predict future results."
}
FieldMeaning
idStable id (sig_…). Also the webhook-id header. Dedupe on it.
publishedAt / staleAfterWhen we sent it, and 30 minutes later. Treat an event you see after staleAfter as history, not a live signal.
directionBULLISH, BEARISH or NEUTRAL. NEUTRAL is context: a real event we will not put a direction on.
callStrength'call' or 'lean'. A lean is a hedged read. Do not act on leans.
eventStatus'decided' means it happened. 'proposed' and 'reported' mean it has not, or is secondhand.
score / scoreBandThe 0-100 signal score subscribers see: a fixed points model over factors the record measured, never the analyst’s own tier.
planThe exact target and stop the public track record grades this call against, both one volatility band from refPrice, and the window in trading days. basis says whether grading starts from the send price or the next close.
liquidityAverage daily dollar volume, market cap, how far the stock had already moved on the day and over five sessions, relative volume, and the broad-market regime at send time.
classRecordHow alerts of this class have graded on the public record, current rules, misses included. null until the class has 20 graded calls.
marketWhich session it was in New York time when we sent it: pre, regular, post or closed.
outcomeThe graded result once the call resolves (REST only; a webhook fires at creation).
disclaimerTravels with every payload so it survives into whatever your agent renders.

REST

The same events on demand, newest first, for roughly the last two weeks. Older alerts resolve by id. Filters mirror your dashboard: plan scope, source toggles, sectors, watchlist and the context-alerts setting.

GET /api/v1/signals?limit=50&since=2026-09-01T00:00:00Z
GET /api/v1/signals?after=sig_...          # everything newer than an id
GET /api/v1/signals?direction=BULLISH&ticker=NVDA,AMD&eventType=insider_buy
GET /api/v1/signals/{id}                    # one signal, with its outcome once graded
GET /api/v1/performance                     # the published hit rate + per-class record
GET /api/v1/me                              # is my key working, what does it see

The filings behind the signals

The same key also reads the public filings the pipeline captures, as rows with a link to the source document. These carry no direction, grade or score: they are what was filed, for your own model or your own eyes. Newest first, up to 200 rows a call, and every list takes ticker= (one symbol or a comma list), since= and limit=.

GET /api/v1/insiders/trades?type=buy&minUsd=250000   # Form 4 open-market rows, 180 days
GET /api/v1/congress/trades?member=nancy-pelosi     # STOCK Act rows with the disclosure lag
GET /api/v1/congress/members?chamber=senate         # every member with trades, by volume
GET /api/v1/congress/members/{slug}                 # one member: totals, top tickers, recent rows
GET /api/v1/activist-stakes?form=13d&minPct=5       # Schedule 13D/G stakes as filed
GET /api/v1/funds                                   # the notable managers we track
GET /api/v1/funds/{cik}                             # one 13F book, largest first, share of book
GET /api/v1/catalysts?kind=pdufa                    # pending binary events per verified ticker
GET /api/v1/watchlist                               # all of the above for your own My stocks

Not here, on purpose: quotes, price history and headlines. Those feeds are licensed to us for our own analysis and are not ours to pass on; your broker or data vendor is the right source.

Limits: 600 requests an hour and 60 in any minute, per key, across everything above. A conversational agent uses a handful an hour; a backfill of every list still fits inside a minute. Errors come back as { "error": { "code", "message" } } with 400, 401, 403, 404, 429 or 503. Filing lists send a Cache-Control: private header so your client can reuse a response for a minute or five instead of asking again.

Connect an AI assistant (MCP)

The same feed as a remote MCP server, so your own Claude or agent can ask for your signals in conversation instead of polling. It is read-only: 13 tools, and none of them places an order, holds a broker login, or takes your holdings as an input. Same key, same limits, same entitlement as the REST API. The server is at:

https://insiderwatch.ai/api/mcp

Claude Code, one command, then ask about your signals:

claude mcp add --transport http insiderwatch https://insiderwatch.ai/api/mcp \
  --header "Authorization: Bearer iw_live_..."

ChatGPT, Claude.ai and any client that wants a sign-in instead of a key: add the server URL as a connector, and when it sends you to InsiderWatch, sign in and approve. That is a standard OAuth 2.1 flow (discovery at /.well-known/oauth-authorization-server, dynamic client registration, PKCE, rotating refresh tokens). The app then shows under Connected apps in your dashboard, where one click revokes it. Claude Desktop and other clients that reach remote servers through mcp-remote can use either the sign-in or the key header.

ToolWhat it returns
list_signalsYour own alert stream, newest first, in the same shape the webhook delivers: direction, plan, liquidity, class record, graded outcome once resolved, and the disclaimer. Covers roughly the last two weeks; older signals resolve by id with get_signal.
get_signalOne signal by id, with its graded outcome once the call has resolved. Ids from months ago still resolve.
get_class_performanceThe one published hit rate (current rules, full graded record, misses included) and the per-class receipts on the same basis. Classes with too few graded calls list null rates rather than being omitted.
get_liquidity_contextThe tape at the moment a signal was sent: dollar volume, market cap, how far the stock had already moved, relative volume, market regime, session, and the flags a bot should honour before acting. Facts only; sizing is yours.
explain_planThe exact target, stop, window and price basis the public track record grades a signal against, in plain words, with how its class has graded so far.
list_insider_tradesOpen-market insider buys and sells from SEC Form 4 filings over the last 180 days: insider, role, dollar value, shares, share of holdings sold, and a link to the filing. Filter by ticker, side, size or insider name. Facts only, no direction.
list_congress_tradesStock trades disclosed by members of Congress, newest filing first: member, chamber, ticker, side, disclosed range, trade and filing dates, and the disclosure lag in days. Filter by ticker, member, chamber, side or size.
list_politiciansEvery member with captured trades, ranked by disclosed volume: trade counts, buys and sells, distinct tickers, last filing and median disclosure lag. Slugs feed get_politician and the member filter of list_congress_trades.
get_politicianA member’s profile from their disclosed trades: totals, most-traded tickers, recent rows with disclosure lag, and the public page. Not found when we hold no trades for the name.
list_activist_stakesSchedule 13D and 13G stakes of 5% or more as filed, newest first: filer, issuer, percent of the class, shares, form type and a link to the filing. Filter by ticker, form or size.
get_fund_holdingsThe latest 13F book of a tracked manager (Berkshire, Pershing Square, Scion, Saudi PIF and others), largest position first with share of book and the resolved ticker; or, without a CIK, the list of tracked managers with their latest filing. A 13F has no cost basis and no shorts.
list_catalystsKnown pending binary events per verified ticker, soonest first: FDA action dates, advisory panels, guided readout windows, merger votes, as stated in the filings and releases the pipeline read. Dates are copied, never inferred.
get_watchlist_activityOne call for the subscriber’s own watchlist (or any tickers given): signals from the last two weeks, insider trades from 30 days, Congress trades and activist stakes from 90 days, and pending catalysts. The “what happened on my stocks” tool.

Every result carries the disclaimer, and the server tells the assistant up front which flags mean do not act: a lean, a proposed or reported event, an informational record, a stale signal.

What your system should do before it acts

The published hit rate is graded close to close, from the price when we sent the alert. A bot pays a spread and, for alerts sent before the open, the gap. That cost comes straight off the rate. At minimum, your rules should:

  • Skip anything with callStrength: "lean", a non-decided eventStatus, or informational: true.
  • Skip when liquidity.advUsd is small next to your order, and use limit orders inside the plan band.
  • Respect staleAfter, and dedupe on id.
  • Size off plan.stopPct, not conviction, and cap how many alerts from one event you hold at once.
  • Treat a null classRecord as unknown, not as good.

Terms in one paragraph

Personal, non-commercial research use on your own account. No redistribution, resale or republishing of the feed or the filings data, raw or repackaged; no use of it to build, train or run a competing product, model or dataset; no presenting our alerts or record as your own or as a recommendation; no working around the rate limits. One key and one endpoint per subscriber, plus any apps you connect, all revocable by you. The API never widens what your plan already covers, may change with notice here, and its rows are our capture of public filings, with the filing itself as the authoritative record. Everything in it is information, not investment advice, and what your software or a connected app does with it is yours; see the Terms and how calls are graded.

Ready to connect your own system?

Pro includes the API and webhooks. Create a key in the dashboard and your first event arrives with the next alert.

See plans

Not a recommendation service. Your system decides.