// guide
Insider Trading Webhooks: Real-Time SEC Form 4 Alerts
Updated 2026-06-16. By Theodor Nielsen, founder of Form4API.
// answer
To get real-time insider trading alerts, register a webhook pointing at a public HTTPS endpoint. Form4API then sends an HTTP POST within minutes of each new SEC Form 4 on EDGAR. Verify the X-Insider-Signature header — an HMAC-SHA256 of the raw body in the form sha256=<hex> — before trusting the payload, then return a 2xx quickly to acknowledge it.
Why webhooks beat polling
You can poll /v1/transactions on a timer — see the Python tutorial — but polling wastes calls when nothing has filed and adds latency equal to your poll interval. Webhooks invert that: you do work only when a filing actually lands, and you hear about it within minutes of EDGAR publication. For alerting, trade automation, or anything time-sensitive, push beats pull.
Register a subscription
Add a subscription on the dashboard webhooks page: a public HTTPS URL to deliver to, the events you want, and a signing secret (keep it somewhere safe — you will need it to verify deliveries). You can subscribe to new filings, cluster buys, and cluster sells; the X-Event-Type header on each delivery tells you which one fired. See the docs for the full event catalogue.
The request you receive
Each delivery is a POST with a JSON body and three headers you care about:
| Header | What it is |
|---|---|
| X-Insider-Signature | sha256=<hex> — HMAC-SHA256 of the raw body, keyed with your signing secret. |
| X-Event-Type | Which event fired (a new transaction, a cluster buy, or a cluster sell). |
| X-Delivery-Id | A unique ID for this delivery — use it to de-duplicate retries (idempotency). |
The body is a compact JSON payload referencing the event — for a new-transaction event, the filing ID and accession number; fetch the full parsed transaction from /v1/transactions. Exact fields are in the docs.
Verify the signature (do this first)
Anyone who learns your URL could POST to it, so never act on a delivery you have not verified. Compute an HMAC-SHA256 of the raw request body with your signing secret, hex-encode it lowercase, prefix sha256=, and compare it to X-Insider-Signature in constant time. In Python:
import hmac
import hashlib
def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
digest = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
expected = "sha256=" + digest
# constant-time compare to avoid timing attacks
return hmac.compare_digest(expected, signature_header or "")The same check in Node:
const crypto = require("crypto");
function verify(rawBody, signatureHeader, secret) {
const digest = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const expected = "sha256=" + digest;
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}The one mistake to avoid: hashing a re-serialized body. Frameworks that auto-parse JSON can change key order and whitespace; always hash the exact bytes you received, which is why the receivers below read the raw body explicitly.
Build a receiver
A minimal Flask receiver that reads the raw body, verifies the signature, and acknowledges fast:
import os
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["FORM4API_WEBHOOK_SECRET"]
@app.post("/form4-webhook")
def on_event():
raw = request.get_data() # raw bytes, before JSON parsing
if not verify(raw, request.headers.get("X-Insider-Signature"), SECRET):
abort(401)
delivery_id = request.headers.get("X-Delivery-Id")
event_type = request.headers.get("X-Event-Type")
if already_processed(delivery_id): # idempotency — see below
return "", 200
enqueue_for_processing(event_type, request.get_json()) # do heavy work async
return "", 200 # acknowledge quicklyExpress is the same shape — mount express.raw() on the route so you get the unparsed Buffer, verify, then res.sendStatus(200).
Retries & idempotency
A delivery is considered successful only if your endpoint returns a 2xx. If it does not, it is retried with a short back-off — roughly +2 minutes after the first failure and +16 minutes after the second — and then marked dead. Two consequences for your receiver:
- Acknowledge fast. Return 2xx as soon as you have verified and stored the event; do parsing, enrichment, and trading logic asynchronously so a slow handler does not trigger a retry.
- Be idempotent. A retry re-delivers the same event, so key your processing on
X-Delivery-Idand skip anything you have already handled.
Because deliveries are dropped after the retries are exhausted, a long outage means gaps — reconcile by paging /v1/transactions for the window you were down.
Frequently asked questions
How do I get real-time insider trading alerts?
Register a webhook subscription pointing at a public HTTPS endpoint you control, choose the events you care about (new filings, cluster buys, cluster sells), and your endpoint receives an HTTP POST within minutes of the underlying SEC Form 4 being published on EDGAR. This is faster and cheaper than polling a transactions endpoint on a timer, because you only do work when something actually happens. Each delivery is signed so you can confirm it really came from Form4API before acting on it.
How do I verify a Form4API webhook signature?
Every delivery includes an X-Insider-Signature header of the form sha256=<hex>. Compute an HMAC-SHA256 of the raw request body using your subscription’s signing secret, hex-encode it in lowercase, prefix it with "sha256=", and compare it to the header using a constant-time comparison. Critically, sign the raw bytes you received — not a re-serialized version of the parsed JSON — because any change in key order or whitespace will change the hash and the check will fail. Reject the request if the signatures do not match.
What happens if my webhook endpoint is down?
Deliveries that do not return a 2xx status are retried with a short back-off — roughly two minutes after the first failure, then about sixteen minutes after the second. If it still fails, the delivery is marked dead and dropped, so a long outage means missed events. Return a 2xx quickly (do heavy work asynchronously), and if you need to backfill anything you missed during downtime, page the /v1/transactions endpoint for the gap.
Are insider trading webhooks free?
Webhooks are available on the paid plans; the free tier is poll-only. The free tier still covers 15,000 API calls a month with no credit card, which is enough to evaluate the data and build a polling prototype before upgrading to push delivery.