Spaces:
Running
Running
| <html lang="en"><head><meta charset="utf-8"> | |
| <!-- og:begin --> | |
| <meta property="og:title" content="Free WARN Act layoff notices API — JSON and CSV, no key, 48 states, updated daily"> | |
| <meta property="og:description" content="A free HTTP API for US WARN Act layoff notices: 61,431 notices from 48 state agencies as JSON or CSV, CORS-enabled, no signup, rebuilt every morning. curl/python/duckdb examples, 11-field schema, CC BY 4.0."> | |
| <meta property="og:url" content="https://approjects-warn-act-notices.static.hf.space/api.html"> | |
| <meta property="og:image" content="https://approjects-warn-act-notices.static.hf.space/assets/og-card.png"> | |
| <meta name="twitter:card" content="summary_large_image"> | |
| <!-- og:end --> | |
| <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://cdn.jsdelivr.net; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self' https://app.gumroad.com; upgrade-insecure-requests"> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>Free WARN Act layoff notices API — JSON and CSV, no key, 48 states, updated daily</title> | |
| <meta name="description" content="A free HTTP API for US WARN Act layoff notices: 61,431 notices from 48 state agencies as JSON or CSV, CORS-enabled, no signup, rebuilt every morning. curl/python/duckdb examples, 11-field schema, CC BY 4.0."> | |
| <link rel="canonical" href="https://approjects-warn-act-notices.static.hf.space/api.html"> | |
| <script type="application/ld+json">{"@context":"https://schema.org","@type":"Dataset","name":"US WARN Act layoff notices \u2014 free JSON/CSV API","description":"A free HTTP API for US WARN Act layoff notices: 61,431 notices from 48 state agencies as JSON or CSV, CORS-enabled, no signup, rebuilt every morning. curl/python/duckdb examples, 11-field schema, CC BY 4.0.","url":"https://approjects-warn-act-notices.static.hf.space/api.html","license":"https://creativecommons.org/licenses/by/4.0/","isAccessibleForFree":true,"dateModified":"2026-09-25","distribution":[{"@type":"DataDownload","encodingFormat":"application/json","contentUrl":"https://approjects-warn-act-notices.static.hf.space/data/warn_notices.json"},{"@type":"DataDownload","encodingFormat":"text/csv","contentUrl":"https://approjects-warn-act-notices.static.hf.space/data/latest.csv"}],"creator":{"@type":"Organization","name":"WARN Feed"}}</script> | |
| <style>body{font:16px/1.5 -apple-system,system-ui,sans-serif;max-width:880px;margin:2rem auto;padding:0 1rem;color:#1a1a1a} | |
| h1{font-size:1.5rem} .stats{display:flex;gap:2rem;flex-wrap:wrap;margin:1.5rem 0} | |
| .stat b{display:block;font-size:1.8rem} table{border-collapse:collapse;width:100%;font-size:.9rem} | |
| td,th{padding:.35rem .6rem;border-bottom:1px solid #e5e5e5;text-align:left} .r{text-align:right} | |
| a{color:#0757ba} .cta{background:#f6f8fa;border:1px solid #d0d7de;border-radius:8px;padding:1rem;margin:1.5rem 0} | |
| nav{font-size:.9rem;margin:1rem 0} footer{margin:2rem 0;font-size:.85rem;color:#666}.cta .ctap{margin:.45rem 0 .9rem}.btn{display:inline-block;background:#b02a1f;color:#fff;text-decoration:none;font-weight:600;padding:12px 20px;min-height:44px;line-height:20px;border-radius:6px;box-sizing:border-box}.btn:hover{background:#8e2118}.btn.ghost{background:#fff;color:#b02a1f;border:1px solid #b02a1f;margin-left:8px}.btn.ghost:hover{background:#fdf3f2}.btnnote{display:block;font-size:.85rem;color:#555;margin-top:.6rem}@media (max-width:520px){.btn{display:block;text-align:center}body{margin:1rem auto}table{font-size:.85rem}} | |
| .dv{ | |
| --dv-ink:#1a1a19; --dv-dim:#5b5b57; --dv-grid:#e6e6e3; | |
| --dv-surface:#fcfcfb; --dv-accent:#1c5cab; | |
| --dv-line:#2a78d6; --dv-area:#cde2fb; | |
| font:14px/1.4 -apple-system,system-ui,"Segoe UI",Roboto,sans-serif; | |
| color:var(--dv-ink); | |
| } | |
| @media (prefers-color-scheme:dark){ | |
| .dv{--dv-ink:#f2f2f0; --dv-dim:#a9a9a4; --dv-grid:#333330; | |
| --dv-surface:#1a1a19; --dv-accent:#6da7ec; | |
| /* dark takes its OWN steps from the same ramp, not a flipped light one */ | |
| --dv-line:#3987e5; --dv-area:#104281} | |
| } | |
| .dv figure{margin:0 0 28px} | |
| .dv figcaption{margin-top:8px;font-size:12px;color:var(--dv-dim)} | |
| .dv-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:18px} | |
| .dv-kpi{ | |
| padding:16px 18px;border:1px solid var(--dv-grid);border-radius:12px; | |
| background:var(--dv-surface);color:var(--dv-ink); | |
| } | |
| .dv-kpi b{display:block;font-size:clamp(1.9rem,5vw,2.9rem);font-weight:800; | |
| letter-spacing:-.03em;line-height:1;font-variant-numeric:tabular-nums; | |
| color:var(--dv-ink)} | |
| .dv-kpi span{display:block;margin-top:7px;font-size:12.5px;color:var(--dv-dim)} | |
| .dv-kpi i{font-style:normal;font-size:12px;font-weight:700;color:var(--dv-accent)} | |
| .dv-svg{display:block;max-width:100%;height:auto;color:var(--dv-ink)} | |
| .dv table{border-collapse:collapse;font-size:13px;color:var(--dv-ink)} | |
| .dv th,.dv td{padding:5px 12px 5px 0;text-align:left; | |
| border-bottom:1px solid var(--dv-grid)} | |
| .ms-kpis{display:flex;gap:1rem;flex-wrap:wrap;margin:1.25rem 0} | |
| .btn{display:inline-block;background:#0757ba;color:#fff;padding:.7rem 1.15rem; | |
| border-radius:8px;text-decoration:none;font-weight:600;min-height:44px; | |
| line-height:1.6;box-sizing:border-box} | |
| .btn.ghost{background:#fff;color:#0757ba;border:1px solid #0757ba} | |
| .cta-row{margin:1.5rem 0;display:flex;gap:.75rem;flex-wrap:wrap} | |
| #msq{width:100%;max-width:420px;padding:.6rem .7rem;font-size:1rem; | |
| border:1px solid #d0d7de;border-radius:8px;min-height:44px;box-sizing:border-box} | |
| .tw{overflow-x:auto} | |
| .st{color:#555;font-size:.85rem} | |
| figure{margin:1.5rem 0}figcaption{font-size:.8rem;color:#666;margin-top:.4rem} | |
| .hit{background:#fff8e1} | |
| @media (max-width:600px){ | |
| body{margin:1rem auto;font-size:15px} | |
| h1{font-size:1.3rem} | |
| .ms-kpis{gap:.5rem} | |
| table{font-size:.82rem} | |
| .btn{display:block;text-align:center} | |
| } | |
| pre{background:#0f172a;color:#e7edf7;padding:14px 16px;border-radius:8px;overflow-x:auto;font-size:13px;line-height:1.5} | |
| pre code{background:none;color:inherit;padding:0} | |
| td.num{text-align:right;white-space:nowrap} | |
| .states{font-size:14px;line-height:2.1}</style></head><body> | |
| <nav><a href="industries.html">layoffs by industry</a> · <a href="index.html">Live stats</a> · | |
| <a href="sheets.html">Google Sheets</a> · <a href="search.html">Search</a> · | |
| <a href="coverage.html">Coverage</a> · <a href="counties.html">Counties</a> · | |
| <a href="https://github.com/APVentureEngine/warn-act-notices">Dataset on GitHub</a></nav> | |
| <h1>A free WARN Act API: 61,431 layoff notices, 48 states, one GET request</h1> | |
| <p>Every US state has to publish the mass-layoff notices employers file under the WARN Act, | |
| and every state publishes them differently — a portal here, a spreadsheet there, a PDF | |
| somewhere else. We scrape all 48 of them every morning, normalize them into one | |
| 11-field schema, resolve the employer names, and serve the result as plain JSON and CSV over | |
| HTTPS. <b>No key, no signup, no rate limit, CORS open.</b> If you have ever wanted to put real | |
| layoff data in something you are building, this is one <code>curl</code> away.</p> | |
| <div class="dv-kpis"><div class="dv-kpi"><b>61,431</b><span>notices, one GET away</span><i style="color:#1c5cab">48 state agencies, back to 1988</i></div><div class="dv-kpi"><b>0</b><span>keys, tokens or signups</span><i style="color:#1c5cab">plain HTTPS, CORS open to any origin</i></div><div class="dv-kpi"><b>59</b><span>endpoints published</span><i style="color:#1c5cab">41.7 MB of JSON/CSV, rebuilt daily</i></div><div class="dv-kpi"><b>CC BY 4.0</b><span>licence</span><i style="color:#1c5cab">use it commercially, credit WARN Feed</i></div></div> | |
| <p class="cta-row"><a class="btn" href="data/latest.json">Try it now — GET /data/latest.json</a> | |
| <a class="btn ghost" href="datapackage.json">Read the 11-field schema</a></p> | |
| <h2 id="quickstart">Quickstart</h2> | |
| <pre><code># the whole archive as JSON (no key, no header) | |
| curl -sL https://approjects-warn-act-notices.static.hf.space/data/warn_notices.json | jq '.[0]' | |
| # just what is new — poll this one daily | |
| curl -sL https://approjects-warn-act-notices.static.hf.space/data/latest.json | jq '.count, .generated_at' | |
| # poll politely: send back the ETag you got last time — unchanged = 304, zero bytes | |
| curl -sL -o latest.json -D - -H 'If-None-Match: "<etag from last run>"' https://approjects-warn-act-notices.static.hf.space/data/latest.json | |
| # streaming: one notice per line, no 20 MB buffer | |
| curl -sL https://approjects-warn-act-notices.static.hf.space/data/warn_notices.ndjson | head -n 3 | jq -c '{company_canonical, state, notice_date}' | |
| # one state, as CSV | |
| curl -sL https://approjects-warn-act-notices.static.hf.space/data/by-state/ca.csv | head -3</code></pre> | |
| <pre><code># python: the recent window straight into pandas | |
| import pandas as pd | |
| df = pd.read_csv("https://approjects-warn-act-notices.static.hf.space/data/latest.csv") | |
| print(len(df), df.columns.tolist())</code></pre> | |
| <pre><code># duckdb: query the archive in place, no download step | |
| SELECT state, count(*) AS notices | |
| FROM read_csv_auto('https://approjects-warn-act-notices.static.hf.space/data/latest.csv') | |
| GROUP BY 1 ORDER BY 2 DESC;</code></pre> | |
| <pre><code>// browser javascript: CORS is open, so this works from any page | |
| const r = await fetch("https://approjects-warn-act-notices.static.hf.space/data/coverage.json"); | |
| const cov = await r.json(); | |
| console.log(Object.keys(cov.states).length, "state agencies", cov.generated_at);</code></pre> | |
| <h2 id="endpoints">Endpoints</h2> | |
| <p>Base URL <code>https://apventureengine.github.io/warn-act-notices</code>. Sizes and row counts below are from the build that wrote this | |
| page, so they are what you will actually download today.</p> | |
| <div class="tw"><table><thead><tr><th>Endpoint</th><th>What</th><th>Records</th><th>Size</th><th>Use it for</th></tr></thead><tbody><tr><td><a href="data/warn_notices.json"><code>/data/warn_notices.json</code></a></td><td>Whole archive, JSON</td><td class="num">61,431 notices</td><td class="num">20.1 MB</td><td>Every notice we hold, one object per notice, 11 normalized fields. The file a backend or notebook wants.</td></tr><tr><td><a href="data/warn_notices.ndjson"><code>/data/warn_notices.ndjson</code></a></td><td>Whole archive, NDJSON</td><td class="num">61,431 notices</td><td class="num">18.7 MB</td><td>The same notices, one JSON object per line, so a stream reader never buffers 20 MB: <code>curl … | head</code>, <code>jq -c</code>, log shippers, DuckDB.</td></tr><tr><td><a href="data/latest.csv"><code>/data/latest.csv</code></a></td><td>Recent notices, CSV</td><td class="num">88 notices</td><td class="num">16 kB</td><td>The rolling window of notices added lately — the cheap poll for a daily job.</td></tr><tr><td><a href="data/latest.json"><code>/data/latest.json</code></a></td><td>Recent notices, JSON</td><td class="num">88 notices</td><td class="num">36 kB</td><td>Same window as latest.csv with a header block: generated_at, window_days, count.</td></tr><tr><td><a href="datapackage.json"><code>/datapackage.json</code></a></td><td>Schema (Frictionless Table Schema)</td><td class="num">11 fields</td><td class="num">3 kB</td><td>Field names, types and descriptions for the CSVs. Read this before you map columns.</td></tr><tr><td><a href="data/coverage.json"><code>/data/coverage.json</code></a></td><td>Per-state coverage + freshness</td><td class="num">48 states</td><td class="num">11 kB</td><td>For every state agency: rows held, last scrape time, latest notice date, status. This is the file to poll if you want to know whether a state is behind.</td></tr><tr><td><a href="data/stale.json"><code>/data/stale.json</code></a></td><td>Sources behind their usual cadence</td><td class="num">10 late sources</td><td class="num">2 kB</td><td>The subset of coverage.json that is late, with how late. Machine-readable honesty.</td></tr><tr><td><a href="data/trends.json"><code>/data/trends.json</code></a></td><td>Monthly series</td><td class="num">24 months</td><td class="num">56 kB</td><td>Notices and workers per month, national and by state — for charts without re-aggregating the archive.</td></tr><tr><td><a href="data/search-index.json"><code>/data/search-index.json</code></a></td><td>Employer search index</td><td class="num">29,971 employers</td><td class="num">2.7 MB</td><td>Canonical employer names with their notice counts; powers client-side search.</td></tr><tr><td><a href="data/badge.json"><code>/data/badge.json</code></a></td><td>Shields.io endpoint badge</td><td class="num">—</td><td class="num">153 B</td><td>Drop a live 'notices on record' badge in your own README.</td></tr><tr><td><a href="feed.xml"><code>/feed.xml</code></a></td><td>RSS of new notices</td><td class="num">50 items</td><td class="num">29 kB</td><td>For feed readers and RSS-to-anything plumbing. No key.</td></tr></tbody></table></div> | |
| <h3>Per-state CSVs (48 states)</h3> | |
| <p class="states"><a href="data/by-state/ak.csv">AK</a> · <a href="data/by-state/al.csv">AL</a> · <a href="data/by-state/az.csv">AZ</a> · <a href="data/by-state/ca.csv">CA</a> · <a href="data/by-state/co.csv">CO</a> · <a href="data/by-state/ct.csv">CT</a> · <a href="data/by-state/dc.csv">DC</a> · <a href="data/by-state/de.csv">DE</a> · <a href="data/by-state/fl.csv">FL</a> · <a href="data/by-state/ga.csv">GA</a> · <a href="data/by-state/hi.csv">HI</a> · <a href="data/by-state/ia.csv">IA</a> · <a href="data/by-state/id.csv">ID</a> · <a href="data/by-state/il.csv">IL</a> · <a href="data/by-state/in.csv">IN</a> · <a href="data/by-state/ks.csv">KS</a> · <a href="data/by-state/ky.csv">KY</a> · <a href="data/by-state/la.csv">LA</a> · <a href="data/by-state/ma.csv">MA</a> · <a href="data/by-state/md.csv">MD</a> · <a href="data/by-state/me.csv">ME</a> · <a href="data/by-state/mi.csv">MI</a> · <a href="data/by-state/mn.csv">MN</a> · <a href="data/by-state/mo.csv">MO</a> · <a href="data/by-state/ms.csv">MS</a> · <a href="data/by-state/mt.csv">MT</a> · <a href="data/by-state/nc.csv">NC</a> · <a href="data/by-state/nd.csv">ND</a> · <a href="data/by-state/ne.csv">NE</a> · <a href="data/by-state/nj.csv">NJ</a> · <a href="data/by-state/nm.csv">NM</a> · <a href="data/by-state/nv.csv">NV</a> · <a href="data/by-state/ny.csv">NY</a> · <a href="data/by-state/oh.csv">OH</a> · <a href="data/by-state/ok.csv">OK</a> · <a href="data/by-state/or.csv">OR</a> · <a href="data/by-state/pa.csv">PA</a> · <a href="data/by-state/ri.csv">RI</a> · <a href="data/by-state/sc.csv">SC</a> · <a href="data/by-state/sd.csv">SD</a> · <a href="data/by-state/tn.csv">TN</a> · <a href="data/by-state/tx.csv">TX</a> · <a href="data/by-state/ut.csv">UT</a> · <a href="data/by-state/va.csv">VA</a> · <a href="data/by-state/vt.csv">VT</a> · <a href="data/by-state/wa.csv">WA</a> · <a href="data/by-state/wi.csv">WI</a> · <a href="data/by-state/wv.csv">WV</a></p> | |
| <p class="st">Pattern: <code>https://approjects-warn-act-notices.static.hf.space/data/by-state/<two-letter-code-lowercase>.csv</code></p> | |
| <figure><svg class="dv-svg" viewBox="0 0 680 440" width="100%" height="440" role="img" xmlns="http://www.w3.org/2000/svg" aria-label="bar chart"><text x="0" y="19" font-size="13" fill="currentColor">California</text><rect x="96" y="0" width="471.0" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="576.0" y="19" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">16,640 notices</text><text x="0" y="55" font-size="13" fill="currentColor">New York</text><rect x="96" y="36" width="184.4" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="289.4" y="55" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">6,515 notices</text><text x="0" y="91" font-size="13" fill="currentColor">Illinois</text><rect x="96" y="72" width="137.2" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="242.2" y="91" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">4,847 notices</text><text x="0" y="127" font-size="13" fill="currentColor">Florida</text><rect x="96" y="108" width="88.2" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="193.2" y="127" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">3,116 notices</text><text x="0" y="163" font-size="13" fill="currentColor">Texas</text><rect x="96" y="144" width="67.7" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="172.7" y="163" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">2,391 notices</text><text x="0" y="199" font-size="13" fill="currentColor">New Jersey</text><rect x="96" y="180" width="66.0" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="171.0" y="199" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">2,330 notices</text><text x="0" y="235" font-size="13" fill="currentColor">Michigan</text><rect x="96" y="216" width="62.3" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="167.3" y="235" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">2,202 notices</text><text x="0" y="271" font-size="13" fill="currentColor">Pennsylvania</text><rect x="96" y="252" width="53.7" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="158.7" y="271" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">1,896 notices</text><text x="0" y="307" font-size="13" fill="currentColor">Washington</text><rect x="96" y="288" width="43.0" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="148.0" y="307" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">1,519 notices</text><text x="0" y="343" font-size="13" fill="currentColor">Oregon</text><rect x="96" y="324" width="38.8" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="143.8" y="343" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">1,371 notices</text><text x="0" y="379" font-size="13" fill="currentColor">Maryland</text><rect x="96" y="360" width="36.1" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="141.1" y="379" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">1,277 notices</text><text x="0" y="415" font-size="13" fill="currentColor">Indiana</text><rect x="96" y="396" width="33.5" height="26" rx="4" fill="var(--dv-line,#2a78d6)"/><text x="138.5" y="415" font-size="12.5" font-weight="700" fill="currentColor" opacity=".72">1,182 notices</text></svg><figcaption>Notices on record per state agency, top 12 of 48 (61,431 in total). Each state also has its own CSV endpoint below. · Source: data/coverage.json, written by the same build as this page · as of 2026-09-25</figcaption></figure> | |
| <h2 id="schema">Schema</h2> | |
| <p>The same fields in every endpoint, machine-readable at <a href="datapackage.json"><code>/datapackage.json</code></a>:</p> | |
| <div class="tw"><table><thead><tr><th>Field</th><th>Type</th><th>Meaning</th></tr></thead><tbody><tr><td><code>id</code></td><td>string</td><td>Stable dedupe id (source record number where available, else content hash)</td></tr><tr><td><code>state</code></td><td>string</td><td>2-letter US postal code</td></tr><tr><td><code>company</code></td><td>string</td><td>Employer name exactly as published by the state</td></tr><tr><td><code>company_canonical</code></td><td>string</td><td>Cleaned employer name; groups the same employer across states, renotices and store numbers</td></tr><tr><td><code>company_dba</code></td><td>string</td><td>Trade name when the state published a dba/aka alias</td></tr><tr><td><code>location</code></td><td>string</td><td>City/county/address, best effort</td></tr><tr><td><code>employees_affected</code></td><td>integer</td><td>Workers affected; empty if the state omitted it</td></tr><tr><td><code>notice_date</code></td><td>date</td><td>ISO date the notice was received/posted (NJ: month precision, day pinned to 01)</td></tr><tr><td><code>effective_date</code></td><td>date</td><td>ISO date the layoff/closure takes effect</td></tr><tr><td><code>notice_type</code></td><td>string</td><td>Layoff/closure label as published</td></tr><tr><td><code>first_seen</code></td><td>datetime</td><td>UTC timestamp the pipeline first saw this notice</td></tr></tbody></table></div> | |
| <h2 id="limits">What this API does not do</h2> | |
| <p>Three things, and they are the honest reason a paid tier exists rather than a fake one:</p> | |
| <ul> | |
| <li><b>It does not push.</b> A snapshot cannot tell you that <i>your</i> employer just filed. You | |
| would have to poll and diff it yourself — <a href="https://github.com/APVentureEngine/warn-layoff-alert-bot">warn-layoff-alert-bot</a> is a | |
| 120-line, dependency-free example that does exactly that from a daily GitHub Actions cron and posts | |
| to Slack or Discord (MIT; fork it).</li> | |
| <li><b>It does not filter.</b> Static files have no query parameters — you download and filter | |
| locally (the DuckDB snippet above does it in one statement).</li> | |
| <li><b>It is a once-a-morning rebuild</b>, not a stream.</li> | |
| </ul> | |
| <div class="cta"><b>If what you actually wanted was an alert, not a file:</b> | |
| WARN Watch runs your employer list — up to 500 names, or whole states — against every daily | |
| refresh for a year and pushes the hits to a private page, an RSS feed, a calendar and your | |
| Slack, Discord or Teams webhook. | |
| <a href="https://approjects-warn-act-notices.static.hf.space/watch.html">WARN Watch — $49/year, one payment →</a> | |
| Or take the <a href="https://approj.gumroad.com/l/warn-free-watch">free 30-day trial</a> | |
| (3 employers or 1 state, no card).</div> | |
| <h2 id="mcp">Ask it in plain English: the MCP server</h2> | |
| <p>If you work inside an AI assistant rather than a notebook, you do not have to download | |
| anything. <code>warn-mcp</code> exposes this dataset as six read-only | |
| <a href="https://modelcontextprotocol.io">Model Context Protocol</a> tools — employer | |
| search, the rolling new-notice feed, one employer’s whole history back to 1988, monthly | |
| state totals, the daily revision log, and a freshness check — so you can just ask:</p> | |
| <p class="quote"><i>“Has Starbucks filed any WARN notices this year, and in which | |
| states?” · “What layoffs were announced in Texas in the last two weeks?” | |
| · “Which state had the most workers affected in 2026?”</i></p> | |
| <p><b>Claude Desktop, Cursor, Continue, Claude Code — no key, no account:</b> install the | |
| one-file bundle from the | |
| <a href="https://github.com/APVentureEngine/warn-mcp/releases/latest/download/warn-mcp.mcpb">latest | |
| release</a>, or one line in a terminal:</p> | |
| <pre><code>claude mcp add warn -- uvx --from git+https://github.com/APVentureEngine/warn-mcp warn-mcp</code></pre> | |
| <p><b>ChatGPT and Claude.ai connectors, n8n, anything that wants a URL:</b> the same six tools are | |
| hosted over Streamable HTTP at <code>https://mQpACuIiQcnwK93JY.apify.actor/mcp</code>. One honest | |
| caveat — the host meters compute to whoever calls it, so that route needs <i>your</i> own | |
| free Apify API token in an <code>Authorization: Bearer</code> header. We charge nothing for it and | |
| store nothing about your queries; the bundle above needs no token at all, so prefer it when your | |
| client supports it.</p> | |
| <p>Both routes are listed as <code>io.github.APProj/warn-mcp</code> in the | |
| <a href="https://registry.modelcontextprotocol.io/v0/servers?search=warn-mcp">official MCP | |
| registry</a>. Source and issues: <a href="https://github.com/APVentureEngine/warn-mcp">the | |
| warn-mcp repository</a>.</p> | |
| <h2 id="faq">FAQ</h2> | |
| <h3>Is it really free, and what is the catch?</h3><p>Really free, CC BY 4.0, no account. The catch is honest and structural: these are static files rebuilt once a morning, so there are no query parameters, no per-request filtering and no push. If that is enough, you never have to pay us.</p><h3>How fresh is it?</h3><p>The build that produced this page finished at <code>2026-09-25T00:11:25.651533Z</code> and the newest notice in it is dated 2026-09-25. Every state is re-scraped in the same run; <code>/data/coverage.json</code> carries the per-state scrape time and <code>/data/stale.json</code> lists any source that is behind its usual cadence, so you never have to guess whether silence means 'no layoffs' or 'our scraper broke'.</p><h3>Why does curl print 'Found. Redirecting to…' for the archive?</h3><p>Files over about 10 MB (<code>warn_notices.json</code>, <code>warn_notices.ndjson</code>) answer <code>302</code> to a CDN copy; everything smaller is served directly. Follow redirects — <code>curl -L</code>, and every HTTP library does it by default. The CDN answers with the same <code>access-control-allow-origin: *</code> and its own <code>ETag</code> (measured 2026-09-13).</p><h3>Can I call it from a browser?</h3><p>Yes. The host answers <code>access-control-allow-origin: *</code> on these files, so <code>fetch()</code> works from any origin with no proxy of your own.</p><h3>Rate limits?</h3><p>None imposed by us, and we would rather you were polite than throttled. Every file is served with an <code>ETag</code>, and a request carrying <code>If-None-Match</code> with the last value you saw gets <code>304 Not Modified</code> and no body (measured 2026-09-13: <code>304</code>, 0 bytes). <code>Last-Modified</code> is <i>not</i> sent, so <code>If-Modified-Since</code> does nothing — use the ETag. Poll <code>/data/latest.json</code> (small) and only re-pull the archive when its <code>generated_at</code> moves. Mirroring the files is explicitly allowed — that is what CC BY 4.0 means.</p><h3>What do I have to put in my app?</h3><p>Credit "WARN Feed" with a link to this site. That is the whole obligation.</p><h3>Will the fields change under me?</h3><p>The schema lives in <code>/datapackage.json</code> and is the same contract the CSVs and the Hugging Face mirrors use. New columns get appended; if one ever has to change meaning it is written up in the repository's release notes, not silently.</p><h3>I need something you do not publish.</h3><p>Ask for it — <a href="https://github.com/APVentureEngine/warn-act-notices/issues/new">open an issue</a> and say which field, state or shape you need. Requests that are a small transform of what we already scrape usually ship the same week, because the pipeline runs every day anyway.</p> | |
| <h2 id="mirrors">Mirrors and other shapes</h2> | |
| <p>The same data, maintained by the same daily build, if a different surface suits you better: | |
| <a href="https://github.com/APVentureEngine/warn-act-notices">the Git repository</a> (versioned, every change is a commit) · | |
| <a href="https://huggingface.co/datasets/APProjects/us-warn-act-layoffs-notices-daily">the | |
| Hugging Face dataset</a> (parquet-backed viewer, <code>datasets.load_dataset</code>) · | |
| <a href="feed.xml">RSS</a> · <a href="search.html">the web search UI</a>.</p> | |
| <footer>61,431 notices across 48 state agencies, rebuilt 2026-09-25. | |
| Data: official state labor department WARN listings, normalized by us. Not legal advice — whether | |
| a given event meets a WARN threshold is a question for the statute and the notice itself. | |
| CC BY 4.0 — credit “WARN Feed”, an independent automated publisher. | |
| Questions, bug reports and endpoint requests: <a href="https://github.com/APVentureEngine/warn-act-notices/issues/new">open an issue</a> · | |
| <a href="index.html">live stats</a> · <a href="coverage.html">per-source freshness</a> · | |
| <a href="terms.html">terms</a> · <a href="privacy.html">privacy</a><p class="beacon-note" style="font-size:.8rem;color:#777">Loads counted anonymously: one 1×1 CDN image, no cookies, no personal data (<a href="privacy.html">detail</a>).</p> | |
| </footer> | |
| <img src="https://cdn.jsdelivr.net/gh/APVentureEngine/warn-act-notices@main/assets/px.png" alt="" width="1" height="1" referrerpolicy="no-referrer" style="position:absolute;left:-9999px;top:0"> | |
| <script id="fl">if(top!==self)for(var a of document.links)if(a.origin!==location.origin){a.target="_blank";a.rel="noopener"}</script> | |
| </body></html> |