Webhook Guides

Webhook Endpoints Guide

A webhook endpoint is the public HTTP boundary that receives event callbacks. In FastHook, that inbound endpoint is a source URL such as https://hook-xxxxxx.fasthook.io/. Providers send requests to the source, FastHook captures the request, and connections route accepted events to destination endpoints.

Endpoint design matters because webhook delivery is usually at-least-once. Your endpoint strategy should handle allowed methods, source authentication, raw-body signatures, fast acknowledgment, durable request history, retries, duplicates, and replay.

What is a webhook endpoint?

A webhook endpoint is an HTTP URL that another system calls when an event happens. The provider sends method, headers, query parameters, and a payload. The receiver decides whether to accept, reject, verify, route, and process that event.

In a FastHook workflow, there are two endpoint boundaries. The source URL is the inbound endpoint that accepts provider traffic. The destination endpoint is your application URL that FastHook calls after routing an accepted request through a connection.

Webhook endpoint boundaries showing provider, FastHook source URL, request capture, connections, and application destination endpoint.
FastHook separates provider ingress from application delivery. The source endpoint handles provider-facing concerns; the destination endpoint handles your application contract.

Webhook endpoint requirements

  • Stable URL: providers need a durable source URL that does not change every time local or staging infrastructure changes.
  • Allowed methods: public provider endpoints usually accept POST only. FastHook records disallowed methods as rejected requests and returns 405.
  • Authentication: sources can use no auth, Basic Auth, API key headers, or HMAC over the raw request body.
  • Fast acknowledgment: accept and queue the request quickly, then process downstream work through routed events and attempts.
  • Observability: keep request, event, attempt, response body, retry, and replay evidence visible together.
  • Idempotency: use event ids, delivery ids, or business object ids so retries do not apply side effects twice.
Webhook endpoint security contract covering allowed methods, source auth, raw body signatures, custom responses, rejected requests, and destination signatures.
Endpoint security is a contract. Reject bad ingress before queueing, store rejected evidence for debugging, and sign outbound deliveries to your application destination.

FastHook endpoint behavior

These examples match the current FastHook API implementation. Control API calls use a project API key or session token, tenancy is selected with x-team-id, and the examples use the /v1 prefix for sources, destinations, connections, and requests.

  • POST /v1/sources creates a source. Source type defaults to WEBHOOK, and the response includes the generated source url.
  • config.auth_type can be null, BASIC_AUTH, API_KEY, or HMAC. Authentication failures are recorded as SOURCE_AUTH_FAILED and return 401.
  • config.allowed_http_methods defaults to POST, PUT, PATCH, and DELETE. If you want a strict provider endpoint, set it to ["POST"].
  • Disabled sources reject before queueing, record SOURCE_DISABLED, and return 410. Disallowed methods record SOURCE_METHOD_NOT_ALLOWED and return 405.
  • A source can define custom_response with content_type of json, text, or xml. The body is returned with 200 after acceptance and queueing.
  • HTTP destinations can use FASTHOOK_SIGNATURE. FastHook signs deliveries with x-fasthook-timestamp and x-fasthook-signature.

Webhook endpoint examples

Create a secure source endpoint

Create source endpoint
curl -X POST "https://api.fasthook.io/v1/sources" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_3b5335b627084a838b" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Orders source",
    "description": "Provider order webhook ingress",
    "type": "WEBHOOK",
    "status": "enabled",
    "config": {
      "auth_type": "HMAC",
      "auth": {
        "secret": "provider_webhook_secret",
        "signature_header": "x-hub-signature-256",
        "prefix": "sha256="
      },
      "allowed_http_methods": ["POST"],
      "custom_response": {
        "content_type": "json",
        "body": "{\"ok\":true,\"queued\":true}"
      }
    }
  }'

Create the destination endpoint FastHook will call

Create destination endpoint
curl -X POST "https://api.fasthook.io/v1/destinations" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_3b5335b627084a838b" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Orders API",
    "type": "HTTP",
    "config": {
      "url": "https://api.example.com/webhooks/orders",
      "path": null,
      "rate_limit": null,
      "rate_limit_period": "second",
      "http_method": "POST",
      "path_forwarding_disabled": false,
      "auth_type": "FASTHOOK_SIGNATURE",
      "auth": {}
    }
  }'

Connect the source to the destination

Create connection
curl -X POST "https://api.fasthook.io/v1/connections" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_3b5335b627084a838b" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "orders-to-api",
    "source_id": "src_q6z62b6py5o79b",
    "destination_id": "des_TU9ioCk5EHUU",
    "disabled_at": null,
    "paused_at": null,
    "rules": [
      {
        "type": "retry",
        "strategy": "exponential",
        "count": 3,
        "interval": 60000,
        "response_status_codes": ["500-599", "429"]
      }
    ]
  }'

Send a signed provider webhook to the source URL

