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.
Overview
Instead of polling our API for new data, you can register an HTTPS endpoint and we’ll POST to it the moment an event fires. Use webhooks to wake up an agent on a fresh earnings release, push records into your warehouse, or trigger downstream automation.New to webhooks? The setup guide walks you through a working Python receiver end-to-end in under 15 minutes. This page is the reference you’ll come back to once you’re integrated.
How it works
Five steps to get from zero to receiving events:Create a destination
Register an HTTPS endpoint and the events you want to receive from the Webhooks dashboard.
Set up your endpoint
Stand up an HTTPS handler that can accept JSON POSTs and read the raw request body. See the setup guide for Python + Node examples.
Verify the signature
Confirm each request came from us using the
FD-Signature header. See Verifying the signature.Test with a canned event
Fire a test event from the dashboard’s destination row and confirm your endpoint returns
2xx within 10 seconds.Go live
Walk through the production checklist before flipping real customer flows onto your handler.
Webhooks are available on Pro and Enterprise plans. Manage your plan from the dashboard.
Production checklist
Before relying on webhooks for production-critical flows, work through each of these:- Use HTTPS, not HTTP. Your endpoint URL must start with
https://. We won’t deliver to plainhttp://in production. Security → - Confirm each request actually came from us. Use the
FD-Signatureheader to check authenticity. Skip this and anyone could forge events. How to verify → - Reply within 10 seconds. Send back
200 OKquickly, then do the heavy work in the background. Slow replies count as failures and we’ll retry. Retries → - Don’t process the same event twice. We may deliver the same event more than once. Track which
event.idvalues you’ve handled and skip duplicates. Idempotency → - Keep your signing secret safe. Treat it like a password — never commit it to git, store it in a secret manager, and rotate it from the dashboard if it ever leaks. Security →
Payload format
Every delivery is aPOST of a JSON envelope wrapping a resource. The envelope itself is identical across event types; data.object carries the resource and its shape depends on the event type.
Envelope
| Field | Type | Description |
|---|---|---|
id | string (UUID) | The event id. Use this for idempotency / deduplication. |
type | string | The event type, e.g. earnings.created. |
api_version | string | The API version pinned on your destination (date-stamped). |
livemode | boolean | false for test events fired from the dashboard, true for production. |
created | integer | Unix timestamp (seconds) of when we recorded the event. |
data.object | object | The resource payload — shape depends on type. See below. |
earnings.created resource
The data.object is identical to a single entry from the GET /earnings/ API response. Any parser you’ve written against the Earnings API will work unchanged against the webhook payload.
See the Earnings API reference for the full field schema, types, and worked examples — we don’t duplicate it here so the two stay in lockstep.
Here’s an example envelope wrapping a single entry:
Headers
Every request includes:| Header | Value |
|---|---|
Content-Type | application/json |
User-Agent | FinancialDatasets-Webhook/1.0 |
FD-Signature | t=<unix-ts>,v1=<hex-hmac-sha256> |
Verifying the signature
TheFD-Signature header lets you confirm the request actually came from us and wasn’t tampered with. The signature is an HMAC-SHA256 of {timestamp}.{raw_body} using your destination’s signing secret.
- Python
- Node
hmac.compare_digest / crypto.timingSafeEqual) — a normal == is vulnerable to timing attacks.
Retries
A delivery succeeds when your endpoint returns any2xx response within 10 seconds. Anything else — a 4xx, a 5xx, a connection error, or a timeout — counts as a failure, and we’ll retry on this schedule:
| Attempt | When we try it |
|---|---|
| 1 | Immediately, as soon as the event fires. |
| 2 | About 1 minute after attempt 1 (±10s of jitter). |
| 3 | About 10 minutes after attempt 2 (±60s of jitter). |
Dead in the dashboard.
Idempotency
The sameevent.id can arrive more than once — replays, retries that succeed late, network races. Your handler must be idempotent:
- Dedupe on
id(e.g., insert into aprocessed_eventstable with a unique constraint and ignore conflicts). - Don’t trust delivery order; events for the same resource can interleave.
Test mode
The Send test event button on each destination row fires a canned event withlivemode: false. Useful for confirming your signature verification + 2xx response path before flipping the switch on production data.
Test events are throttled to 1 per minute per destination.
Security
- HTTPS only. We refuse to deliver to plain
http://URLs in production. - SSRF defense. We resolve your URL’s IP at every delivery attempt and reject private (RFC 1918), loopback, link-local, and metadata-service ranges.
- Signing-secret rotation. Use Regenerate secret on the destination’s row whenever you suspect a leak. The old secret stops working as soon as you rotate, so deploy the new secret to your handler in lockstep.
- Secret access. Re-copy your secret from the destination’s row in the dashboard if you misplace it. Retrieval is gated by your dashboard login; API keys cannot read signing secrets.
Limits
- 5 active destinations per account. Disable or delete unused ones to free up slots.
- One event type per destination today. The picker is single-select for now; we’ll widen to multi-select as we add more event types.
Troubleshooting
Destination keeps auto-disabling. Open the destination’s expanded row and checkRecent failures. Your endpoint is probably 5xx-ing or timing out beyond 10s. The fastest debug path is replaying a recent failed delivery from Recent events and inspecting the response body that came back.
Signature verification fails. Three usual suspects:
- You parsed the body before computing the HMAC. Always verify the raw bytes.
- The signing secret in your config is stale after a rotation. Re-copy from the dashboard.
- Your server has clock drift > 5 minutes. We reject signatures outside the skew window.
Active (not Disabled). Fire a test event from the row’s ⋯ menu — if that doesn’t arrive within ~5 seconds, the destination URL is unreachable from our network (check firewalls / IP allowlists).
Still stuck? Open a ticket via Support and include the destination id + a recent event id from the dashboard.
Next steps
- How to set up webhooks — step-by-step walkthrough with a working Python receiver.
- Open the Webhooks dashboard to create your first destination.