Loading documentation…
Loading documentation…
Create an endpoint, verify exact body bytes and durably accept a delivery.
Events must be explicitly enabled in your environment. Endpoint management requires a signed-in Customer session. A Project workload Credential cannot create or change a webhook.
Expose an HTTPS endpoint with a valid certificate on a permitted public destination. Redirects, URL credentials, query tokens and private destinations are rejected. SteamCall checks DNS again for each new attempt, including retries. Localhost is not an accepted customer destination.
Your handler must retain the exact raw request bytes before JSON parsing. Verify the signature and event identity, then atomically record both acceptance and pending work. Return 2xx only after that transaction commits. Process downstream business effects through a separate idempotent worker.
Implement this acceptance sequence in your server framework. This is pseudocode, not a downloadable SDK:
receive bounded raw body and headers
reject duplicate security headers and malformed signatures
verify timestamp, signature, event identity, Project, type and version
begin transaction
insert unique (endpoint_id, event_id), raw-body hash and pending work
if already accepted: require the same raw-body hash
commit transaction
return 2xxReturn an error if durable acceptance fails. Apply business actions from the committed inbox with idempotency; a duplicate delivery must not repeat them. Bound body size and retained work, monitor capacity, and retain accepted identities for at least 35 days to cover delayed duplicates and recovery.
In the Dashboard, select the owning Project and open Events → Webhooks when the feature is available. Choose a name, HTTPS destination and explicit completed/failed event subscriptions. Save the signing key ID and secret when shown: ordinary reads cannot reveal it again. Creating an endpoint does not automatically send a test.
If the one-time signing secret was not saved, use secret rotation in the Dashboard rather than creating a duplicate endpoint. Never put a signing secret into a URL, source control, browser code, or logs.
The sender includes Webhook-Id, Webhook-Timestamp, Webhook-Signature and Webhook-Attempt-Id. Signatures contain one or two space-separated entries:
v1:whk_KEY_ID:BASE64URL_HMAC_WITHOUT_PADDINGThe signed bytes are ASCII timestamp, ., ASCII Webhook-Id, ., then the unchanged body bytes. Compute HMAC-SHA256 using the endpoint secret decoded from unpadded base64url into its original 32 key bytes, accept a recognized configured key with constant-time comparison, and reject timestamps more than 300 seconds from current UTC. Validate the body's id equals Webhook-Id and that Project/type/version match your subscription. The attempt ID is diagnostic; deduplicate by event ID within the endpoint.
The displayed secret is a 43-character unpadded base64url value, not the literal HMAC key text. Decode it with your language’s URL-safe base64 decoder (adding the required = padding), require 32 decoded bytes, and reject invalid or noncanonical encoding. Signature values use the same unpadded base64url encoding.
Reject duplicate security headers, oversized bodies, malformed signatures, unknown keys, and mismatched event identity. Compare decoded signatures in constant time. Do not parse and re-serialize JSON before verifying its signature.
Test your handler with modified body bytes, an expired timestamp, an unknown key, repeated event IDs, and storage failure. Invalid signatures must never create accepted work. An identical accepted event may return success again without repeating business effects.
Use Send test explicitly. The result is a synthetic webhook.test delivery, not an Inventory outcome, and does not appear in Activity or SSE. After a successful test, submit a normal Inventory refresh in the same Project. Inspect Activity and delivery attempts. A failed refresh can still produce a correctly delivered failure event.
Continue with lifecycle and rotation and delivery guarantees.