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

FieldTypeRequiredDescription
config.urlstringYesThe URL to send events to
config.custom_headersstringNoJSON object of custom HTTP headers to include

Credentials

FieldTypeRequiredDescription
credentials.secretstringNoSigning secret — auto-generated if not provided
credentials.previous_secretstringNoPrevious secret during a rotation window
credentials.previous_secret_invalid_atstringNoRFC 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-event-id: evt_abc123
x-outpost-topic: user.created
x-outpost-timestamp: 2024-06-01T08:23:36Z
x-outpost-signature: v0=abc123def456...
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.

Event ID header and idempotency

Webhook delivery is at-least-once (see Event delivery & retries). Your handler should deduplicate using the event id — the same stable id you set when publishing (Outpost may redeliver on retries).

In default mode, that id is sent as the system event-id metadata field. The HTTP header name is {header_prefix}{metadata-key} with no extra separator — the prefix and key are concatenated as-is. So the default prefix x-outpost- plus event-id yields X-Outpost-Event-Id; a prefix without a trailing separator (for example x-acme) would produce x-acme + event-idX-Acmeevent-Id (Go canonicalizes the wire name). Include a trailing hyphen in the prefix when you want a conventional shape like X-Acme-Event-Id. Change the prefix with DESTINATIONS_WEBHOOK_HEADER_PREFIX, or omit this header with DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_EVENT_ID_HEADER.

In Standard Webhooks mode, the same value is sent as the webhook-id header (default prefix webhook-, so typically Webhook-Id) per the Standard Webhooks specification.

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:

  1. Extract the timestamp and signature from the header
  2. Compute the expected signature using your secret
  3. Compare signatures using a constant-time comparison
  4. 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:

  1. The current secret becomes previous_secret
  2. A new secret is generated
  3. The previous secret remains valid until previous_secret_invalid_at (default: 24 hours)
  4. 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_DEFAULT_EVENT_ID_HEADER, DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TIMESTAMP_HEADER, DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TOPIC_HEADER, DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_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

VariableDefaultDescription
DESTINATIONS_WEBHOOK_HEADER_PREFIXx-outpost- / webhook-Prefix for system webhook headers (event id, topic, timestamp, signature). Unless overridden, defaults to x-outpost- when DESTINATIONS_WEBHOOK_MODE is default and webhook- when standard.
DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_EVENT_ID_HEADERfalseDisable the event ID header
DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TIMESTAMP_HEADERfalseDisable the timestamp header
DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TOPIC_HEADERfalseDisable the topic header
DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_SIGNATURE_HEADERfalseDisable the signature header

Signature Settings

VariableDefaultDescription
DESTINATIONS_WEBHOOK_MODEdefaultSet to standard for Standard Webhooks compliance
DESTINATIONS_WEBHOOK_SIGNATURE_ALGORITHMhmac-sha256Signature algorithm
DESTINATIONS_WEBHOOK_SIGNATURE_ENCODINGhexEncoding: hex or base64
DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE{{.Body}}Template for signed content
DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATEv0={{.Signatures | join ","}}Template for signature header value