Appearance
Sources
Sources are incoming webhooks that create Pulses. Configure them in the app under Connections → Sources.
This is not Context (enrichment at triage time) and not Notifications (outbound after triage). See the Connections overview.
Today: paging sources — PagerDuty, JSM Operations (Opsgenie), Splunk On-Call, and incident.io — plus observability sources — Grafana, Datadog, Alertmanager, New Relic, Sentry, Honeycomb, Elastic Observability, Dynatrace, and AWS CloudWatch — and tenant manual webhooks are production ingest paths.
Hosted ingest URLs use /webhooks/... on https://exhaleoncall.com. Session and admin routes in these guides are written as /v1/auth/...; the app calls them under /api. See API versioning.
How ingest works (all sources)
Every incoming source follows the same pipeline:
- Authenticate — vendor signature, shared secret, or tenant token (per source).
- Size limit — reject bodies over the configured maximum (default 1 MiB → 413).
- Dedupe — delivery id and/or
(tenant_id, source, external_id)to avoid duplicate Pulses. - Scrub — regex + structural masking before persist and before LLM.
- Resolve tenant — pulse source registry (an account hint on an account-mapped paging source, or a webhook token).
- Upsert pulse — set
source,external_id, title, status, ephemeralpayload. - Enqueue triage — when async triage is enabled and lifecycle rules allow.
Shipped today
| Source | Endpoint | Pulse source | Guide |
|---|---|---|---|
| PagerDuty | POST /webhooks/pagerduty | pagerduty | PagerDuty webhooks |
| JSM Operations (Opsgenie) | POST /webhooks/opsgenie (header X-Exhale-Webhook-Token) or POST /webhooks/opsgenie/{token} | opsgenie | JSM Operations (Opsgenie) |
| Splunk On-Call | POST /webhooks/splunk-oncall (header X-Exhale-Webhook-Token) or POST /webhooks/splunk-oncall/{token} | splunk_oncall | Splunk On-Call |
| incident.io | POST /webhooks/incident-io (header X-Exhale-Webhook-Token) or POST /webhooks/incident-io/{token} | incident_io | incident.io |
| Grafana | POST /webhooks/grafana (header X-Exhale-Webhook-Token) or POST /webhooks/grafana/{token} | grafana | Grafana |
| Datadog | POST /webhooks/datadog (header X-Exhale-Webhook-Token) or POST /webhooks/datadog/{token} | datadog | Datadog |
| Prometheus Alertmanager | POST /webhooks/alertmanager (header X-Exhale-Webhook-Token) or POST /webhooks/alertmanager/{token} | alertmanager | Alertmanager |
| New Relic | POST /webhooks/newrelic (header X-Exhale-Webhook-Token) or POST /webhooks/newrelic/{token} | new_relic | New Relic |
| Sentry | POST /webhooks/sentry (header X-Exhale-Webhook-Token) or POST /webhooks/sentry/{token} | sentry | Sentry |
| Honeycomb | POST /webhooks/honeycomb (header X-Exhale-Webhook-Token) or POST /webhooks/honeycomb/{token} | honeycomb | Honeycomb |
| Elastic Observability | POST /webhooks/elastic (header X-Exhale-Webhook-Token) or POST /webhooks/elastic/{token} | elastic | Elastic |
| Dynatrace | POST /webhooks/dynatrace (header X-Exhale-Webhook-Token) or POST /webhooks/dynatrace/{token} | dynatrace | Dynatrace |
| AWS CloudWatch | POST /webhooks/aws-cloudwatch (header X-Exhale-Webhook-Token) or POST /webhooks/aws-cloudwatch/{token} | aws_cloudwatch | AWS CloudWatch |
| Manual webhook | POST /webhooks/manual (header X-Exhale-Webhook-Token) or POST /webhooks/manual/{token} | other (UI: Manual webhook) | Manual webhook |
Customer setup: Connections → Sources. Account-mapped paging sources use self-serve account id registration and a shared webhook URL. Token-auth sources use a per-tenant URL token from Connect (manual webhooks also use HMAC).
A token webhook URL is a credential. Treat the URL like a password and share it only with people who should create Pulses. Exhale stores only a hash for lookup and does not return the URL to teammates with the Viewer role. Owners, admins, and members can read it; only admins and owners can rotate it, and the previous URL stops working right away. PagerDuty is the exception: /webhooks/pagerduty carries no token and stays visible to every role.
Incoming slots: Trial/Starter allow one primary paging ingest source and a separate supporting observability pool (Trial 1, Starter 3, Growth primary 3 / supporting 8, Business primary 10 / supporting 25). Enterprise is unlimited. Manual and OAuth connections for the same vendor share one slot (JSM Operations). Each named manual webhook endpoint occupies one primary or supporting slot. New connect returns 403 when the tenant is at cap; ingest for an already-wired source is unchanged.
Sources vs Context vs Notifications
| Track | Purpose | Examples |
|---|---|---|
| Sources (this section) | Creates Pulses | Paging and observability webhooks |
| Context | Enrichment at triage time | Grafana API key, GitHub repos, markdown runbooks |
| Notifications | Outbound after triage | Slack, Teams, email, SMS |
Some vendors appear in both Sources and Context. Connect the webhook if that vendor should create Pulses. Connect Context if you want enrichment on Pulses that already exist.
Use the guides above for signing, dedupe, tenancy, and lifecycle behavior. Source setup in the app uses an admin session and CSRF.