Connect a Sentry project to a repository and each error Sentry alerts on reaches developerz.ai as an ask: a request for work, judged like any other. The path:
- Sentry fires an issue alert and POSTs it, signed, to a URL developerz.ai minted for you.
- The delivery files one ask per Sentry issue. A repeat alert for the same issue lands on the ask it already filed; it never files a second one.
- Triage judges the ask on your own model key: it schedules a fix, drops it as noise, links it to a duplicate, or escalates it to you.
- A scheduled fix runs on one of your boxes and opens a pull request.
- The pull request is watched through CI and review and merged by the merge gate, on
your
maintainer.ymlpolicy. Nothing merges that your policy would not merge.
Coding work waits for the repository's one-time onboarding pass, so a Sentry ask on a repository that was never onboarded is held until that pass lands.
Before you start
- The repository is connected and enabled on your account.
- An MCP client is connected with a token carrying
write:integrations(MCP clients). Inbound sources are managed over MCP. - You can create an internal integration in your Sentry organization (owner or manager).
One integration per repository
Sentry posts every alert an integration fires to that integration's one webhook URL. A source pinned to repository A files every delivery it receives against A, including an alert from a project that belongs to repository B. So:
- create one Sentry internal integration per target repository,
- connect one source per integration, pinned to that repository,
- route only that repository's projects' alert rules to that integration.
Two Sentry organizations, or two integrations, on one account are fine: each source keeps its own asks apart.
Step 1: create the internal integration
In Sentry: Settings → Developer Settings → Custom Integrations → Create New Integration → Internal Integration.
- Name it after the repository, so the alert action is unambiguous later.
- Webhook URL: any
https://placeholder for now. You replace it in step 3. - Enable Alert Rule Action, so the integration can be chosen as an alert action.
Save it and copy its Client Secret. Sentry signs every delivery with that secret, and developerz.ai verifies against it, so it is required: a secret minted on our side would reject every real delivery.
Step 2: connect the source
integration({
action: "source_connect",
kind: "sentry",
label: "acme-api errors",
repo: "acme/api",
gesture: { kind: "always" },
vendor_secret: "<the integration's Client Secret>"
})
gesture: { kind: "always" }takes every delivery the integration sends. That is right for an alert feed: the alert rule in step 4 is the filter.repopins the source to one enabled repository (see Which repository an error lands on).- The answer carries the source
url. The secret is sealed and never returned.
Refusals name their fix: vendor_secret_required (pass the Client Secret),
unknown_repo (connect and enable the repository first), label_taken (pick another
label).
Step 3: point Sentry at the URL
Edit the internal integration and set its Webhook URL to the url from step 2. Save.
Step 4: add an issue alert rule per project
For every Sentry project that belongs to this repository: Alerts → Create Alert → Issues, choose the project, set the conditions you want work for (for example "a new issue is created", narrowed to your production environment), and add the action that sends a notification via the integration from step 1.
The alert rule is the best place to filter: an error Sentry never posts costs nothing.
Which repository an error lands on
- Pinned (
reposet): every delivery lands on that repository, whatever project it names. This is the recommended setup. - Unpinned (
repoomitted): the delivery names its Sentry project, and that project's slug must equal the name of exactly one repository enabled on your account (case-insensitive;apimatchesacme/api). No match, or two matches, and the delivery is dropped asunresolved_repo: developerz.ai never guesses between repositories.
So pin repo whenever a project slug is not exactly the repository name, for example a
project api-backend for the repository acme/api.
Dropping noise
Filter in Sentry first. What Sentry still sends and you never want work for can be
dropped at the door with drop_matching on source_connect: up to 20 {path, equals}
pairs, where path is a dotted path into the JSON body Sentry posts and equals is
compared case-insensitively.
drop_matching: [{ path: "action", equals: "resolved" }]
A matching delivery answers 200 with {"status":"dropped","reason":"expected_error"}
and files nothing. Read each path off a real delivery body rather than guessing it. Drop
rules are set when the source is connected; to change them, connect a new source,
repoint the integration's Webhook URL, then disconnect the old source.
What each delivery answers
| Answer | Meaning |
|---|---|
200 {"status":"filed"} |
A new ask was filed. |
200 {"status":"noop","reason":"already_filed"} |
A repeat for a Sentry issue that already has an ask. |
200 dropped, ignored_resource |
Sentry sent something that carries no issue or event (an install notice, a comment). |
200 dropped, unresolved_repo |
Unpinned, and the project slug matched no repository, or more than one. |
200 dropped, no_stable_id |
The body named no stable Sentry issue to key the ask on. |
200 dropped, expected_error |
One of your drop rules matched. |
200 dropped, intake_cap_exceeded |
The source already filed 20 new asks today (UTC). Repeats of existing asks still land. |
401 |
The signature did not verify: the stored secret is not this integration's Client Secret. |
404 |
The URL names no source: it was disconnected, or mistyped. |
A dropped delivery is a decision, not a failure: it is recorded, and Sentry is not asked to retry it.
Rotating and stopping
- Rotate: when you rotate the integration's Client Secret in Sentry, store the new one
with
integration({action: "source_rotate", source_id, vendor_secret}). The old secret keeps verifying for 24 hours, so deliveries in flight are not lost. - Stop:
integration({action: "source_disconnect", source_id})closes the source at once; Sentry's next delivery to that URL gets a404. - List:
integration({action: "source_list"})shows each source with itsurl, its repository and its status.
See also: inbound and outbound webhooks, and the
MCP verb reference for the full integration verb.