Webhooks
A webhook represents one webhook integration — a target URL where HostWebhook delivers events, with optional fallback URLs, payload filters, payload transforms, and signature verification.
What is a webhook?
Each webhook has:
- Name—A friendly label shown in the dashboard
- Target URL—Where HostWebhook POSTs events (your server)
- Ingress URL—Where your webhook source sends events — unique per webhook
- Ingress token—The token in the ingress URL — rotate it to invalidate the old URL
- Signing secret—Used to sign every delivery — verify it on your server
- Max retries—How many additional attempts after a failure (plan-limited: Free 0–3, Pro 0–10, Enterprise 0–20)
- Retry delay—Base delay (seconds) for exponential backoff (default: 60)
- Rate limit—Max deliveries per minute (0 = unlimited)
- Active—Paused webhooks queue events but pause delivery
- Incoming signature—Verify signatures from Stripe, GitHub, or custom HMAC on inbound requests
- Payload filters—Rules to accept or discard events based on payload content
- Fallback URLs—Backup URLs tried in order when the primary target URL fails
Plan limits
| Plan | Events / week | Max retries | Max retry delay | Backoff cap |
|---|---|---|---|---|
| Free | 1,000 | 3 | 60 s | 30 min |
| Starter | 2,500 – 10,000 | 5 | 600 s | 2 hr |
| Pro | 6,000 – 50,000 | 10 | 3,600 s | 6 hr |
| Enterprise | 12,000 – 200,000 | 20 | 7,200 s | 24 hr |
Events reset every week. Free has 1,000; on Starter, Pro and Enterprise you choose how many you need each week, and above 200,000 a week there's a Custom plan.
maxRetries: 3 means up to 4 total attempts (1 initial + 3 retries). Exceeding your plan's limit returns 403 Forbidden.Rotating secrets
Both the ingress token and signing secret can be rotated at any time from the webhook detail page.
- Rotating the ingress token invalidates the old ingress URL immediately. Update your webhook source to use the new URL.
- Rotating the signing secret invalidates the old secret immediately. Update your server's environment variable first.
Pausing a webhook
Pausing a webhook stops delivery. Events continue to be accepted at the ingress URL and queued — they will be delivered once you activate the webhook again. Useful for maintenance windows.
Ingress protection
HostWebhook offers multiple layers of ingress protection. You can enable any combination — when multiple are active, all must pass.
Require API Key
When enabled, every request to the ingress must include a valid API key with the ingress:write scope in the Authorization header (events:write, the wider scope, opens it too — keys created beforeingress:write existed use that one). The API key identifies who is sending, verifies they have permission, and confirms they belong to the same organization as the webhook.
curl -X POST https://api.hostwebhook.com/api/in/YOUR_TOKEN \
-H "Authorization: Bearer hwk_your_api_key" \
-H "Content-Type: application/json" \
-d '{"event": "order.created"}'Incoming signature verification
Verifies that the payload was not tampered with in transit. Configure the type and shared secret — HostWebhook validates the signature header on every inbound request.
| Type | Description |
|---|---|
| none | No signature verification (default) |
| stripe | Verify Stripe-Signature header (HMAC-SHA256) |
| github | Verify X-Hub-Signature-256 header (HMAC-SHA256) |
| shopify | Verify X-Shopify-Hmac-Sha256 header (HMAC-SHA256, base64) |
| hostwebhook | Verify X-HostWebhook-Signature header (t=timestamp,v1=hmac) |
| static | Verify a static secret in Authorization, X-Webhook-Secret, or custom header |
API Key vs Incoming Signature
They solve different problems and can work together.
| API Key | Incoming Signature | |
|---|---|---|
| Who uses it | Your clients (SDK, API) | External services (Stripe, GitHub) |
| What it verifies | Identity + permissions (scopes) | Payload integrity (not tampered) |
| Scopes | Yes (ingress:write, canvas:write, etc.) | No |
| Org ownership | Yes | No |
| Replay protection | No (use deduplication) | Yes (timestamp in HMAC) |
stripe, Shopify → shopify, GitHub → github).Payload filters
Payload filters let you discard events that don't match specific criteria — before any delivery attempt is made. Events that fail the filter are saved with status filtered and no delivery job is created.
payment_intent.succeeded events from a Stripe integration that sends dozens of event types.How filters work
All filter rules are evaluated against the parsed JSON payload. If all rules pass, the event is queued for delivery. If any rule fails, the event is discarded. Fields support dot-notation for nested properties.
Available operators
| Operator | Description | Value required |
|---|---|---|
| eq | Field equals value (string comparison) | Yes |
| neq | Field does not equal value | Yes |
| contains | Field contains value (string) | Yes |
| gt | Field is greater than value (numeric) | Yes |
| lt | Field is less than value (numeric) | Yes |
| exists | Field is present and not null | No |
| not_exists | Field is absent or null | No |
Example — only process succeeded payments
// Payload filters on the webhook:
[
{ "field": "type", "operator": "eq", "value": "payment_intent.succeeded" },
{ "field": "data.object.amount", "operator": "gt", "value": "0" }
]
// This Stripe payload passes:
{ "type": "payment_intent.succeeded", "data": { "object": { "amount": 5000 } } }
// This one is filtered (wrong type):
{ "type": "payment_intent.created", "data": { "object": { "amount": 5000 } } }Manage payload filters from the Payload Filters section on the webhook detail page.
Payload transforms
A payload transform lets you reshape the event before HostWebhook delivers it to the webhook's target URL — converting a raw Stripe payload into a Discord embed, for example. Transforms use a JSON template with {{path}} interpolation.
Interpolation syntax
| Syntax | Description |
|---|---|
| {{payload.type}} | Value from the event payload using dot-notation |
| {{headers.stripe-signature}} | Value from the original inbound headers |
| {{meta.eventId}} | HostWebhook event metadata (eventId, receivedAt) |
| {{payload.amount ?? 0}} | Null coalescing — use fallback if path is null/undefined |
| {{payload.status === 'active' ? 'Yes' : 'No'}} | Ternary — compare with string/number/null |
| {{payload.field !== null ? payload.other : 'none'}} | Ternary with path resolution in branches |
Example — Stripe payment to Discord embed
{
"embeds": [{
"title": "💳 Payment Received",
"color": 5763719,
"fields": [
{
"name": "Amount",
"value": "{{payload.data.object.amount_received ?? 0}} {{payload.data.object.currency}}",
"inline": true
},
{
"name": "Customer",
"value": "{{payload.data.object.customer ?? 'Guest'}}",
"inline": true
}
],
"timestamp": "{{meta.receivedAt}}"
}]
}API
The transform is a field on the webhook itself — send payloadTransform when you create or update one, ornull to remove it. See the API reference for the full schema.
Circuit Breaker
The circuit breaker automatically stops delivering to a webhook that is consistently failing — protecting both your server and your retry budget.
| Field | Description | Default |
|---|---|---|
| circuitBreaker.enabled | Enable the circuit breaker | false |
| circuitBreaker.threshold | Consecutive failures to open the circuit | 5 |
| circuitBreaker.cooldownSeconds | How long the circuit stays open before testing | 300 |
The circuit breaker has three states: CLOSED (normal — deliveries flow), OPEN (blocked — events are queued but not delivered), and HALF_OPEN (testing — one event is allowed through to check if the webhook has recovered).
Priority
Each webhook has a priority field (1–5, default 3). Priority 1 is critical — events for higher-priority webhooks are dequeued and delivered before lower-priority ones.
X-HW-Priority header on inbound requests. This overrides the webhook default for that specific event.Fallback URL
Configure a fallbackUrl on a webhook. If the primary targetUrl fails all retries, HostWebhook makes one final attempt to the fallback URL before marking the event as failed. Useful for disaster recovery or backup processing servers.
Chaos testing
Enable chaos testing to simulate failures in development and staging:
| Field | Description |
|---|---|
| chaosConfig.enabled | Enable chaos testing for this endpoint |
| chaosConfig.failureRate | Percentage of deliveries that will be artificially failed (0–100) |
| chaosConfig.latencyMs | Artificial latency added to each delivery (milliseconds) |