This guide walks you through receiving your first webhook delivery end-to-end: create a destination in the dashboard, spin up a receiver, verify the signature, and replay a delivery. By the end you’ll have a production-ready handler.Documentation Index
Fetch the complete documentation index at: https://docs.financialdatasets.ai/llms.txt
Use this file to discover all available pages before exploring further.
Already integrated? Jump to the Webhooks reference for the full event catalog, payload envelope, retry schedule, and production checklist.
Prerequisites
- Pro or Enterprise plan. Upgrade if needed.
- Python 3.10+ for the code samples (Node alternative shown in tabs).
- An HTTPS endpoint you control. For local testing, use a tunnel like ngrok or localtunnel to expose
localhost.
What we’ll build
Throughout this guide we’ll build a handler for a fictional integrator, Acme Capital. Acme wants a Slack ping the moment we publish new earnings for any ticker on their watchlist (AAPL, MSFT, NVDA).
| Value | |
|---|---|
| Acme’s endpoint URL | https://acme.example.com/webhooks/financial-datasets |
| Signing secret (placeholder) | whsec_PLACEHOLDER_FROM_DASHBOARD |
| Event type | earnings.created |
| Watchlist | AAPL, MSFT, NVDA |
Step 1: Add a destination in the dashboard
- Go to the Webhooks page in your dashboard.
- Click Add destination.
- Paste your HTTPS endpoint URL — for Acme that’s
https://acme.example.com/webhooks/financial-datasets. - Expand the Earnings group, check
earnings.created, click Add destination. - The new row appears with a truncated signing secret (
whsec_...). Click the row to expand it, then click Reveal next to the signing secret and copy the full value. You’ll plug it into the receiver in the next step.
Treat your signing secret like a credential. Store it in a secret manager (not git, not your
.env checked into source control), and rotate it from the dashboard if it ever leaks.Step 2: Spin up a receiver
The receiver does three things: read the raw request body, verify theFD-Signature header, and return 2xx.
- Python (Flask)
- Node (Express)
Install Flask:Save as Run it:Then expose it via a tunnel for the dashboard to reach:
receiver.py:Step 3: Fire a test event
Back in the dashboard:- Find your destination row and click it to expand.
- Click Send test event.
- Within ~5 seconds your receiver should log two lines and the event should appear in Recent events with a green checkmark and HTTP
200.
BLDR, which isn’t on Acme’s watchlist — so it goes through the verify-and-skip branch. Once real earnings.created events for AAPL, MSFT, or NVDA arrive, the handler will hit the 🔔 watchlist hit branch instead.
Test events have livemode: false and use a canned earnings.created payload — useful for confirming the wiring before real data flows.
Step 4: Inspect a delivery
Click any row in Recent events to slide up the detail drawer. You’ll see:- Request: event type, event id, endpoint URL, attempt number, timestamps.
- Response: HTTP status, duration, body returned by your endpoint.
- Signed payload: the exact JSON we POSTed, ready to copy or download as
.jsonfor replaying in your local tests.
Step 5: Replay a delivery
From the detail drawer, click Replay delivery. We’ll re-send the same event payload through the full delivery pipeline (signed with your current secret) and create a new row in Recent events with attempt number 1. The original row stays as a historical record. This is the fastest way to debug a handler fix — patch your code, deploy, hit Replay.Production checklist
Before flipping real customers onto your handler:- HTTPS endpoint. Required in production; we reject
http://URLs. - Return 2xx within 10s. Anything else counts as a failure. If real processing takes longer, enqueue to a background job and return
200immediately. - Dedupe on
event.id. Retries and replays mean the same id can arrive multiple times. A unique constraint on aprocessed_eventstable is the simplest reliable pattern. - Watch the auto-disable threshold. After 50 consecutive failed deliveries we automatically disable the destination to protect your endpoint. Catch issues earlier by monitoring the
Recent failuresfield on the destination row. - Rotate the signing secret if it leaks. Click Regenerate secret from the destination’s expanded row. The old secret stops working immediately, so deploy your config change in lockstep.
Common pitfalls
Signature mismatch on every request. You’re hashing the JSON-parsed body instead of the raw bytes. Read the raw request body before any framework middleware parses it (see therequest.get_data() / express.raw() calls in the samples above).
The 200 comes from your auth middleware, not your handler. If a reverse proxy or auth layer swallows the request and replies with its own 200, our worker sees success but your handler never runs. Check your access logs.
Timeouts on big handlers. Don’t process the entire downstream pipeline inside the webhook handler. Enqueue and acknowledge.
Clock drift. Our verification rejects timestamps more than 5 minutes off. If you keep failing right after a deploy, check NTP sync on your server.
Next steps
- Webhooks reference — full event catalog, payload envelope, retry semantics, and security model.
- Join the Discord if you hit something not covered here.