Outgoing webhooks
Send ADO Pilot review and billing events to your own HTTPS endpoint — configure the URL, choose events, and validate delivery with the test button.
Last updated
Send ADO Pilot events — review completions, credit alerts, and plan renewals — to your own HTTPS endpoint so you can fan them out to Slack, PagerDuty, an analytics warehouse, or any custom automation.
Requirements
- HTTPS only. ADO Pilot refuses to save plain
http://URLs, and refuses to deliver to non-HTTPS endpoints even if you bypass the form. - Public reachability. Your endpoint must accept connections from the public internet. Private IPs and unresolvable hostnames fail at delivery time.
- Five-second response budget. Your handler must respond
2xxwithin 5 seconds. Anything slower is treated as a failure and is not retried. - Org-admin role. Only admins can save the webhook URL or fire the test button.
Configure the endpoint
- Open Settings then Notifications in the dashboard.
- In the Webhook card, enter your endpoint in the Endpoint URL field. The placeholder is
https://hooks.example.com/adopilot. - Under Events, select the events you want delivered, then save (see the table below).
- Click Save webhook and wait for the Saved confirmation.
Saving with no events selected disables the webhook — you can re-enable by ticking events and saving again.
HTTPS validation rejection
The form refuses to save anything that does not parse as an https:// URL. If you paste http://hooks.example.com/adopilot and click Save webhook, the request is rejected with:
Webhook URL must be a valid https:// URL
The error appears inline next to the save button. The previously saved URL (if any) is left untouched.
Supported events
ADO Pilot emits five outgoing webhook events. Each event fires once per occurrence — there are no duplicate deliveries for the same trigger.
| Event | Triggered when |
|---|---|
review.completed | A pull request review finishes and a PASS, ADVISORY, or FAIL status check has been posted. |
review.failed | A review enters a terminal failure state (orchestration abort, fatal LLM error, or quota exhaustion). |
credit.low | Your organization's review credit (RC) consumption first crosses 80% of the plan's included RCs. |
credit.exhausted | Your organization runs out of RCs — either the hard-block quota is hit or the auto-overage cap is hit. |
plan.renewed | Stripe processes a subscription renewal: RCs reset and a new billing period begins. |
Test your endpoint
The Test webhook button is disabled until you have saved a valid https:// URL and the value in the input matches the saved value exactly. Clicking it sends a single request to your saved endpoint.
The test payload is intentionally minimal:
{
"event": "review.completed.test",
"orgId": "your-org-id",
"timestamp": "2026-05-05T14:30:00.000Z",
"test": true
}
If your endpoint replies 2xx within 5 seconds, the dashboard shows Delivered (HTTP NNN) with the status code your endpoint returned — for example Delivered (HTTP 200) or Delivered (HTTP 204). Anything else surfaces as an inline error — connection refused, TLS failure, timeout, or an HTTP 4xx/5xx from your handler.
Production payloads
Each event below shows a representative JSON body and a field reference. Every field on every payload is provisional pending PM/eng confirmation — see the warning at the top of this page.
review.completed
Fires when a review reaches a terminal verdict.
{
"event": "review.completed",
"orgId": "org-12345",
"timestamp": "2026-05-05T14:35:22.000Z",
"reviewId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"prId": 42,
"projectId": "ado-proj-guid-or-slug",
"repositoryId": "ado-repo-guid-or-slug",
"verdict": "ADVISORY",
"findingCounts": {
"blocker": 0,
"warning": 2,
"suggestion": 5
},
"durationMs": 180000,
"creditsUsed": 1
}
| Field | Type | Notes |
|---|---|---|
event | string | Always "review.completed". |
orgId | string | Your ADO Pilot organization ID. |
timestamp | string | ISO 8601 UTC; emitted when the review was finalized. |
reviewId | string | Unique review identifier; correlates to the PR thread in ADO. |
prId | number | Pull request number in the ADO repository. |
projectId | string | ADO project GUID or slug. |
repositoryId | string | ADO repository GUID or slug. |
verdict | string | "PASS", "ADVISORY", or "FAIL". |
findingCounts | object | Counts of blocker, warning, and suggestion findings. |
durationMs | number | Milliseconds from queued to completed. |
creditsUsed | number | RCs charged for this review. |
review.failed
Fires when a review enters a terminal failure state — orchestration abort, fatal LLM error, tenant-inactive, or quota exhaustion.
{
"event": "review.failed",
"orgId": "org-12345",
"timestamp": "2026-05-05T14:40:10.000Z",
"reviewId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"prId": 42,
"projectId": "ado-proj-guid-or-slug",
"repositoryId": "ado-repo-guid-or-slug",
"errorType": "quota_exceeded",
"errorMessage": "Review quota exhausted — upgrade your plan to continue.",
"durationMs": 5000
}
| Field | Type | Notes |
|---|---|---|
event | string | Always "review.failed". |
orgId | string | Your organization ID. |
timestamp | string | ISO 8601 UTC at the moment of failure. |
reviewId | string | Unique review identifier. |
prId | number | Pull request number. |
projectId | string | ADO project GUID or slug. |
repositoryId | string | ADO repository GUID or slug. |
errorType | string | Machine-readable category, e.g. "quota_exceeded", "auth_error", "rate_limit". |
errorMessage | string | Human-readable description; safe to surface in alerts. |
durationMs | number | Milliseconds from queued to failure. |
credit.low
Fires once per billing period the first time RC consumption crosses 80% of the included plan credits.
{
"event": "credit.low",
"orgId": "org-12345",
"timestamp": "2026-05-05T14:45:33.000Z",
"usagePercent": 82,
"rcConsumed": 410,
"rcIncluded": 500,
"billingPeriod": "2026-05"
}
| Field | Type | Notes |
|---|---|---|
event | string | Always "credit.low". |
orgId | string | Your organization ID. |
timestamp | string | ISO 8601 UTC at the moment the threshold was crossed. |
usagePercent | number | RC consumption as a percentage of rcIncluded. |
rcConsumed | number | RCs consumed this period (includes any overage already accrued). |
rcIncluded | number | RCs included in your current plan tier. |
billingPeriod | string | YYYY-MM for the current Stripe billing period. |
credit.exhausted
Fires when the organization runs out of usable RCs — either the hard-block quota is hit, or the auto-overage cap is reached.
{
"event": "credit.exhausted",
"orgId": "org-12345",
"timestamp": "2026-05-05T14:50:01.000Z",
"rcConsumed": 500,
"rcIncluded": 500,
"overageCapReached": true,
"overageCap": 100,
"billingPeriod": "2026-05"
}
| Field | Type | Notes |
|---|---|---|
event | string | Always "credit.exhausted". |
orgId | string | Your organization ID. |
timestamp | string | ISO 8601 UTC at the moment the limit was hit. |
rcConsumed | number | Total RCs used this period. |
rcIncluded | number | RCs included in your plan. |
overageCapReached | boolean | true if the auto-overage cap was hit; false if the hard-block quota ran out. |
overageCap | number | The cap configured in Billing; 0 for hard-block plans. |
billingPeriod | string | YYYY-MM. |
plan.renewed
Fires when Stripe processes a subscription renewal — RCs reset, and a new billing period begins.
{
"event": "plan.renewed",
"orgId": "org-12345",
"timestamp": "2026-05-05T15:00:00.000Z",
"planTier": "team",
"rcIncluded": 400,
"billingPeriodStart": "2026-06-05",
"billingPeriodEnd": "2026-07-05",
"invoiceUrl": "https://invoice.stripe.com/i/acct_xxx/inv_yyy"
}
| Field | Type | Notes |
|---|---|---|
event | string | Always "plan.renewed". |
orgId | string | Your organization ID. |
timestamp | string | ISO 8601 UTC when the renewal was processed. |
planTier | string | "starter", "team", "business", or "enterprise". |
rcIncluded | number | RCs included in the new billing period. |
billingPeriodStart | string | ISO YYYY-MM-DD; first day of the new period. |
billingPeriodEnd | string | ISO YYYY-MM-DD; last day of the new period. |
invoiceUrl | string | HTTPS link to the Stripe-hosted invoice. |
Delivery semantics
- ADO Pilot sends each event once. There are no automatic retries on failure.
- If your endpoint is unreachable, slow, or returns a non-
2xxstatus, the event is dropped — it is not queued for later replay. - Monitor your endpoint health and alert on consecutive failures so you notice silently-broken integrations.
Troubleshooting
The test button is disabled. You have either typed an invalid URL, edited the URL since last save, or left the saved URL blank. Save a valid https:// URL first; the button enables once the input matches the saved value.
Webhook URL must be a valid https:// URL. The form rejects http://, hostnames without a scheme, and malformed URLs. Paste a full URL that starts with https://.
The test reports a 5-second timeout. Your endpoint accepted the connection but did not respond in time. Check downstream services your handler depends on; consider returning 2xx immediately and processing asynchronously.
The test returns an HTTP 4xx or 5xx. Your endpoint received the request but rejected it. Inspect your server logs — common causes are missing route handlers, body-parser misconfiguration, or auth middleware blocking unauthenticated requests.
Summary
Outgoing webhooks let you forward five ADO Pilot events — review.completed, review.failed, credit.low, credit.exhausted, and plan.renewed — to any HTTPS endpoint you control. Configure the URL on Settings then Notifications, pick the events you care about, and use Test webhook to verify delivery before you depend on it. The form rejects non-HTTPS URLs outright. Each event fires once with a 5-second response budget and no retries, so monitor your endpoint and alert on failures. Payload schemas on this page are provisional — pin to a published version once one exists, and watch the changelog for field renames or additions before general availability.