Azure DevOps integration
Two paths into ActivityLog from Azure DevOps:
- Service Hooks (webhooks) — recommended for operational activity: code pushes, pull requests, work items, builds, releases. Real-time, one message per event.
- Event Grid — alternative for org-level admin activity via a Service Bus relay or custom topic. Same destination URL as webhooks.
Both land in a single ActivityLog system through one webhook URL. Service Hooks feed the Change control report.
Quick path — Service Hooks
1. Generate a webhook URL
In the ActivityLog portal → Systems → + Mint new system named devops (or any name ending in devops, such as acme-devops, so the Change control report finds it) → open the system → Webhook endpoint panel → Generate webhook URL → copy the URL from the dialog.
Your full URL looks like:
https://api.activitylog.com/api/v1/webhooks/alw_REPLACE_WITH_YOUR_TOKEN
See 53-ingest-webhooks.md for the underlying webhook contract.
2. Configure ADO Service Hooks
In your ADO project → Project Settings → Service hooks → + Create subscription. For each event type you want, repeat:
| Service | Trigger | Action URL |
|---|---|---|
| Web Hooks | Code pushed | https://api.activitylog.com/api/v1/webhooks/alw_REPLACE_WITH_YOUR_TOKEN |
| Web Hooks | Pull request created | same |
| Web Hooks | Pull request updated | same |
| Web Hooks | Pull request merge attempted | same |
| Web Hooks | Build completed | same |
| Web Hooks | Release deployment started | same |
| Web Hooks | Release deployment completed | same |
| Web Hooks | Release deployment approval pending / completed | same (optional) |
| Web Hooks | Work item created | same |
| Web Hooks | Work item updated | same |
Settings on each subscription:
- Basic authentication: leave blank.
- Resource details to send: All.
- Messages to send: All.
- Detailed messages to send: All.
Click Test before saving — you should see HTTP 201 in the response.
3. Verify in ActivityLog
Trigger one of the events (push a commit, open a PR) and check the Messages page in the portal (/portal/messages?system=devops shows just this system). The message should appear within a couple of seconds with a type such as webhook.ado.git.push.
Message types you'll see
Each ADO event becomes one message. Its type is webhook.ado. followed by the ADO eventType:
| ADO event | ActivityLog type |
|---|---|
| Code pushed | webhook.ado.git.push |
| Pull request created | webhook.ado.git.pullrequest.created |
| Pull request updated (incl. completed / abandoned) | webhook.ado.git.pullrequest.updated |
| Pull request merge attempted | webhook.ado.git.pullrequest.merged |
| Build completed | webhook.ado.build.complete |
| Release deployment started / completed | webhook.ado.ms.vss-release.deployment-started-event / …deployment-completed-event |
| Work item created / updated | webhook.ado.workitem.created / webhook.ado.workitem.updated |
What the API adds for change control
Azure DevOps names the same thing several ways, so when a service hook arrives the API reads the full payload once and adds a small set of plain fields at the top level of the stored body. The original payload is kept alongside (on Free, the lean projection is kept; the added fields survive it). The type is never renamed.
| Field | Contents |
|---|---|
change.kind |
pr.created, pr.updated, pr.merged (completed), pr.abandoned, pr.merge_attempted, push, build.completed, deploy.started, deploy.completed, deploy.approval |
pull_request |
id, status, source_branch, target_branch, reviewers[{name, vote}], approved |
push |
id, branches[], and pr_completion: true when the push is the merge commit behind a completed pull request |
build |
result, definition, number, source_branch, source_version |
deploy |
environment, result, release, definition |
repo |
repository name |
Then it adds the approval state, change.state:
- Pull request completed (
pr.merged):approvedwhen any reviewer voted 5 or more (10 is "approved", 5 is "approved with suggestions", which Azure DevOps branch policies also accept), otherwiseunapproved. Votes are read from the event itself. - Push to
mainormaster:direct_push, unless the push is the merge commit Azure DevOps makes when it completes a pull request. That push is recognised by a commit comment starting withMerged PRand gets no state, so completing a reviewed pull request never shows up as a direct push. - Anything else: no state.
The Change control report counts these through the change_kind, change_state, repo, environment, build_result and deploy_result facets (90-reports.md). Messages stored before these fields existed carry no change.kind and are not counted.
A pull request completed with a custom merge-commit message (for example a squash merge whose message you edited) does not start with
Merged PR, so its push tomainis counted as adirect_push.
Storage mode
DevOps webhooks store the full ADO payload on Pro and Enterprise — the 3–18 KB JSON is kept as-is in body next to the fields above. This preserves source-curated context (commit lists, PR descriptions, build pipeline refs).
On the Free tier, payloads are projected down to a lean ~1 KB body (event type, actor, target, summary) plus the change-control fields above. See 53-ingest-webhooks.md.
Event Grid alternative
If you have an Event Grid topic that already aggregates ADO events, the same webhook URL accepts Event Grid's array-of-events format — see 53-ingest-webhooks.md. Activity that arrives as an Event Grid array does not get the change-control fields, so use Service Hooks for the Change control report.
Audit log API (admin activity)
Service Hooks don't cover org-level admin activity (project creation, permission changes, policy changes). For those, the ADO Audit Log API is the canonical source. Pulling that into ActivityLog is not built today. For now, customers who need it pull via an Azure Function or scheduled script and POST to the webhook URL.
Retries and idempotency
ADO retries failed webhook deliveries with backoff. When a delivery carries ADO's X-VSS-EventId header (or you add ?sourceEventId= to the URL), that value is the idempotency key: a repeat delivery is answered 200 { "deduplicated": true } and stores nothing new.
Subscription health monitoring
ADO disables a Service Hook after repeated failures. If you see activity dry up, check Project Settings → Service hooks → History for the affected subscription and re-enable / re-test.
What's next
| Goal | Doc |
|---|---|
| The Change control report | 90-reports.md |
| Webhook endpoint behaviour in detail | 53-ingest-webhooks.md |
| Full ADO event catalogue + metadata schema | ../../../ActivityLog-Integrations/DevOps/SPEC.md |
| Cross-source query: ADO + Teams + Claude together | 60-query-api.md |
Troubleshooting
ADO subscription test shows 404 webhook-not-found. The URL is wrong or was rotated / revoked. Copy the current URL from the system's Webhook endpoint panel (rotate it if you no longer have it).
Activity stops appearing after a stretch of working fine. Check the Service Hook history in ADO — most likely the subscription was disabled after a transient outage. Re-enable and re-test.
Change control shows no data, but Messages shows the ADO activity.
Check that the system's name ends in devops (the report finds it by kind) and that the Change control facets exist for your tenant; the report names any missing facet in its empty state.
I want PR comment bodies and commit diffs. Not stored today. If you have a use case, file a ticket.