Webhook
Send events via HTTP POST to a URL endpoint. Outpost supports two webhook modes:
- Default mode — Customizable headers and signature format
- Standard Webhooks mode — Follows the Standard Webhooks specification
Creating a Webhook Destination
curl 'https://api.outpost.hookdeck.com/2025-07-01/tenants/<TENANT_ID>/destinations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <API_KEY>' \
--data '{
"type": "webhook",
"topics": ["user.created", "user.updated"],
"config": {
"url": "https://example.com/webhooks"
}
}'
Configuration
Config
| Field | Type | Required | Description |
|---|---|---|---|
config.url | string | Yes | The URL to send events to |
config.custom_headers | string | No | JSON object of custom HTTP headers to include |
Credentials
| Field | Type | Required | Description |
|---|---|---|---|
credentials.secret | string | No | Signing secret — auto-generated if not provided |
credentials.previous_secret | string | No | Previous secret during a rotation window |
credentials.previous_secret_invalid_at | string | No | RFC 3339 timestamp when the previous secret expires |
If secret is not provided, one is auto-generated. Tenants can trigger secret rotation but cannot set secrets directly.
Event Format
When you publish an event:
{
"topic": "user.created",
"data": { "user_id": "usr_123", "email": "user@example.com" },
"metadata": { "source": "signup-service" }
}
Outpost sends an HTTP POST request:
POST /webhooks HTTP/1.1
Content-Type: application/json
x-outpost-id: evt_abc123
x-outpost-topic: user.created
x-outpost-timestamp: 1704067200
x-outpost-signature: t=1704067200,v0=abc123...
x-outpost-source: signup-service
{"user_id": "usr_123", "email": "user@example.com"}
The request body contains the event's data field as JSON. The metadata field is translated to headers using the configured prefix.
Signatures
Default Mode
The signature is computed over the timestamp and request body:
HMAC-SHA256(secret, "${body}")
The x-outpost-signature header value follows the format: v0=${signature}
To verify:
- Extract the timestamp and signature from the header
- Compute the expected signature using your secret
- Compare signatures using a constant-time comparison
- Optionally reject requests with old timestamps to prevent replay attacks
Standard Webhooks Mode
Follows the Standard Webhooks specification:
base64(HMAC-SHA256(secret, "${webhook-id}.${timestamp}.${body}"))
Use the official Standard Webhooks SDK to verify signatures. Secrets use the whsec_<base64> format.
Enable Standard Webhooks mode by setting DESTINATIONS_WEBHOOK_MODE=standard in the Config API or in Hookdeck Destinations settings.
Enable Standard Webhooks mode:
DESTINATIONS_WEBHOOK_MODE=standard
Secret Rotation
Rotate a webhook secret without downtime. During the rotation window, both the old and new secrets produce valid signatures.
curl --request PATCH \
'https://api.outpost.hookdeck.com/2025-07-01/tenants/<TENANT_ID>/destinations/<DESTINATION_ID>' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <API_KEY>' \
--data '{
"credentials": {
"rotate_secret": "true",
"previous_secret_invalid_at": "2025-01-15T00:00:00Z"
}
}'
When rotation is triggered:
- The current secret becomes
previous_secret - A new secret is generated
- The previous secret remains valid until
previous_secret_invalid_at(default: 24 hours) - Both secrets appear in the signature header during the rotation window
Custom Headers
Tenants can add custom HTTP headers to webhook requests for authentication or routing:
curl 'https://api.outpost.hookdeck.com/2025-07-01/tenants/<TENANT_ID>/destinations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <API_KEY>' \
--data '{
"type": "webhook",
"topics": ["*"],
"config": {
"url": "https://example.com/webhooks",
"custom_headers": "{\"x-api-key\": \"secret123\"}"
}
}'
Header names must start with a letter or digit and may contain letters, digits, underscores, and hyphens. The following headers cannot be overridden: content-type, content-length, host, connection, user-agent.
Custom webhook headers in the tenant portal are disabled by default. Enable them in Hookdeck User Portal settings.
Custom headers are disabled in the tenant portal by default. Enable with:
PORTAL_ENABLE_WEBHOOK_CUSTOM_HEADERS=true
Operator Configuration
Configure webhook operator behavior using these keys in the Config API or in Hookdeck Destinations settings: DESTINATIONS_WEBHOOK_HEADER_PREFIX, DESTINATIONS_WEBHOOK_DISABLE_EVENT_ID_HEADER, DESTINATIONS_WEBHOOK_DISABLE_TIMESTAMP_HEADER, DESTINATIONS_WEBHOOK_DISABLE_TOPIC_HEADER, DESTINATIONS_WEBHOOK_DISABLE_SIGNATURE_HEADER, DESTINATIONS_WEBHOOK_MODE, DESTINATIONS_WEBHOOK_SIGNATURE_ALGORITHM, DESTINATIONS_WEBHOOK_SIGNATURE_ENCODING, DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE, and DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE.
Header Settings
| Variable | Default | Description |
|---|---|---|
DESTINATIONS_WEBHOOK_HEADER_PREFIX | x-outpost- | Prefix for all webhook headers |
DESTINATIONS_WEBHOOK_DISABLE_EVENT_ID_HEADER | false | Disable the event ID header |
DESTINATIONS_WEBHOOK_DISABLE_TIMESTAMP_HEADER | false | Disable the timestamp header |
DESTINATIONS_WEBHOOK_DISABLE_TOPIC_HEADER | false | Disable the topic header |
DESTINATIONS_WEBHOOK_DISABLE_SIGNATURE_HEADER | false | Disable the signature header |
Signature Settings
| Variable | Default | Description |
|---|---|---|
DESTINATIONS_WEBHOOK_MODE | default | Set to standard for Standard Webhooks compliance |
DESTINATIONS_WEBHOOK_SIGNATURE_ALGORITHM | hmac-sha256 | Signature algorithm |
DESTINATIONS_WEBHOOK_SIGNATURE_ENCODING | hex | Encoding: hex or base64 |
DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE | {{.Body}} | Template for signed content |
DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE | v0={{.Signatures | join ","}} | Template for signature header value |