Skip to main content
An error webhook is a routing fact, not a work order. This recipe turns one Sentry issue webhook into exactly one governed Automation firing — verified by you, deduplicated by the platform, and never trusted as Run input beyond routing.
Plain HTTP against the Checkfu API needs no private package. The Checkfu CLI and TypeScript SDK are private-alpha artifacts with no self-service public installation channel. The artifacts this page uses are gated behind the current private-alpha rollout. Confirm capability status before making availability part of your application’s contract.

Who owns what

You own every Sentry-shaped thing. Checkfu never verifies Sentry’s signature, never holds your Client Secret, and never operates the Sentry integration. Register the webhook URL with your Sentry integration for the resources you actually map. Subscribing to everything and filtering in code builds a router you then have to operate; subscribing to issue only is the smaller surface.

Create the reviewed Automation pair per mapped project

A regressed issue must not be suppressed by the firing that handled its original appearance, and webhook predicates are a conjunction — “action is created” and “substatus is regressed” cannot live in one trigger. So each mapped Sentry project gets a pair of Automations that share the same reviewed resource bindings and differ only in their filter:
The resources are the reviewed Session resource bindings — the writable file-tree volumes, each carrying the pull-request publication policy a fix PR targets. A mount without that policy is a writable overlay that never publishes a change. They freeze at create time; the payload never selects or authors them, only your frozen mapping decides which pair a delivery forwards to. Both members dedupe on /data/issue/id, and occurrence identity is per-Automation, so each converges its own redeliveries while the other class stays free to fire — that is the whole regression story. Predicates run before the dedupe claim, and a filtered delivery is recorded as a filtered delivery, not silence. The environment_id freezes the Environment every child Session admits against; a missing Environment fails closed before the Session exists.

Verify Sentry’s signature over the exact bytes

Sentry signs each delivery with your integration’s Client Secret: an HMAC-SHA256 digest, hex-encoded, in the Sentry-Hook-Signature header. Sentry’s documented verification snippet signs the re-serialized parse of the body, while compact raw-bytes signing is what integrations commonly observe. Verify the raw bytes first and accept the documented canonicalization as a fallback — an attacker without the secret can produce neither digest, and a body that is not JSON never gets the second chance:
Capture the raw body before any framework parsing. If your stack parses JSON and hands you an object, you no longer have the bytes that were signed.

Classify the occurrence, then consult your mapping

Two derivations decide everything downstream, and both refuse rather than guess. The occurrence key carries identity coordinates only — installation, issue id, and the class derived from action and substatus. Titles, culprits, stack hashes, and breadcrumbs never enter it: text that changes must not change dedupe identity, and provider text must not sit in coordination stores. created maps to new, unresolved with regressed maps to regression, and everything else maps to a non-firing class. The firing map is frozen configuration keyed by the pair actually present in the payload — the installation UUID and the project slug — and each entry names the reviewed Automation pair plus the resource bindings those firings freeze:
An unmapped pair refuses explicitly. There is no default route, and no payload field can select a firing or author a binding: the closed decode extracts only the identity facts and drops everything else on the floor.

Forward the exact bytes through the relay

The stock relay helper orders verify-before-forward, refuses a verifier that rewrites the body, and produces the ordinary ingest signature for the same bytes — your HTTP transport stays yours:
targetAutomationId comes from your occurrence class — new deliveries to the mapped pair’s new-issue member, regressions to its regression member. The platform does the rest: the predicate ladder re-decides relevance, the dedupe pointer converges redeliveries, and an accepted event becomes one AutomationRun linked to its Session.

Keep the webhook out of the Run

The webhook body told you where the work is, not what the work is. Inside the Session, fetch the full issue, stacktrace, and events through a governed connection — your provider client operating under credentials the platform never copies — and build the fix brief from that fresh read. A prompt template that interpolates webhook text has made provider bytes into trusted Run input, which is the exact inversion this recipe exists to prevent. Delivery back to Sentry is read-only in this shape: the fix PR link lands in the Session log, and your delivery worker projects it wherever your reviewed provider capability honestly supports. Do not bolt a write path on without the same custody review any provider call gets.

Prove it before you wire Sentry to it

The reference relay ships with deterministic suites that need no credentials: signature acceptance and forgery rejection (including the re-serialization fallback boundary), occurrence-class stability and regression separation, closed-decode refusals, mapping refusal, and the admission verdicts. Run them before the webhook URL exists:
These 18 local cases do not receive a Sentry delivery or qualify a deployed relay. Real provider delivery and end-to-end relay qualification remain unperformed; setting a signing secret does not supply that evidence. The reference relay and its suites are staged in this repository’s docs workspace until they publish to the examples repository — the publishing step is the repository owner’s, not yours and not the platform’s.

Next

Trigger Automations from providers

The Automation side this recipe forwards into: sources, registrations, and the admission ladder.

Follow a Linear issue as one conversation

The other half of the error-to-fix loop: a continuing thread instead of a fresh Session per event.