Direct Answer

Direct answer: A webhook is an HTTP callback your server registers with a trading platform so the platform can push event data to you, order fills, price alerts, account status changes, without you polling for updates. Reliable webhook integrations require three things: verifying the request signature so only genuine platform events are processed, designing handlers that are idempotent so duplicate deliveries produce no extra side effects, and maintaining a replay mechanism so events that arrive out of order or during downtime can be reprocessed safely.

Key takeaways

  • Webhooks are push, not pull: The platform sends HTTP POST requests to your endpoint when events occur; your server does not poll. This reduces latency compared to repeated polling but shifts reliability responsibility to your endpoint.
  • Signature verification is mandatory: Every incoming webhook should be validated against an HMAC signature computed from a shared secret before your handler acts on the payload. Skip this and any external party can spoof trading events to your server.
  • Idempotency is not optional: Platforms retry failed deliveries. If your handler places an order on every invocation, a retry will double the order. Design handlers so processing the same event ID twice produces the same outcome as processing it once.
  • Delivery order is not guaranteed: A fill event can arrive before the corresponding order-accepted event. Handlers must tolerate gaps and apply events against a state machine rather than assuming strict sequence.
  • Timeouts cause silent failures: If your endpoint takes longer than the platform's timeout window (often 5-30 seconds) to respond, the platform records a failure and retries, even if your handler eventually completed the work. Respond with HTTP 200 quickly and process asynchronously.
  • Test without live credentials: Use a local tunneling tool or a dedicated test environment with dummy events to verify your handler logic before exposing a live account to webhook traffic.
  • Replay windows have an expiry: Most platforms store failed events for a fixed window (24 hours to 7 days). If your server is down longer than the replay window, those events are permanently unavailable, plan for this in your incident response runbook.

Core concepts and design choices

1. What a webhook is, and what it is not

A webhook is a user-defined HTTP callback. When you register an endpoint URL with a trading platform, the platform stores it and issues an HTTP POST to that URL whenever a matching event occurs. The body of the POST contains a structured event payload, typically JSON, describing what happened, when it happened, and which account or instrument was affected.

Webhooks are sometimes called "reverse APIs" because the data flow runs opposite to a standard REST call: instead of your code calling the platform, the platform calls your code. This is significant for latency-sensitive workflows: a polling loop that checks every five seconds misses events that happen between checks, whereas a webhook fires within milliseconds of the event.

What webhooks are not: They are not a streaming protocol. Each event is a discrete HTTP request; there is no persistent connection. For continuous market data feeds (tick-by-tick prices, order book depth), a WebSocket or FIX connection is the appropriate choice. Webhooks are designed for discrete, lower-frequency events, fills, alerts, account changes, not for ingesting every price update on a liquid instrument.

2. Signature verification

When a platform sends a webhook, it typically includes a signature header, for example, X-Signature-256, computed by applying HMAC-SHA256 to the raw request body using a shared secret that only your account and the platform know. Your handler must recompute this signature from the raw body and compare it to the header before acting on the payload.

The comparison must be constant-time. A naive string equality check (a == b) returns early on the first mismatching character, creating a timing side-channel that could theoretically be exploited to brute-force the signature. Use your language's built-in constant-time comparison function (for example, hmac.compare_digest in Python or crypto.timingSafeEqual in Node.js).

What this means in practice: Parse the raw body bytes before JSON-decoding. If you decode first and re-encode the payload to compute the signature, whitespace normalization or key reordering in your JSON library can silently break signature validation even when the event is genuine. Most platform SDKs handle this correctly; if you implement verification manually, test against a known-good event from the platform's documentation.

Common error: Silently ignoring signature validation failures in development and forgetting to re-enable it before going live. Use a feature flag or environment variable that defaults to enforced validation, and require an explicit override to disable it in non-production environments.

3. Idempotency and event IDs

Platforms guarantee at-least-once delivery, not exactly-once. A network error during your response, a timeout, or a platform retry policy means the same event can arrive multiple times. If your handler places a market order or records a journal entry each time it runs, duplicate deliveries cause real financial and data problems.

The solution is idempotency: your handler checks whether it has already successfully processed the event ID before doing any side-effectful work. The event ID is typically a UUID included in every webhook payload. Store processed event IDs in a durable store, a database table, a Redis set with TTL, or a similar mechanism, and skip or acknowledge events whose IDs already appear in that store.

What this means in practice: Respond with HTTP 200 to duplicates as well as to genuinely new events. Some platforms interpret a non-2xx response as a failure and retry indefinitely. If you return 409 Conflict for a duplicate, you may trigger unnecessary retries.

TTL consideration: Event IDs do not need to be stored forever. If the platform's retry window is 72 hours, storing IDs for 7 days gives you a safe margin. After that, the probability of a genuinely duplicate late delivery is negligible, and purging old records keeps the idempotency store small.

4. Out-of-order delivery and state machines

HTTP delivery order is not guaranteed. A platform may emit an order.filled event before the corresponding order.accepted event arrives, particularly if the two events pass through different internal queues. Your handler must not assume that earlier events have already been applied.

