Platform reference
For every platform the recipe is the same: create a subscription, copy its ingest URL, and paste it into the platform's webhook config. This page has the exact events we accept, the setup steps, optional signing, and how each platform's states map to card statuses.
The secret key in your ingest URL already authenticates every call. Several platforms can additionally sign the payload with a shared secret for integrity — that secret is configured by whoever operates your deployment. It's optional and called out per platform below.
GitHub Actions
Accepts: the workflow_run event only (other events are rejected).
- Repo → Settings → Webhooks → Add webhook.
- Payload URL: your ingest URL. Content type:
application/json. - Events → Let me select individual events → check Workflow runs only.
- Add webhook. For all repos at once, configure it at Org → Settings → Webhooks.
Signing (optional): set a webhook secret; we verify X-Hub-Signature-256.
action + conclusion → status
requested / in_progress → started
completed + success/neutral/skip → success
completed + failure/timed_out → failure
completed + cancelled → cancelled
GitLab
Accepts: Pipeline events (object_kind: pipeline) and Deployment events.
- Project (or Group) → Settings → Webhooks.
- URL: your ingest URL. Triggers: Pipeline events + Deployment events.
- Keep SSL verification on → Add webhook. Group webhooks apply to all child projects.
Signing (optional): a secret token, sent verbatim in X-Gitlab-Token.
pipeline status → status deployment status → status
pending / running → started running → deployment_started
success → success success → deployment_success
failed → failure failed / canceled → deployment_failure
canceled / skipped / manual → cancelled
Jenkins
Accepts: the Notification Plugin payload (the de-facto Jenkins standard).
- Install the Notification Plugin (Manage Plugins).
- Job → Configure → Job Notifications → Add Endpoint.
- Format JSON · Protocol HTTP · Event Job Finalized (or All Events for started cards) · URL your ingest URL. Save.
phase / status → status
STARTED / QUEUED → started
FINALIZED + SUCCESS → success
FINALIZED + UNSTABLE → unstable
FINALIZED + ABORTED → cancelled
FINALIZED + FAILURE/NOT_BUILT → failure
Azure DevOps
Accepts: run-state-changed (YAML pipelines) and build.complete (classic).
- Project → Project Settings → Service Hooks → New Subscription → Web Hooks.
- Trigger: Run state changed (YAML) or Build completed (classic). Optionally filter by pipeline/branch/state.
- URL: your ingest URL. Save.
state / result → status
inProgress / queued / notStarted → started
result=succeeded → success
result=partiallySucceeded → unstable
result=canceled → cancelled
any other terminal result → failure
Bitbucket Pipelines
Accepts: repo:commit_status_created / updated events.
- Repo → Repository settings → Webhooks → Add webhook.
- URL: your ingest URL. Triggers → Build: Commit status created + updated.
Bitbucket Cloud doesn't sign payloads — the ingest-URL key is the authentication on that path.
commit_status.state → status
INPROGRESS → started
SUCCESSFUL → success
FAILED → failure
STOPPED → cancelled
CircleCI
Accepts: v2 workflow-completed (preferred) and job-completed.
- Project → Project Settings → Webhooks.
- Webhook URL: your ingest URL. Events: workflow-completed.
Signing (optional): a secret; we verify Circleci-Signature: v1=… (HMAC-SHA256).
status → status
success → success
failed / error / unauthorized → failure
canceled / not_run / on_hold → cancelled
Buildkite
Accepts: build.scheduled/started/running/finished events.
- Organization settings → Notification services → Add Webhook.
- Webhook URL: your ingest URL. Pick the build events you want.
Signing (optional): a token verified against BUILDKITE_WEBHOOK_TOKEN.
event / build.state → status
scheduled / started / running → started
passed → success
failed → failure
canceled / skipped / not_run / blocked → cancelled
Argo CD
Accepts: a purpose-built notification payload (Argo CD notifications are template-driven, so you define the body). Argo CD is a CD tool, so events render as deployment cards.
In your argocd-notifications-cm ConfigMap, add a webhook service, a template that
POSTs the app's status, and a trigger — then annotate the Applications you want notified:
service.webhook.pmlw: |
url: <your ingest URL>
headers: [{ name: Content-Type, value: application/json }]
template.pmlw-deploy: |
webhook:
pmlw:
method: POST
body: |
{
"app": "{{.app.metadata.name}}",
"project": "{{.app.spec.project}}",
"syncStatus": "{{.app.status.sync.status}}",
"healthStatus": "{{.app.status.health.status}}",
"operationPhase": "{{.app.status.operationState.phase}}",
"revision": "{{.app.status.sync.revision}}",
"appUrl": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
}
trigger.on-deploy: |
- when: app.status.operationState.phase in ['Succeeded','Failed','Error','Running']
send: [pmlw-deploy]
Then on each Application:
notifications.argoproj.io/subscribe.on-deploy.pmlw: "".
operationPhase / health / sync → status
Succeeded → deployment_success
Failed / Error → deployment_failure
Running / Terminating → deployment_started
(no phase) Degraded / Missing → deployment_failure
(no phase) Progressing / Suspended→ deployment_started
(no phase) Healthy + Synced → deployment_success
TeamCity
Accepts: a purpose-built JSON payload. TeamCity webhooks — the native Webhooks build feature or the tcWebHooks plugin — are template-driven, so you map TeamCity build parameters into these fields:
- On the build configuration, add a webhook (native feature or tcWebHooks) with URL = your ingest URL.
- Set the payload template to produce this JSON:
{
"buildName": "<project> :: <build config>",
"buildNumber": "128",
"buildResult": "success", // success | failure | running | canceled | unstable
"branch": "main",
"commitSha": "<vcs revision>",
"buildUrl": "<server>/build/<id>"
}
buildResult → status
success → success
running → started
unstable → unstable
canceled → cancelled
failure / error → failure
Datadog
Accepts: a purpose-built JSON payload built from Datadog's webhook template variables. Datadog is observability, so a monitor alert renders as a status card.
- Datadog → Integrations → Webhooks → New. URL = your ingest URL.
- Set the Payload to:
{
"title": "$EVENT_TITLE",
"alertStatus": "$ALERT_STATUS",
"priority": "$PRIORITY",
"tags": "$TAGS",
"eventUrl": "$LINK",
"id": "$ID",
"date": "$DATE"
}
- In each monitor's notification message, add
@webhook-<name>to fire it.
alertStatus → status
Recovery / OK → success
Warn / No Data → unstable
Alert → failure
Grafana
Accepts: the Grafana unified-alerting webhook payload — it's fixed, so no
template is needed. status: firing → failure, resolved → success.
- Grafana → Alerting → Contact points → Add contact point → type Webhook.
- URL: your ingest URL. Save, then attach it to a notification policy.
status → status
firing → failure
resolved → success
Drone CI
Accepts: Drone's build webhook payload — fixed, no template.
- Add a webhook (global via
DRONE_WEBHOOK_ENDPOINT, or repo settings) → URL: your ingest URL.
build.status → status
success → success
running / pending → started
killed / skipped → cancelled
failure / error → failure
Sentry
Accepts: a purpose-built JSON payload (Sentry's webhook shapes vary by integration, so you define the body in an alert rule's webhook action).
- Sentry → Alerts → Create Alert Rule → add a webhook / internal-integration action with your ingest URL.
- Send this JSON:
{
"title": "<issue title>",
"level": "error", // fatal | error | warning | info
"status": "unresolved", // unresolved | resolved | ignored
"project": "<project>",
"environment": "production",
"url": "<issue url>"
}
status / level → status
status resolved → success
status ignored → cancelled
level warning → unstable
fatal / error / (default) → failure
PagerDuty
Accepts: the PagerDuty v3 generic-webhook payload (fixed — no template). Incident lifecycle maps onto a status.
- PagerDuty → Integrations → Generic Webhooks (v3) → New Webhook.
- Webhook URL: your ingest URL. Subscribe to incident events.
event_type / status → status
incident.resolved → success
incident.acknowledged → started
incident.triggered / etc. → failure
Prometheus Alertmanager
Accepts: the Alertmanager webhook_configs payload (fixed — no template).
status: firing → failure, resolved → success.
route:
receiver: pmlw
receivers:
- name: pmlw
webhook_configs:
- url: <your ingest URL>
Octopus Deploy
Accepts: a purpose-built JSON payload (Octopus subscription webhooks are event-category driven, so you shape the body). Octopus is a CD tool → deployment cards.
- Octopus → Configuration → Subscriptions → new subscription for deployment events, with a webhook to your ingest URL.
- Body:
{
"project": "Web Storefront",
"environment": "Production",
"release": "2.3.0",
"state": "Success", // Success | Failed | Executing | Queued | Canceled
"deploymentUrl": "<deployment url>"
}
state → status
Success → deployment_success
Executing / Queued → deployment_started
Failed / TimedOut / Canceled→ deployment_failure
Generic JSON
Anything that can POST JSON works via the generic platform. When you create the subscription,
supply a field mapping — declarative paths into the payload for title,
status, link, summary, and optional facts, plus a
statusMap that maps your raw status strings to success / failure / running / neutral.
Then point the tool's webhook at your ingest URL. Great for Datadog monitors, custom scripts, or any CI we
don't have a dedicated normalizer for yet.
The generic platform covers most cases. Want a first-class normalizer for a tool we don't list yet? Tell us — it's a mechanical add and we prioritize by demand.