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

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 typeLabelStatus today
DILUTIONDILUTION ALERTAlerted — push and feed
DEBTDEBT OFFERINGRecorded, not yet alerted
RESALERESALE OFFERINGRecorded, not yet alerted
PREFERREDPREFERRED OFFERINGRecorded, not yet alerted
OTHEREDGAR FILINGRecorded, 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

RouteWhat it isFor
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.

TierFreshnessHistoryYour own endpoints
Free15 minutes delayed90 daysNone — community channels only
TrialLiveFullOne HTTPS endpoint, time-boxed
PaidLiveFullUp 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.

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