Guide
Manage Environments
Webhook environments should be visible in the route model, not hidden in a single endpoint that changes behavior internally.
Use separate sources, destinations, and connections for production, staging, and local testing so provider setup, signatures, retries, metrics, and replay operations stay scoped to the right traffic.
FastHook source, destination, and connection records do not currently use a first-class route environment field. Model environments with names, separate ids, source URLs, destination targets, and team-scoped secrets.
Environment Topology
Create one visible route per environment boundary. A production provider should call a production source URL. A staging provider should call a staging source URL. Local development should use a staging or local source and a CLI destination instead of production ingress.
This keeps the operational evidence clean: Requests can be filtered by source_id, Events can be filtered by connection_id, and Metrics can be filtered by source_id, connection_id, or destination_id.
- Create one source per provider account and environment.
- Create one destination per deployed receiver environment.
- Use CLI destinations for local development instead of pointing production traffic at localhost.
- Name connections with both sides, such as stripe-prod-to-billing-prod.
- Keep production replay operations separate from staging experiments.
- Treat transformation env variables as transformation runtime config, not as route environment scoping.
stripe-production source
-> billing-production destination
stripe-staging source
-> billing-staging destination
stripe-staging source
-> local-cli-andrew destinationCreate Environment Objects
Environment setup can be automated with the same source, destination, and connection APIs used elsewhere. The key is to keep the environment name in the resource names and to store the returned ids for later deploys and runbooks.
- Sources own the public ingress URL, source auth config, allowed_http_methods, disabled_at, and accepted/rejected request evidence.
- Destinations own the outbound target URL or CLI path, rate limits, destination auth, disabled_at, and attempt evidence.
- Connections own source_id, destination_id, rules, paused_at, disabled_at, and branch-level event evidence.
- Use PUT /v1/sources, PUT /v1/destinations, and PUT /v1/connections for repeatable environment creation.
- Use PATCH /v1/connections/:id to change rules or pause state without rebuilding the source or destination.
{
"name": "stripe-staging",
"type": "WEBHOOK",
"status": "enabled",
"config": {
"auth_type": "HMAC",
"auth": {
"secret": "whsec_staging",
"signature_header": "stripe-signature"
},
"allowed_http_methods": ["POST"]
}
}
{
"name": "billing-staging",
"type": "HTTP",
"config": {
"url": "https://staging.example.com/webhooks/stripe",
"http_method": "POST",
"rate_limit": 20,
"rate_limit_period": "minute",
"path_forwarding_disabled": false,
"auth_type": "FASTHOOK_SIGNATURE",
"auth": {}
}
}
{
"name": "stripe-staging-to-billing-staging",
"source_id": "src_staging",
"destination_id": "des_staging",
"paused_at": null,
"disabled_at": null,
"rules": [
{
"type": "filter",
"body": { "livemode": false }
},
{
"type": "retry",
"strategy": "exponential",
"interval": 30000,
"count": 3,
"response_status_codes": ["429", "500-599", "!501"]
}
]
}Secrets And Auth Boundaries
There are three different secret boundaries in a webhook environment. Provider source auth verifies inbound provider traffic. Project API keys authenticate automation. Project signing secrets are used by receivers that verify FastHook outbound delivery signatures.
Project secrets are scoped by team_id. If production and staging must have separate API keys or FastHook signing secrets, keep them in separate teams/projects or enforce a rotation process that matches your deployment boundary.
- Use provider signing secrets that match the provider environment.
- Do not reuse production source HMAC secrets in staging.
- Store API keys in CI secret storage, not in route JSON files.
- Rotate FastHook project signing secrets when destination verification credentials are exposed.
- Document which receivers verify FASTHOOK_SIGNATURE delivery.
# Source auth secret lives on the source.
"config": {
"auth_type": "HMAC",
"auth": {
"secret": "whsec_provider_environment_secret",
"signature_header": "stripe-signature"
}
}
# Project secrets are team-scoped.
curl "https://api.fasthook.io/v1/project-secrets" \
-H "Authorization: Bearer fhs_xxx" \
-H "x-team-id: tm_xxx"Promotion Workflow
Promote route shape, not traffic. Build the staging source, destination, connection, and rules first. After testing with provider test events, mirror the rule set in production with production IDs, URLs, auth secrets, and limits.
The safest promotion artifact is usually the connection rules array plus a checklist of fields that must be replaced before production. Never copy source_id, destination_id, provider secrets, or receiver URLs blindly between environments.
- Export or copy the staging connection rule JSON.
- Replace source_id and destination_id with production IDs.
- Review filters for provider test-mode fields before moving to production.
- Set production destination rate limits conservatively before first replay.
- Inspect Requests, Events, Attempts, and Metrics after the first provider production event.
- Keep production paused or disabled until provider dashboards point to the correct source URL.
# Staging route uses staging IDs.
{
"name": "stripe-staging-to-billing-staging",
"source_id": "src_staging",
"destination_id": "des_staging",
"rules": [
{ "type": "filter", "body": { "livemode": false } },
{ "type": "retry", "strategy": "exponential", "interval": 30000, "count": 3 }
]
}
# Production route copies route shape but replaces environment-specific fields.
{
"name": "stripe-production-to-billing-production",
"source_id": "src_production",
"destination_id": "des_production",
"rules": [
{ "type": "filter", "body": { "livemode": true } },
{ "type": "retry", "strategy": "exponential", "interval": 30000, "count": 5 }
]
}Local Development
Local development should not point provider production traffic at a developer machine. Use a CLI destination or a staging HTTP destination, then keep that branch paused or disabled when no one is actively testing it.
- Use a staging source for local testing unless the provider requires a separate local source.
- Use a CLI destination when the final receiver is running on localhost.
- Pause a local connection when you want to hold routed events until the tunnel is online.
- Disable a local connection when it should stop creating future event branches.
- Retry old local events only when the developer expects them and the receiver is idempotent.
fasthook tunnel --destination des_local_cli --to http://localhost:3000/api/webhooks
curl -X PUT "https://api.fasthook.io/v1/connections/conn_local/unpause" \
-H "Authorization: Bearer fhp_xxx" \
-H "x-team-id: tm_xxx"
curl "https://api.fasthook.io/v1/events?connection_id=conn_local&status=HOLD&limit=20" \
-H "Authorization: Bearer fhp_xxx" \
-H "x-team-id: tm_xxx"Environment-Scoped Operations
Operational commands should always include the environment-specific ids. This is the guardrail that keeps a staging replay from turning into a production replay.
Use request metrics to prove provider ingress for one source. Use event metrics to prove delivery health for one connection or destination. Use the same id filters when creating retry or bulk retry operations.
- Requests: filter by source_id, status, verified, time range, and search term.
- Events: filter by source_id, connection_id, destination_id, status, batch_operation_id, and time range.
- Metrics: filter request metrics by source_id and event metrics by source_id, connection_id, destination_id, or batch_operation_id.
- Bulk retry: always include from, to, status, and the environment-specific source_id, connection_id, or destination_id.
- Runbooks should write the exact ids they are about to touch before changing state.
curl "https://api.fasthook.io/v1/metrics/requests?date_range[start]=2026-05-29T00:00:00Z&date_range[end]=2026-05-29T23:59:59Z&granularity=1h&source_id=src_staging&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/events?connection_id=conn_staging&status=FAILED&limit=20" \
-H "Authorization: Bearer fhp_xxx" \
-H "x-team-id: tm_xxx"
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_staging",
"connection_id": "conn_staging",
"destination_id": "des_staging"
}'Environment Checklist
- Production and staging have separate source URLs.
- Production and staging destination URLs point to separate receivers.
- Provider dashboards point to the matching FastHook source URL.
- Route names include producer, environment, and consumer.
- Connection ids returned by the API are stored in deploy output or runbooks.
- Source auth secrets match the provider environment.
- Project API keys and signing secrets are isolated by team when required.
- Local CLI destinations are disabled or paused when not in use.
- Events and metrics can be filtered by environment-specific source and destination IDs.
- Bulk retry runbooks include source_id, connection_id, destination_id, status, and time window.