EDGAR Signals
A micro-cap learns it is being diluted when the 424B5 hits EDGAR. We read that filing within minutes and tell you what it actually says — how big the raise is, how many shares, at what price, and whether the number we printed is the filing's or our own arithmetic.
Live: DILUTION alerts Provenance on every field Free delayed feed · paid live feed
Honest scope: today we alert on DILUTION only.
DEBT, RESALE, PREFERRED and OTHER findings are
recorded and shipped in the dataset, but are not yet delivered as alerts.
What we watch
Everything in EDGAR's 424 offering family — registration statements and prospectus supplements for shares being sold into the market. We poll EDGAR's new-filings feed every few seconds, fetch the document, and read the offering terms out of the cover page and fee table.
What we claim about speed, precisely: detection is bounded by our poll interval — the alert goes out within seconds of a filing appearing in EDGAR's feed — and our own processing from ingest to delivery is measured in seconds. What we do not claim is latency from EDGAR's acceptance time: EDGAR does not publish when a filing first becomes discoverable, so that number could not be verified by you or by us.
What comes out of it
- Size and structure — aggregate offering price, shares offered, price per unit, units offered, commission rate, last sale price.
- What else is attached — warrants (count, strike, pre-funded subset), convertibles (principal, conversion price/rate/shares, whether the conversion is variable), placement agent, use of proceeds.
- Whether it is dilutive at all, and on what basis — labelled with the evidence class, in words, never a "confidence score" we did not measure.
And, on every single field, where the number came from
This is the part that matters if you intend to trade off it. Each value carries its provenance: read from the document by code, read by a language model, or computed by us. A figure we calculated is flagged as derived rather than presented as something the filing stated. Unreadable fields stay empty — they are never guessed to look complete.
A real finding from our corpus
Verastem, Inc. 424B5, accession
0001104659-26-115879
(the
filing itself). Trimmed for readability; this is machine output, not a mock-up.
{
"schema": "dilution/v1",
"event_type": "DILUTION",
"accession_number": "0001104659-26-115879",
"ticker": "VSTM",
"values": {
"company_name": "Verastem, Inc.",
"form_type": "424B5",
"max_aggregate_offering_price": 249999992.75,
"shares_offered": 30937500,
"warrants_included": true,
"offering_type": "Firm commitment",
"security_type": "Common/ordinary shares",
"last_sale_price": 7.45,
"is_dilutive": true,
"filing_url": "https://www.sec.gov/Archives/edgar/data/1526119/..."
},
"sources": {
"max_aggregate_offering_price": "llm",
"shares_offered": "llm",
"last_sale_price": "code",
"security_type": "code:primary",
"is_dilutive": "code:primary",
"classification_evidence": "code:firm_commitment"
},
"derived": {},
"confidence": {
"classification_evidence": "moderate",
"classification_basis": "firm_commitment",
"form": "registered",
"fields": { "total": 13, "from_code": 6, "from_llm": 2, "unfilled": 5 }
}
}
Read that honestly: two of the five numbers here were read by a model, not by code — and
sources says so. derived is empty, meaning nothing in this alert is our
arithmetic. unfilled: 5 is the tell that would be hidden anywhere else: five of the
thirteen fields the stream tracks were never filled, because the filing did not state them.
What we classify, and what we alert on
Event types are economic, not form-qualified: a resale is RESALE whether
it arrived on a 424B3 or a 424B5. The form travels alongside, so you always know the document.
| Event type | Label | Status today |
|---|---|---|
DILUTION | DILUTION ALERT | Alerted — push and feed |
DEBT | DEBT OFFERING | Recorded, not yet alerted |
RESALE | RESALE OFFERING | Recorded, not yet alerted |
PREFERRED | PREFERRED OFFERING | Recorded, not yet alerted |
OTHER | EDGAR FILING | Recorded, not yet alerted |
We would rather say this plainly than imply a breadth we have not earned: four of the five types are captured and published, but not yet delivered as alerts.
Three ways to consume it
| Route | What it is | For |
|---|---|---|
| Community chat | Our Discord and Telegram. The free feed is delayed; a paid role unlocks the live channels. | Traders who want alerts in a chat app and nothing to build |
| The dataset | A downloadable file, one row per recorded finding, over a fixed past window — including the filings we never alerted on. | Quants who want to evaluate the data before talking to us |
| Signed HTTP push | Every finding POSTed to your endpoint, signed with our Ed25519 key, plus a read API to backfill and gap-fill after downtime. | Systems that need the data the moment it exists |
How fresh it is — the one thing that is actually for sale
The free feed is 15 minutes behind. Paid is live. That is the product; everything else is packaging. The delay is a real property of the data you receive, not a UI trick: it is enforced on both the push and the read side from the same policy, so there is no way to reconstruct the live feed from a free account by polling.
| Tier | Freshness | History | Your own endpoints |
|---|---|---|---|
| Free | 15 minutes delayed | 90 days | None — community channels only |
| Trial | Live | Full | One HTTPS endpoint, time-boxed |
| Paid | Live | Full | Up to two HTTPS endpoints (community chat via the paid role) |
Registerable endpoints are HTTPS only today. Pointing us at your own Discord or Telegram would mean holding a credential of yours, and we would rather build that behind envelope encryption than store it in the clear — so it is deliberately not available yet.
Pricing is not published yet — we are setting it with our first subscribers rather than guessing at a number here. The free community feed is free and will stay free. Get on the list and you will be told before it changes.
For developers
Everything below is a real, live contract, current as of today. The API base is
https://edgar-api-34u3u5uiha-uc.a.run.app — the interactive schema is at
/docs.
1. Read history, and gap-fill after downtime
GET /findings returns the same projection we push, oldest first, with a
cursor. Replay the cursor after a reconnect and you have covered the gap — no duplicate, no miss.
# page 1
curl "https://edgar-api-34u3u5uiha-uc.a.run.app/findings?limit=100" \
-H "X-API-Key: $EDGAR_API_KEY"
# next page (and again, until "has_more" is false)
curl "https://edgar-api-34u3u5uiha-uc.a.run.app/findings?since=$NEXT_CURSOR" \
-H "X-API-Key: $EDGAR_API_KEY"
The key goes in a header, never in the URL — a key in a query
string leaks into logs, history and referrers. Optional filters: event_type,
ticker. Each response reports as_of (the freshest data your tier may
see), window_start, and quota_remaining, so a delayed tier can see its
own lag rather than infer it.
2. Receive it live, signed
Register an HTTPS endpoint with your licence key, and every finding is POSTed to it as JSON:
curl -X POST "https://edgar-api-34u3u5uiha-uc.a.run.app/register_endpoint" \
-H "Content-Type: application/json" \
-d '{"license_key":"...","url":"https://your-app.example/edgar","event_types":["DILUTION"]}'
Each request carries X-EDGAR-Timestamp, X-EDGAR-Signature and
X-EDGAR-Key-Id. The signature is Ed25519 over "<timestamp>." + raw_body. We
hold the private key; you verify with the public key published at /keys. Nothing
secret is ever exchanged, and no per-endpoint secret is stored on our side.
import base64, time
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
PUBLIC_KEY = base64.b64decode("<our public key from /keys>") # 32 raw bytes
def verify(headers, raw_body):
ts = int(headers["X-EDGAR-Timestamp"])
if abs(time.time() - ts) > 300: # reject stale/replayed requests
return False
sig = base64.b64decode(headers["X-EDGAR-Signature"].split("=", 1)[1])
Ed25519PublicKey.from_public_bytes(PUBLIC_KEY).verify(sig, f"{ts}.".encode() + raw_body)
return True # raises InvalidSignature on mismatch
Verify over the raw request bytes — re-serialising the parsed JSON will not reproduce the signature. Only public HTTPS URLs are accepted (loopback, private and link-local hosts are refused, redirects are disabled).
3. Get a key
Keys are issued with a subscription today. Self-serve signup — paste an email, get a key, lift the demo caps — is the next thing we are building, and it will change nothing about the contract above. Join the list to get one, or ask for a trial.
Get on the list
The community channels and self-serve signup are being built now — this page is live ahead of them so the developer contract above is public and testable in the meantime.
- Discord — invite link to follow (community feed, delayed; live channels for subscribers)
- Telegram — invite link to follow (community feed, delayed)
- Early access / a key — signup form to follow
The dataset
A downloadable file over a fixed past window, one row per recorded finding —
including the DEBT, RESALE and OTHER filings we never alerted
on. A researcher wants the population, not our alert filter, and publishing the population is what
makes our coverage auditable instead of something you have to take on faith.
The download and the coverage notes go live with the dataset tooling. It is not gated behind an account: the point of it is that you can evaluate us without talking to us.
What we will not claim
- Coverage started 13 October 2026. That is when we began recording findings live. Anything before it is issuer filing history, backfilled from EDGAR, not our alert record.
- Only
DILUTIONis alerted. The other four event types are recorded and shipped in the dataset. - Fields are sometimes unreadable, and we leave them empty. Every finding reports how many of its tracked fields were filled, and by what — code or model. A blank is a blank, never a guess.
- We are not affiliated with the SEC, and this is not investment advice. We read public filings and tell you what they say; what you do with that is yours.