Guide

Avoid Webhook DDoS

Webhook traffic can look like a DDoS when providers retry aggressively, bulk imports emit thousands of events, or operators replay too much traffic into a fragile receiver.

FastHook helps by accepting ingress separately from delivery, then letting each destination branch shape, pace, pause, or replay outbound traffic.

This guide is about preventing webhook delivery pressure from overwhelming your receivers. FastHook is not a replacement for an edge WAF or abuse firewall, but it gives operators source gates, branch-local controls, destination limits, retry backoff, bulk operation safety, and metrics.

Where Pressure Enters

Start by naming the pressure source. A provider burst, an auth failure loop, a destination outage, and a too-broad replay need different controls. The safest control is the smallest one that stops the pressure without hiding evidence.

  • Provider retries after receiver timeouts.
  • Bulk provider jobs that send many events at once.
  • Internal producers with no backpressure.
  • Operators replaying a large failed window.
  • Noisy event types sent to destinations that do not need them.
  • A disabled or unhealthy receiver causing automatic retry backlogs.
Control pressure at the narrowest boundary: source, connection, destination, retry, or bulk recovery.

Choose The Smallest Control

Do not disable a shared source just because one downstream consumer is unhealthy. In FastHook, source, connection, and destination controls have different blast radii.

  • Source auth and allowed_http_methods reject bad ingress before events are created.
  • Source disable stops that source URL and disables related connections; use it as an emergency ingress brake.
  • Connection pause holds new routed events as HOLD for that branch without stopping other branches.
  • Connection disable stops future routing for that branch.
  • Destination rate_limit paces delivery attempts to the receiver.
  • Destination disable is useful during receiver maintenance when delivery should stop at the target boundary.
Prefer branch-local controls before disabling a shared source or destination.

Harden The Source Boundary

Source controls are for ingress. They stop traffic before route rules, destination rate limits, and retries can matter. Use them for public production sources, but keep the provider contract clear so legitimate retries are not rejected by mistake.

  • Use HMAC, API_KEY, or BASIC_AUTH when the provider supports it.
  • Keep allowed_http_methods to the provider's real method, usually POST.
  • Watch rejected request metrics for SOURCE_AUTH_FAILED or SOURCE_METHOD_NOT_ALLOWED patterns.
  • Disable the source only when ingress itself must stop.
Source boundary
curl -X PATCH "https://api.fasthook.io/v1/sources/src_xxx" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "auth_type": "HMAC",
      "auth": {
        "secret": "whsec_provider_secret",
        "signature_header": "x-provider-signature",
        "timestamp_header": "x-provider-timestamp",
        "prefix": "sha256="
      },
      "allowed_http_methods": ["POST"]
    }
  }'

curl -X POST "https://api.fasthook.io/v1/sources/src_xxx/disable" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx"

Connection Rules For Noisy Traffic

Most DDoS-like webhook pressure should be reduced before it reaches the receiver. Put filtering and deduplication on the connection that needs the protection, not on every consumer of the source.

A connection owns the branch from one source to one destination. That makes it the right place to drop irrelevant event types, suppress duplicates, delay low-priority delivery, and back off retryable failures for that receiver.

  • Use filters to remove low-value event types before delivery.
  • Split consumers into separate connections so one receiver can be protected without slowing every branch.
  • Use deduplicate when provider retries can repeat the same business event.
  • Use retry backoff for temporary 429 and 5xx failures.
  • Pause one connection when a receiver is unhealthy; new routed events stay in HOLD.
Connection protection
curl -X PATCH "https://api.fasthook.io/v1/connections/web_xxx" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": [
      {
        "type": "filter",
        "body": { "type": "invoice.paid" }
      },
      {
        "type": "deduplicate",
        "window": 300000,
        "include_fields": ["body.id"]
      },
      {
        "type": "retry",
        "strategy": "exponential",
        "interval": 30000,
        "count": 5,
        "response_status_codes": ["429", "500-599", "!501"]
      }
    ],
    "paused_at": null,
    "disabled_at": null
  }'

curl -X PUT "https://api.fasthook.io/v1/connections/web_xxx/pause" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx"

Set Destination Capacity

Destination rate limits are the main control for protecting a receiver with known capacity. The dashboard exposes this as Max delivery rate. In the API, set config.rate_limit and config.rate_limit_period on the destination.

When destination capacity is exhausted, delivery waits for a later slot instead of hammering the receiver immediately. In event views, scheduled work can come from retry backoff, delay rules, or destination throughput limits.

  • Use rate_limit: null to remove the limit.
  • Supported periods are second, minute, hour, and day.
  • Use a low limit before unpausing a large backlog.
  • Disable the destination during maintenance if attempts should stop entirely.
In the current Structured Connections UI, edit the destination and enable Max delivery rate to write config.rate_limit and config.rate_limit_period.
Destination capacity
curl -X PATCH "https://api.fasthook.io/v1/destinations/des_xxx" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "url": "https://api.example.com/webhooks",
      "http_method": "POST",
      "rate_limit": 60,
      "rate_limit_period": "minute",
      "auth_type": "FASTHOOK_SIGNATURE",
      "auth": {}
    }
  }'

