CanaryWhistle API
A clean JSON feed of every US WARN Act layoff and closure filing, enriched with role families, comp and payroll estimates. Query the live feed, the forward calendar, the trend index and any company's history. Built for investors, sales-intelligence, credit-risk and commercial-real-estate teams. Get a key on the Data / API plan.
Base URL & auth
All endpoints live under https://canarywhistle.com/api/v1. Authenticate with your key as a Bearer token on every request.
curl https://canarywhistle.com/api/v1/filings?state=CA&min=250 \ -H "Authorization: Bearer cw_live_your_key_here"
Paste this and you get real records back. cw_demo_public is public and answers the archive: ten filings a page, nothing newer than 30 days, no forward calendar, no change feed, no webhooks. The archive is already free under CC BY 4.0 on our data page, so there is nothing to sign up for first.
curl "https://canarywhistle.com/api/v1/filings?state=CA&min=250" \ -H "Authorization: Bearer cw_demo_public"
Endpoints
Paginated, filterable list of WARN filings (newest first). Each record includes role families, median comp and est. payroll released.
- state — 2-letter state, e.g. CA
- metro — metro slug, e.g. bay-area, dallas, nyc
- industry — industry slug, e.g. technology
- role — role family, e.g. Engineering
- min — minimum headcount, e.g. 100
- type — Layoff or Closure
- q — free text: company or city
- since_days — only filings logged in the last N days
- page / limit — pagination (limit max 200)
Forward calendar: jobs scheduled to be cut, from filed effective dates. Same filters, plus days (horizon, max 365).
Monthly filing volume and 90-day industry/state momentum (the CanaryWhistle Index).
Every filing on record for one employer, with totals and affected states.
Check your own list of companies (suppliers, holdings, accounts) in one call: for each name, every filing on record across every state, the jobs filed but not yet gone, the next effective date and other distress signals. Name variants resolve to one employer. Params: names, separated by | or commas, up to 200. POST {"names": [...]} works too. Nothing you send is stored.
Everything that moved since you last looked: new filings and amendments to filings already on record, newest first. Params: since_days (default 7), state, type (new|amended).
As-filed history: what the state published when we first saw it, and every change the state has made since. Effective dates move, layoffs get reclassified as closures, cities are corrected. Most sources overwrite that silently; we keep it.
Register an endpoint to be pushed new filings and amendments as we record them, instead of polling. Body: url (https), events (filing.new, filing.amended), states, min_employees, label. The signing secret is returned once.
Your endpoints, with the cursor each one is delivering from, its consecutive failure count and whether it has auto-disabled.
Send a signed webhook.test event now, so you can prove the integration before the first real filing arrives. Never counts as a failure and never moves the cursor.
Re-enable an endpoint that auto-disabled. Delivery resumes from the cursor, so nothing queued is skipped.
Every attempt we have made to that endpoint: status, duration, error, and with include_payload=1 the exact bytes we signed. Params: limit (max 200), only=failed.
Remove the endpoint and its delivery log.
Verifying a webhook
Each delivery carries x-canary-event, x-canary-delivery, x-canary-timestamp and x-canary-signature. The signature is an HMAC-SHA256 over timestamp + "." + raw body, keyed with your secret. Sign the raw body, not a re-serialised object, and reject a timestamp more than five minutes old so a captured payload cannot be replayed at you later.
const crypto = require("crypto");
function verify(req, secret) {
const ts = req.headers["x-canary-timestamp"];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // too old, treat as replay
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(ts + "." + req.rawBody) // the RAW body, exactly as received
.digest("hex");
const got = Buffer.from(req.headers["x-canary-signature"] || "");
const want = Buffer.from(expected);
// Length first: timingSafeEqual THROWS on a length mismatch, so a missing or
// malformed header would crash your handler instead of being rejected.
return want.length === got.length && crypto.timingSafeEqual(want, got);
}Answer 2xx and we consider it delivered. Anything else is retried three times with backoff, and after fifteen consecutive failed deliveries the endpoint auto-disables so we stop knocking. Nothing is lost when that happens: the cursor only advances past a delivery you accepted, so re-enabling resumes exactly where it stopped. Expect at-least-once delivery, and key on the filing id plus observed_at if a repeat would matter to you.
If you act on a filing, you eventually need to answer what the record said on the day you acted. Every filing here carries its own history and observed_at is when we saw a change, not when the state made it. Records collected before 8 October 2026 open with a history_began entry: that is the record as it stood when we started keeping history, not a reconstruction of the original filing. Where a state publishes one row per separation date, the filing keeps the earliest date and the other dates appear in the history rather than overwriting each other.
Example response
{
"object": "list",
"data": [
{
"id": "cmq...",
"company": "Meta Platforms, Inc.",
"city": "Menlo Park",
"state": "CA",
"employees": 2212,
"industry": "Technology",
"roles": ["Engineering", "Sales", "Marketing"],
"median_comp_usd": 122000,
"payroll_released_usd": 269864000,
"type": "Layoff",
"notice_date": "2026-05-22T00:00:00.000Z",
"effective_date": "2026-07-22T00:00:00.000Z",
"source_url": "https://edd.ca.gov/...",
"url": "https://canarywhistle.com/drop/cmq..."
}
],
"page": 1, "limit": 50, "total": 38, "has_more": false
}Data sourced from public state WARN Act registries. Fair-use limits apply. Need higher volume or a bulk feed? Reply to your receipt email.
Questions buyers ask
Is there an API for WARN notices?
Yes. CanaryWhistle serves 39,281 WARN filings back to 2005 as JSON over a documented REST API, with endpoints for filings, companies, the forward calendar, amendments and trends, plus signed webhooks for push delivery. There is a public demo key that needs no signup. The whole historical archive is also downloadable free under CC BY.