Send signed webhook
import crypto from "node:crypto";

const sourceUrl = "https://hook-xxxxxx.fasthook.io/";
const secret = "provider_webhook_secret";
const payload = JSON.stringify({
  id: "evt_9283",
  type: "order.created",
  created_at: "2026-05-31T10:00:00Z",
  data: {
    order_id: "ord_102",
    customer_id: "cus_88"
  }
});

const signature = "sha256=" + crypto
  .createHmac("sha256", secret)
  .update(payload)
  .digest("hex");

await fetch(sourceUrl, {
  method: "POST",
  headers: {
    "content-type": "application/json",
    "x-hub-signature-256": signature
  },
  body: payload
});

Verify FastHook delivery signatures at your destination

Verify destination signature
import crypto from "node:crypto";

function verifyFastHookSignature({ rawBody, timestamp, signature, signingSecret }) {
  const expected = "v1=" + crypto
    .createHmac("sha256", signingSecret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  const actualBytes = Buffer.from(signature);
  const expectedBytes = Buffer.from(expected);

  return actualBytes.length === expectedBytes.length &&
    crypto.timingSafeEqual(actualBytes, expectedBytes);
}

// FastHook sends:
// x-fasthook-timestamp: Unix timestamp in seconds
// x-fasthook-signature: v1=<hex-hmac-sha256>

Common source authentication configs

Source auth configs
{
  "no_auth_for_local_tests": {
    "auth_type": null,
    "allowed_http_methods": ["POST"]
  },
  "basic_auth": {
    "auth_type": "BASIC_AUTH",
    "auth": {
      "username": "provider",
      "password": "secret"
    },
    "allowed_http_methods": ["POST"]
  },
  "api_key_header": {
    "auth_type": "API_KEY",
    "auth": {
      "header_name": "x-api-key",
      "value": "provider-api-key"
    },
    "allowed_http_methods": ["POST"]
  },
  "hmac_raw_body": {
    "auth_type": "HMAC",
    "auth": {
      "secret": "provider_webhook_secret",
      "signature_header": "x-provider-signature",
      "timestamp_header": "x-provider-timestamp",
      "prefix": "v1="
    },
    "allowed_http_methods": ["POST"]
  }
}

Example webhook payload

Endpoint payload
{
  "id": "evt_9283",
  "type": "order.created",
  "created_at": "2026-05-31T10:00:00Z",
  "data": {
    "order_id": "ord_102",
    "customer_id": "cus_88",
    "total": 4900,
    "currency": "USD"
  }
}

Test method rejection

Method rejection
curl -i -X GET "https://hook-xxxxxx.fasthook.io/"

# If the source only allows POST, FastHook records a rejected request
# with SOURCE_METHOD_NOT_ALLOWED and returns HTTP 405.

Inspect rejected endpoint traffic

Inspect rejected requests
curl "https://api.fasthook.io/v1/requests?source_id=src_q6z62b6py5o79b&status=rejected&from=now-24h&to=now&limit=20&include=data" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_3b5335b627084a838b"

Inspect accepted endpoint traffic

Inspect accepted requests
curl "https://api.fasthook.io/v1/requests?source_id=src_q6z62b6py5o79b&status=accepted&from=now-24h&to=now&limit=20&include=data" \
  -H "Authorization: Bearer fhp_xxx" \
  -H "x-team-id: tm_3b5335b627084a838b"

Endpoint design checklist

  • Use separate source URLs and secrets for local, staging, and production.
  • Restrict public provider sources to the HTTP methods the provider actually uses.
  • Verify HMAC signatures against the raw body, not parsed and re-serialized JSON.
  • Return quickly after acceptance and keep downstream work observable through events and attempts.
  • Use destination signatures so your application can verify traffic came from FastHook.
  • Use idempotency keys before creating invoices, orders, deployments, messages, or other external effects.
  • Inspect rejected requests when providers report delivery problems but no routed event appears.

Webhook endpoints FAQ

What is a webhook endpoint?

A webhook endpoint is an HTTP URL that receives event callbacks. In FastHook, the inbound webhook endpoint is a source URL, and downstream receiver URLs are configured as destination endpoints.

Should a webhook endpoint return 200 before processing is complete?

A source endpoint should acknowledge only after the request is accepted for durable processing. Expensive receiver work should happen after capture so provider timeouts do not hide downstream failures.

How should webhook endpoints be secured?

Use source authentication where the provider supports it, restrict allowed HTTP methods, verify HMAC signatures against the raw request body, and use separate endpoints and secrets for local, staging, and production.

What is the difference between a source URL and a destination endpoint?

A source URL receives webhooks from providers. A destination endpoint is your application URL that FastHook calls after routing an accepted request through a connection.

Try FastHook

Create a source URL, configure authentication and allowed methods, connect it to a destination endpoint, send a signed test event, and inspect accepted or rejected requests in one place.

Related guides