curl -X POST "https://api.fasthook.io/v1/destinations/des_xxx/disable" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx"

Replay Safely

Recovery can create a second incident if the replay is broader than the outage. Build the bulk operation from the same evidence you used in list and metrics queries: from, to, status, source_id, connection_id, destination_id, and optional q.

  • Filter bulk retries by destination, connection, status, and time range.
  • Set or lower destination rate limits before replaying.
  • Watch metrics by batch_operation_id during recovery.
  • Cancel a bulk operation if the receiver starts failing again.
  • Keep receivers idempotent so repeated events are safe.
Do one event retry first, then bulk retry the smallest failed window that actually needs recovery.
Event bulk retry
curl -X POST "https://api.fasthook.io/v1/events/bulk_operations" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "2026-05-29T10:00:00.000Z",
    "to": "2026-05-29T10:30:00.000Z",
    "status": "FAILED",
    "source_id": "src_xxx",
    "connection_id": "web_xxx",
    "destination_id": "des_xxx",
    "q": "timeout"
  }'

curl -X POST "https://api.fasthook.io/v1/events/bulk_operations/bch_xxx/cancel" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx"

Request Retry Versus Event Retry

Use the retry path that matches the failure. Request retry replays inbound requests through current routing, so it can create new branch events. Event retry targets existing destination-specific events. During receiver pressure, event retry is usually safer because it does not re-run the whole route graph.

  • Use request bulk retry for rejected or accepted ingress that needs to be routed again.
  • Use event bulk retry for failed destination delivery on a known branch.
  • Bulk retry targets failed or cancelled events; held events are released by unpausing the connection.
  • Retry one event before creating a large bulk operation.
  • Keep idempotency in the receiver because any retry can duplicate business work.

Signals To Watch

Use metrics to decide whether pressure is at ingress or delivery. Request metrics answer whether providers are sending and whether FastHook is accepting or rejecting. Event metrics answer whether branches are delivered, failed, queued, processing, held, or ignored.

  • Request volume by source: count, accepted_count, and rejected_count.
  • Event pressure by destination or connection: delivered_count, failed_count, queued_count, processing_count, hold_count, and ignored_count.
  • Attempt responses by event_id for receiver status codes, latency, and body.
  • batch_operation_id during bulk retry recovery.
  • Destination attempts_24h_count and bins in the Destinations view.
  • Connection events_24h metrics in the Connections view.
If accepted_count rises but delivered_count stalls, protect the destination branch before retrying more traffic.
Pressure metrics
curl "https://api.fasthook.io/v1/metrics/requests?date_range[start]=2026-05-29T10:00:00Z&date_range[end]=2026-05-29T10:30:00Z&granularity=1m&source_id=src_xxx&measures[]=count&measures[]=accepted_count&measures[]=rejected_count" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx"

curl "https://api.fasthook.io/v1/metrics/events?date_range[start]=2026-05-29T10:00:00Z&date_range[end]=2026-05-29T10:30:00Z&granularity=1m&destination_id=des_xxx&measures[]=delivered_count&measures[]=failed_count&measures[]=queued_count&measures[]=hold_count&measures[]=ignored_count" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_xxx"

Incident Runbook

During a live pressure event, preserve evidence before changing state. Then use the narrowest control, verify the effect in metrics, and only replay after the receiver is stable.

  • Identify source_id, connection_id, destination_id, status, and affected time window.
  • If traffic is forged or malformed, fix source auth or methods; disable source only if ingress must stop.
  • If one receiver is unhealthy, pause the connection or lower destination rate_limit.
  • If all traffic to a destination is unsafe, disable the destination temporarily.
  • After recovery, unpause with a rate limit and watch HOLD, SCHEDULED, FAILED, and delivered counts.
  • Run one manual event retry, then a narrow event bulk retry.

Common Mistakes

  • Disabling a shared source when only one destination branch is unhealthy.
  • Bulk retrying every failed event before lowering the destination rate limit.
  • Retrying requests when only existing destination events failed.
  • Leaving broad provider event streams unfiltered for receivers that need one event type.
  • Treating 429 as permanent failure instead of backing off.
  • Unpausing a large HOLD backlog without watching event metrics.
  • Skipping receiver idempotency because FastHook deduplication is configured.

Prevention Checklist

  • Every public production source has auth configured and only required methods enabled.
  • Each downstream consumer has its own connection branch.
  • Noisy providers have filter rules for event type, path, query, or headers.
  • Provider event ids are included in deduplication keys when available.
  • Every constrained receiver has a destination rate_limit.
  • Retry rules use backoff for 429 and 5xx classes.
  • Bulk retry runbooks include from, to, status, source_id, connection_id, destination_id, and a cancel step.
  • Metrics dashboards compare request accepted_count with event delivered_count, failed_count, queued_count, and hold_count.

Next