The robust pattern is to model account and order state as an explicit state machine. When an event arrives, apply it to the stored state regardless of sequence, the state machine's transition rules determine whether the event is valid for the current state, needs to be queued for later application, or can be discarded as superseded. This is functionally similar to event sourcing in distributed systems design.

Practical minimum: At minimum, track an order's lifecycle (submitted, accepted, partially filled, filled, cancelled) in your database and apply each incoming event as an update rather than an insert. An order.filled that arrives before order.accepted should upsert the order record and transition it directly to the filled state, trusting the fill event's data over the expected sequence.

5. Respond fast, process asynchronously

Trading platform webhooks typically have short timeout windows, often 5, 10, or 30 seconds. If your endpoint does not respond within the window, the platform logs a delivery failure and schedules a retry, even if your handler eventually completes the work. The retry may arrive before or after your original handler finishes, creating a race condition.

The solution is to separate acknowledgment from processing. Your endpoint should immediately write the raw event to a queue or durable store, return HTTP 200, and then process the event asynchronously in a background worker. This pattern decouples network latency from processing latency and gives you a natural retry point if the background processing fails.

Queue choices: For small-scale setups, a database-backed queue (an unprocessed-events table with a worker polling it) is simple and auditable. For higher throughput, a dedicated message broker (RabbitMQ, AWS SQS, Redis Streams) provides better isolation. The right choice depends on your event volume and operational complexity tolerance.

6. Replay mechanics and incident recovery

Most platforms provide a webhook delivery log in their developer dashboard or via an API endpoint. When your server experiences downtime, you can query the delivery log for events that arrived during the outage and replay them against your handler.

Replay is only safe if your handler is idempotent. Without idempotency, replaying 200 missed events could submit 200 duplicate orders or record 200 duplicate journal entries.

Replay window expiry: Platforms do not store delivery logs indefinitely. Common windows range from 24 hours to 7 days. If your server is down for longer, or if you need to reconstruct state from further back, you must fall back to reconciling against the REST API, fetching your order history, positions, and account activity directly from the platform and comparing them against your local records.

Incident runbook requirement: Document the replay procedure before you need it. Under incident pressure, referring to a pre-written step-by-step procedure is far less error-prone than improvising against an unfamiliar delivery log UI.

7. Testing without live credentials

Testing webhook handlers requires simulating inbound HTTP requests to your endpoint. Several approaches work without touching a live account:

Local tunneling: Tools like ngrok or similar create a temporary public URL that forwards requests to your local development server. You register this URL as your webhook endpoint in the platform's sandbox environment, then trigger test events from the sandbox dashboard. The tunnel forwards each request to your localhost handler, and you can inspect the full request/response cycle in the tool's web UI.

Synthetic payloads: Capture a real event payload from the platform's documentation or from a sandbox delivery, and write unit tests that POST this payload directly to your handler function. Sign the payload with your test secret so signature verification passes. This approach does not require a live connection to the platform and runs entirely in CI.

Platform test mode: Some brokers and data providers offer an explicit test-mode webhook that sends artificial fill events, price alerts, or account updates on demand. Check whether your platform provides this before setting up a tunneling workflow.

8. Security surface and common mistakes

Webhook endpoints are public HTTP endpoints. Without proper controls, they are an attack vector. Beyond signature verification, consider the following:

IP allowlisting: If the platform publishes a known list of IP addresses from which webhooks will originate, add them to your server's allowlist. This is a defense-in-depth measure; it supplements signature verification rather than replacing it, because IP ranges can change and dynamic cloud egress does not always come from a stable range.

Rate limiting: A malicious actor who discovers your endpoint URL can flood it with requests. Apply rate limiting at the load balancer or application layer to prevent a flood of invalid requests from consuming server resources or triggering handler logic for unsigned events.

Logging and alerting: Log every incoming webhook, event type, event ID, timestamp, signature validity, and processing outcome. Set alerts for elevated rates of signature failures (which may indicate a secret rotation problem or an active spoofing attempt) and for processing failures (which may indicate a downstream dependency outage).

Worked example: order-fill webhook handler

Suppose a broker sends a POST to your /webhooks/broker endpoint when an order is filled. The payload is JSON containing event_id, event_type (order.filled), order_id, symbol, quantity, fill_price, and filled_at. The broker signs the request with an HMAC-SHA256 header.

Smartphone displaying VISA on a laptop for online shopping experience.
Photo by Julio Lopez via Pexels

A correct handler does the following, in order: (1) reads the raw request body before JSON-parsing; (2) extracts the signature header; (3) recomputes the expected signature using the raw body and the shared secret; (4) compares signatures using constant-time comparison, if they do not match, returns HTTP 401 and logs the failure; (5) checks the idempotency store for event_id, if already present, returns HTTP 200 immediately; (6) writes the raw event to the processing queue and inserts event_id into the idempotency store atomically; (7) returns HTTP 200.

