Webhook Guides
What Is a Webhook Endpoint?
A webhook endpoint is an HTTP URL that receives an automatic request when an event happens in another system. For example, Stripe can send an invoice.paid event to your endpoint as soon as a payment succeeds, without your application polling Stripe for updates.
The request normally contains an HTTP method, headers, query parameters, and a JSON payload. The endpoint verifies the sender, acknowledges the request, and starts or queues the work required by the event.
In FastHook, the provider-facing webhook endpoint is a source URL such as https://hook-xxxxxx.fasthook.io/. FastHook captures the original request before connections route accepted events to your destination endpoints.
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.
When someone asks for a webhook URL, they usually mean the provider-facing source URL. When they ask for the receiver endpoint, they usually mean the destination URL your application owns.
A practical webhook endpoint example
Suppose a payment provider needs to notify your application that an invoice was paid. You register a webhook endpoint with the provider, and it sends a request like this when the payment succeeds:
curl -X POST "https://hook-xxxxxx.fasthook.io/" \
-H "Content-Type: application/json" \
-H "X-Event-Type: invoice.paid" \
-d '{
"id": "evt_9283",
"type": "invoice.paid",
"data": {
"invoice_id": "in_102",
"customer_id": "cus_88",
"amount_paid": 4900
}
}'- The provider sends the event to the registered webhook endpoint.
- The endpoint validates the method, authentication, and signature.
- The request is acknowledged quickly after it is accepted for durable processing.
- The event is routed to the application that performs the business action.
- Failures remain visible and can be retried or replayed without asking the provider to resend the event.
Webhook endpoint vs webhook URL vs API endpoint
These terms overlap, but they describe different parts of an integration. The distinction is useful when configuring providers and debugging delivery failures.
| Term | What it means | Who initiates the request | Example |
|---|---|---|---|
| Webhook endpoint | The receiving HTTP handler for event callbacks. | The event provider. | /webhooks/stripe |
| Webhook URL | The complete public address registered with the provider. | The event provider. | https://example.com/webhooks/stripe |
| API endpoint | A URL exposed for clients to request data or run an operation. | Your application or API client. | POST /v1/invoices |
A webhook endpoint is technically an API endpoint, but its direction and trigger are different. A provider calls the webhook endpoint when an event occurs; your application calls a normal API endpoint when it needs data or wants an operation performed. Read the fuller webhook vs API comparison or the guide to webhook URLs.
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.
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
Which webhook endpoints does FastHook use?
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
- Webhooks
- How to create a webhook
- Secure webhook endpoint
- Webhook URL
- Webhook testing
- Webhook debugger
- Webhook debugging
- Webhook paths integration
- Webhook request example
- Receive webhooks
- Source authentication
- Custom source responses
- Verify webhooks
- Destination delivery signatures
- Deduplication patterns
- Why 200 OK does not guarantee processing
- Stripe webhooks
- GitHub webhooks