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 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
POSTonly. FastHook records disallowed methods as rejected requests and returns405. - 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.
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/sourcescreates a source. Sourcetypedefaults toWEBHOOK, and the response includes the generated sourceurl.config.auth_typecan benull,BASIC_AUTH,API_KEY, orHMAC. Authentication failures are recorded asSOURCE_AUTH_FAILEDand return401.config.allowed_http_methodsdefaults toPOST,PUT,PATCH, andDELETE. If you want a strict provider endpoint, set it to["POST"].- Disabled sources reject before queueing, record
SOURCE_DISABLED, and return410. Disallowed methods recordSOURCE_METHOD_NOT_ALLOWEDand return405. - A source can define
custom_responsewithcontent_typeofjson,text, orxml. The body is returned with200after acceptance and queueing. - HTTP destinations can use
FASTHOOK_SIGNATURE. FastHook signs deliveries withx-fasthook-timestampandx-fasthook-signature.
Webhook endpoint examples
Create a secure 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
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
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
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
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
{
"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
{
"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
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
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
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.