The background worker then applies the fill: locates or creates the order record, transitions its state to filled, records the fill price and quantity, and triggers any downstream actions (portfolio position update, P&L calculation, journal entry). If the background worker fails, the idempotency record is not marked complete, and the next delivery of the same event retriggers processing. The queue and idempotency store together implement at-least-once processing with controlled retry behavior.

Frequently Asked Questions

What is the difference between a webhook and a REST API poll for trading events?

With a REST poll, your code initiates an HTTP request to the platform on a schedule and checks for new events. With a webhook, the platform initiates an HTTP request to your endpoint whenever an event occurs. Polling introduces latency equal to your poll interval and wastes requests when nothing has changed. Webhooks are lower latency and more efficient for event-driven workflows, but require your server to be reachable and to respond correctly. Polling is simpler to implement and does not require an internet-accessible endpoint, making it a reasonable fallback for development or low-frequency use cases.

What happens if my webhook endpoint is down when an event is sent?

The platform records a delivery failure and retries according to its retry schedule, typically with exponential backoff over a window of hours. Events that cannot be delivered within the retry window are dropped and will not be retried further. You can recover missed events by querying the platform's delivery log via its dashboard or API and manually replaying them against your handler, provided your handler is idempotent. If your endpoint is down for longer than the retry window, you must reconcile state by fetching your order and account history directly from the REST API.

How do I verify a webhook signature in practice?

Read the raw request body as bytes before JSON-decoding it. Extract the platform's signature header (the header name varies by platform, for example X-Broker-Signature). Compute HMAC-SHA256 of the raw body bytes using your shared webhook secret as the key. Compare the computed signature to the header value using a constant-time comparison function. If they match, the event is authentic. If they do not match, return HTTP 401 and log the mismatch. Do not process the payload. Never decode the body to JSON before computing the signature, as re-serialization can change whitespace and break the hash.

Why is idempotency so important for webhook handlers?

Platforms guarantee at-least-once delivery, meaning the same event may arrive more than once due to network errors, timeouts, or platform retries. If your handler places an order, records a trade, or sends a notification on every invocation, duplicate deliveries will cause duplicate orders, incorrect P&L records, or repeated alerts. Idempotency means designing your handler so that processing the same event ID twice produces the same final state as processing it once. The standard implementation is to store processed event IDs in a durable store and skip side effects for IDs already present.

Can I receive webhook events out of order, and how should I handle that?

Yes. HTTP delivery order is not guaranteed. A fill event can arrive before the corresponding order-accepted event, particularly when events pass through different internal queues on the platform side. Design your handler to apply events to a state machine rather than assuming a strict sequence. When an event arrives, apply it to the current stored state regardless of what has come before. Use upsert operations rather than inserts so that a later event for an order that does not yet exist in your database creates the record in the appropriate terminal state rather than failing.

What is the safest way to test a webhook handler before going live?

Use a combination of synthetic payload unit tests and a local tunnel. For unit tests, capture a real event payload from the platform's sandbox or documentation, sign it with your test secret, and POST it directly to your handler function, no internet connection required. For end-to-end testing, use a tunneling tool such as ngrok to expose your local development server on a public URL, register that URL as your webhook endpoint in the platform's sandbox environment, and trigger test events from the sandbox dashboard. Verify that your signature check, idempotency logic, and state transitions all behave correctly before pointing a live account at the endpoint.

How long does a typical platform store undelivered webhook events for replay?

Retention windows vary by platform. Common windows range from 24 hours to 7 days. Some platforms provide a delivery log API you can query programmatically; others only expose the log through their developer dashboard. If your server is down for longer than the retention window, missed events are permanently unavailable from the webhook delivery system and you must reconcile state by querying the platform's REST API for order history, account activity, and position data. Document your fallback reconciliation procedure in an incident runbook before you need it.

Should I use IP allowlisting as a security control for my webhook endpoint?

IP allowlisting is a useful defense-in-depth measure, but it should not replace signature verification. Allowlisting blocks traffic from unexpected sources, reducing the attack surface, but platform IP ranges can change and dynamic cloud infrastructure does not always originate from stable ranges. Treat allowlisting as a secondary control and signature verification as the primary trust mechanism. Combine both with rate limiting to prevent flood attacks from unknown sources that somehow bypass the allowlist, and log all signature validation failures so that a pattern of invalid requests triggers an alert before it causes harm.

How quickly does a webhook endpoint need to respond, and what happens if processing is slow?

Senders generally apply a short timeout and treat a slow response as a failure, scheduling a retry. An endpoint that performs its full processing before responding therefore risks being retried while the first attempt is still working, producing exactly the duplicate the retry was meant to avoid. The usual pattern is to verify the signature, persist the raw event, respond immediately, and process asynchronously. That keeps the response inside the timeout regardless of how long the downstream work takes.

References

Educational disclaimer

For education only; not personalized investment, tax, or legal advice. Trading can result in substantial losses.

Broker rules, API behavior, platform policies, and security recommendations can change. Verify current requirements with your broker, platform, or a qualified technical or financial professional before acting. Code examples are illustrative and not production-ready without independent review and testing.