Appearance
Errors & authentication
This page covers structured API errors, correlation ids, and how customers authenticate to Exhale APIs. Webhook ingest uses per-source verification — HMAC for PagerDuty and manual webhooks; URL/header tokens for most other sources. See the integrations index and guides linked below.
Full route catalog: API reference.
Structured errors
Non-success responses use a consistent JSON shape:
json
{
"error": {
"code": "NOT_FOUND",
"message": "Pulse … not found",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000"
}
}| Field | Description |
|---|---|
code | Machine-readable error code (e.g. NOT_FOUND, VALIDATION_ERROR, UNAUTHORIZED) |
message | Human-readable detail |
correlation_id | Request id for support and log lookup |
Every response includes an X-Correlation-Id header. Clients may send their own value; otherwise the API generates a UUID. Match this id in support requests.
| HTTP | Typical code | When |
|---|---|---|
| 400 | BAD_REQUEST | Missing required webhook fields, invalid Content-Length |
| 401 | UNAUTHORIZED | Bad or missing signature / session |
| 403 | FORBIDDEN | Viewer role, disabled tenant, expired trial |
| 404 | NOT_FOUND | Unknown pulse, unmapped PagerDuty account, unknown webhook token |
| 409 | CONFLICT | Conflicting state (e.g. retry-triage race, billing conflict) |
| 413 | PAYLOAD_TOO_LARGE | Body over size limit (default 1 MiB) |
| 422 | VALIDATION_ERROR | Schema validation failure |
| 429 | RATE_LIMITED | Per-IP webhook or API rate limit (Retry-After) |
| 503 | (varies) | Redis fail-closed, maintenance, ambiguous account mapping |
| 500 | INTERNAL_ERROR | Unexpected server error |
Customer authentication
Session cookie (primary)
Customer UI and /auth routes use the exhale_session HTTP-only cookie after login or signup.
Mutating /auth routes require:
- Valid session
X-CSRF-Tokenheader matching the CSRF cookie (double-submit pattern)
In staging and production, mutating routes also require Origin or Referer from an allowed browser UI origin.
MFA (TOTP): Paid tenant admins may be required to enroll in TOTP before full session access when admin MFA is required. Trial signups and optional member/viewer MFA policies are configured under Settings → Account → Sign-in & MFA.
Integration setup routes (PUT /auth/integrations/*, manual webhook connect, etc.) use session + CSRF. See OpenAPI security schemes SessionCookie and CsrfHeader.
API key bridge (operations)
When the platform operator configures API_KEY and PULSES_API_KEY_BRIDGE_ENABLED=true, requests may authenticate with:
X-API-Key: <platform-api-key>This scopes GET /pulses and related ops-bridge routes to the dev tenant only — not arbitrary tenant data. The bridge is off by default in staging and production; production customer access uses sessions or tenant API keys.
OpenAPI scheme: ApiKeyAuth.
Tenant API keys (customer)
Tenant admins issue keys under Settings → Security & data → API keys (GET/POST /auth/api-keys, revoke). Secrets are shown once (exh_… prefix); only a hash is stored.
X-API-Key: exh_<secret>Scopes: read for list/get; admin also allows retry-triage and archive. Keys are tenant-scoped (not the platform bridge).
Webhook authentication
Webhooks do not use session cookies. Each source has its own verification:
| Auth style | Sources | How |
|---|---|---|
| HMAC signature | PagerDuty, Manual webhook | HMAC-SHA256 of the raw body as v1=<hex> (X-PagerDuty-Signature or X-Exhale-Signature). Manual also requires X-Exhale-Webhook-Token (header route) or a path token. |
| URL / header token | OpsGenie, Splunk On-Call, Grafana, Datadog, Alertmanager, New Relic, Sentry, Honeycomb, Elastic, Dynatrace, AWS CloudWatch | Opaque tenant token via header X-Exhale-Webhook-Token (preferred) or POST /webhooks/{source}/{token}. No vendor HMAC. |
OpenAPI schemes: PagerDutySignature, ExhaleSignature, ExhaleWebhookToken.
Pulses API (tenant-scoped)
GET /pulses, GET /pulses/{id}, timeline/notes routes, and POST /pulses/{id}/retry-triage require:
- Valid
exhale_sessioncookie, or - Tenant API key (
X-API-Keystarting withexh_), or - Platform
X-API-Keywhen the pulses bridge is enabled (dev-tenant only)
Mutations that change tenant data from the browser (archive, notes, feedback) also require X-CSRF-Token. Retry-triage with a tenant API key requires admin scope.
Cross-tenant pulse ids return 404. Retry with a session requires member or admin role; viewers receive 403.
List responses include X-Total-Count for pagination.
Health
| Endpoint | Purpose |
|---|---|
GET /health | Database, Redis, triage queue depth — healthy or degraded (always 200) |
GET /health/live | Process liveness for load balancers (no dependency checks) |
Neither endpoint requires authentication.
Published OpenAPI policy
Live Swagger UI (/docs), ReDoc (/redoc), and /openapi.json are disabled on staging and production API hosts. Only local development / test expose those explorers on the API.
Use this documentation site’s API reference for the published (integrator-filtered) OpenAPI schema.