Skip to content

Receive signals via webhooks (Pro Plus)

Receive signals via webhooks (Pro Plus)

Webhooks push events to your URL the moment FalsifyLab generates them. No polling, no missed firings. Pro Plus and Teams only.

What gets pushed

eventwhen
confluencea new asset hits 2+ signal alignment (equity or crypto)
insider_cluster3+ insiders bought the same ticker in a 5-day window
material_8knew 8-K filing with a material item code (1.01, 1.03, 2.01, 2.02, 4.02, 5.02, 8.01)
etf_flow_milestonespot BTC or ETH ETF flow crosses $50M net for a day

Pick a subset or pass ["all"] for every event type.

Register your endpoint

Terminal window
curl -X POST https://mcp.falsifylab.com/api/webhooks/register \
-H "Content-Type: application/json" \
-d '{
"license_key": "<your_whop_license_key>",
"webhook_url": "https://yourapp.com/falsifylab-webhook",
"events": ["confluence", "insider_cluster", "material_8k", "etf_flow_milestone"]
}'

Response:

{
"ok": true,
"tier": "<your_whop_plan_id>",
"webhook_url": "https://yourapp.com/falsifylab-webhook",
"events": ["confluence", "insider_cluster", "material_8k", "etf_flow_milestone"],
"note": "Registered. Pending operator approval (typically <24h). Deliveries fire on next event match after activation.",
"echo": { "license_hash": "abcd...wxyz" }
}

The operator (Navid) gets a Telegram ping with your registration. After a quick sanity check on the URL, the subscription activates and starts firing on the next event match. Usually within an hour during waking hours.

Receive

Every event arrives at your endpoint as POST with these headers:

Content-Type: application/json
User-Agent: FalsifyLab-Webhook/1.0
X-FalsifyLab-Event: confluence
X-FalsifyLab-Signature: sha256=<hex>

Body (flat JSON, fields vary slightly by event):

{
"event": "confluence",
"fired_at": "2026-05-15T07:42:18Z",
"asset": "ETH",
"kind": "crypto",
"signal_count": 3,
"signals": ["form4_cluster", "etf_flow_milestone", "sec8k_material"],
"raw_url": "https://falsifylab.com/api/confluence?min_signals=2",
"delivery_id": "a1b2c3d4e5f6g7h8",
"sequence": 1
}

delivery_id is unique per delivery attempt. Use it for idempotency on your side. sequence is monotonic per subscription, useful for ordering.

Each event type has slightly different payload fields:

  • confluence: asset, kind, signal_count, signals
  • insider_cluster: asset, filer_count, total_buy_usd
  • material_8k: asset, items, filer, link
  • etf_flow_milestone: asset, net_flow_usd, streak_direction, streak_days

All payloads include: event, fired_at, raw_url, delivery_id, sequence.

Verify the signature

Your HMAC secret is your license_key itself. No separate secret to manage.

Python:

import hmac, hashlib
def verify(body_bytes: bytes, signature_header: str, license_key: str) -> bool:
expected = hmac.new(
license_key.encode(), body_bytes, hashlib.sha256
).hexdigest()
provided = signature_header.replace("sha256=", "")
return hmac.compare_digest(expected, provided)

Node:

import crypto from "node:crypto";
function verify(bodyBytes, signatureHeader, licenseKey) {
const expected = crypto
.createHmac("sha256", licenseKey)
.update(bodyBytes)
.digest("hex");
const provided = signatureHeader.replace("sha256=", "");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(provided),
);
}

If the signature does not match, reject the request and log it. Replay attack is possible without verification.

Delivery semantics

  • POST timeout: 15 seconds. Non-2xx response or timeout counts as failure.
  • Retry policy: one retry, 60 seconds after the first failure.
  • After 3 consecutive failed deliveries, your subscription status flips to failing and stops firing. Ping the operator to reactivate after you fix your endpoint.
  • Idempotency: dedupe on delivery_id (it stays stable across the retry).
  • No replay endpoint in v1. If you miss an event you can recompute via the raw_url in the payload.

Limits

tierwebhook URLsevents
Free / Pro ($19)0 (registration returns 402)none
Pro Plus ($49)1all 4 event types
Teams ($199)5all 4 event types

Manage subscriptions

Listing and deleting via API is on the roadmap for v1.1. Today, ping the operator on Telegram or via the support email and we will remove or update your subscription manually.

Common issues

  • 402 license not valid / not active: your Whop subscription is not Pro Plus or higher, or your license_key is invalid. Check Whop dashboard.
  • 400 webhook_url must be https://: registration requires an HTTPS endpoint. No HTTP.
  • 400 invalid license_key: license_key must be 8+ chars, alphanumeric / underscore / dash.
  • Subscription stuck “Pending operator approval”: the operator vets every new sub manually before activation. Usually <1h while operator is awake, up to 24h. Once active, fires start on the next event match.

What to expect after registration

  1. You curl the register endpoint and get ok: true.
  2. The operator gets a Telegram ping and vets your URL.
  3. The operator appends your subscription to the active subs file.
  4. On the next 5-minute cron tick after activation, the dispatcher checks for new events.
  5. Matching events fire to your endpoint with HMAC signature.
  6. You verify, dedupe, and act.

First event usually arrives within an hour of activation, depending on market activity.