Dome Systems

Guide

Handle signed Dome webhooks without repeating the business action

Suppose a denied tool call should open one review ticket. The webhook arrives, your receiver opens the ticket, and later someone replays the delivery. Without a duplicate check, the same event can open a second ticket.

For Dome integrations, distinguish the event from an individual delivery. Verify the signed request, durably accept it, and deduplicate the business action using a stable event identity. The procedure below is an integration design, not a claim that Dome runs your receiver's transaction.

First, subscribe to an event Dome delivers

Start with the webhook documentation. Choose a supported operation and supported filters for the workspace subscription.

For example, a denied-operation workflow uses the operation name and a result=denied filter where supported. Do not invent an access.denied event name. Do not assume every audit event is a webhook event: model.call is available in audit but is not delivered through webhooks.

Write down what the receiver will do when the selected event arrives. “Create a review task for a denied tool call” is testable. “Send all security information” is not a useful subscription contract.

Track the event separately from its delivery

A delivery identifier answers, “Which HTTP delivery am I diagnosing?” An event identifier answers, “Have I already handled this underlying event?”

Dome's replay behavior matters here: replay uses a new webhook-id while preserving Dome-Event-Id. Deduplicating only on webhook-id therefore does not prevent replay from repeating the business action.

Use a durable key based on the stable event ID and the receiver's intended processing namespace. If the same event legitimately drives both a ticket and an archive, those are two consumers, not an accidental duplicate. Give each intended action its own consumer key.

Keep the delivery ID for diagnostics alongside the event ID. Neither identifier is a substitute for signature verification.

Accept the event without losing or repeating work

  1. Capture the raw request body and the required signature headers without rewriting the body.
  2. Verify the Standard Webhooks signature and timestamp using the subscription's signing secret and a suitable verifier. Reject unverified requests before acting on their content.
  3. Parse the verified envelope. Check that it contains the expected event identity and belongs to a subscription your receiver handles.
  4. In durable storage, insert a receipt keyed by consumer namespace and Dome-Event-Id. Treat an existing receipt as a duplicate according to its processing state.
  5. Atomically persist the work to be done with that receipt, for example through a transaction and outbox. A receipt recorded before an unprotected queue write can otherwise lose work after a crash.
  6. Return a success response within Dome's documented ten-second receiver window once acceptance is durable. Perform slow downstream work asynchronously.
  7. Make the downstream action idempotent too, or persist its result so a worker retry can recover without creating another ticket or notification.

This is a recommended receiver architecture. Its guarantees depend on your storage, queue, and downstream API. A database uniqueness constraint alone does not make a non-idempotent external action exactly-once.

Test retries, replay, and crashes

FixtureExpected receiver behavior
Valid new eventOne durable receipt and one intended action
Body changed after signingRejected before a business action
Invalid or unacceptable signature timestampRejected according to verifier policy
Duplicate delivery of the same eventExisting receipt recognized; no extra action
Replay with a new delivery ID and the same event IDSame consumer action not repeated
Crash after durable acceptance, before processingPending work resumes
Crash after downstream success, before local completionIdempotency key or reconciliation prevents duplication
Durable storage unavailableDo not acknowledge acceptance that was not recorded

Keep synthetic payloads in the test suite. Avoid storing full production bodies in application logs merely to debug delivery.

Separate delivery health from incident judgment

A signed denial event tells the receiver what was refused. It does not tell an operator whether the refusal was expected, caused by a rollout defect, or worth investigating as suspicious activity. Keep those incident-response decisions separate from the receiver's job of delivering one review ticket.

Keep a short receiver runbook: the selected events, signature verifier, duplicate key, durable receipt, retry behavior, and recovery owner. Test the replay case before relying on the integration. One event should still produce one intended ticket, even after a failed delivery or worker retry.

Published

October 21, 2026

Preska Sharma

webhooksintegrationsagent-operations
All blog posts