Azure DevOps integration

Two paths into ActivityLog from Azure DevOps:

  1. Service Hooks (webhooks) — recommended for operational activity: code pushes, pull requests, work items, builds, releases. Real-time, one message per event.
  2. 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): approved when any reviewer voted 5 or more (10 is "approved", 5 is "approved with suggestions", which Azure DevOps branch policies also accept), otherwise unapproved. Votes are read from the event itself.
  • Push to main or master: 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 with Merged PR and 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 to main is counted as a direct_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.