# Receive a monitoring tool's webhook

`POST https://evohub.io/ingest/{type}`

Part of the [Alert ingest API](https://docs.evohub.io/alert-ingest.md) reference · operationId `sendIntegrationWebhook`.

The endpoint each integration's webhook URL points at, shown with its
key in On-Call → Integrations. `type` selects the parser.

For `alerts` the body is EvoHub's generic alert (below). For every
other type it is the tool's own webhook payload, sent unchanged — a
firing alert opens an alert, and where the tool reports recovery, the
matching open alert is resolved. Most tools send JSON; UptimeRobot,
StatusCake, Site24x7 and PRTG may send form-encoded data (UptimeRobot
and StatusCake may also append fields to the URL's query string), and
those are read too.

Answers **200** whenever the payload was read, even if it produced no
alert, so tools do not disable the webhook; `created` and `resolved`
say what happened. An AWS SNS subscription confirmation sent to
`cloudwatch` or `eventbridge` is confirmed automatically and answered
with `created` 0 and a `note`. SNS deliveries must carry a valid SNS
signature.

`github`, `gitlab`, `jenkins` and `sonarqube` deliveries can be signed:
once the integration has a signing secret (On-Call → Integrations, or
the On-Call API's signing-secret endpoints), a delivery without a valid
signature is refused. GitHub signs with `X-Hub-Signature-256`, SonarQube
with `X-Sonar-Webhook-HMAC-SHA256`, GitLab sends the secret as
`X-Gitlab-Token` or signs with its signing token, and Jenkins sends it as
the Basic auth password or `X-EvoHub-Token`.

Two more routes live under `/ingest`: `/ingest/api` (the Events API,
above) and `/ingest/email`, where EvoHub's mail provider delivers the
mail sent to an Email integration's address. You send email to that
address; you never call `/ingest/email` yourself.

## Authorization

Requires:

- `integrationKey`

Where:

- `integrationKey`: API key in the query `key` — The integration key (the integration's API Key in On-Call → Integrations).

## Path parameters

- `type` (string, required, one of `alerts`, `prometheus`, `grafana`, `datadog`, `newrelic`, `cloudwatch`, `azuremonitor`, `dynatrace`, `sentry`, `googlecloud`, `zabbix`, `uptimerobot`, `pingdom`, `site24x7`, `statuscake`, `nagios`, `prtg`, `cortex`, `opensearch`, `uptimekuma`, `graylog`, `splunk`, `cloudflare`, `instana`, `netdata`, `eventbridge`, `elastic`, `opmanager`, `solarwinds`, `sumologic`, example `alerts`): The integration type.

## Query parameters

- `key` (string, required, example `YOUR_INTEGRATION_KEY`): The integration key. `eventbridge` also accepts it in an `X-EvoHub-Key` header and `honeycomb` in `X-Honeycomb-Webhook-Token`.

## Request body (required)

Content type: `application/json`

Type: `GenericAlert | object`

- One of:
  - GenericAlert
    - `title` (string, required, example `Disk almost full on web-03`)
    - `description` (string)
    - `status` (string): `resolved` (or `resolve`, `ok`, `up`, `online`, `recovered`, `closed`) resolves the open alert with this fingerprint; anything else, or nothing, opens or retriggers one.
    - `severity` (string, one of `critical`, `high`, `medium`, `low`, `info`, default `medium`): Common synonyms are read too (`error` and `major` as `high`, `warning` as `medium`, `minor` as `low`, `p1`–`p5`); anything else is `medium`.
    - `source` (string): Stored as the alert's `source` label; the alert's own source is always `webhook`.
    - `fingerprint` (string): Deduplicates repeated sends while the alert is open. When omitted, one is derived from the title, the labels and `alert_instance`/`alert_service`.
    - `escalation_policy_id` (string): Used only when the integration has no escalation policy of its own.
    - `labels` (object)
      - Other keys: string
    - `annotations` (object)
      - Other keys: string
  - Native payload: The monitoring tool's own webhook body, for every type except `alerts`.
    - Other keys: any

Content type: `application/x-www-form-urlencoded`

Type: `object`

Form-encoded bodies sent by `uptimerobot`, `statuscake`, `site24x7` and `prtg`.

- Other keys: string

## Responses

### 200 — The payload was read.

Content type: `application/json`

Type: `IngestResult`

- `data` (object)
  - `received` (integer): Alerts and recoveries found in the payload.
  - `created` (integer): Alerts opened, or matched to an alert already open with the same fingerprint.
  - `resolved` (integer): Recoveries processed.
  - `test` (boolean): Present and `true` when the delivery was the tool's test notification.
  - `note` (string): Present when the delivery needed no alert work, for example a test notification, an AWS SNS subscription confirmation, or a delivery already processed.
- `success` (boolean, value `true`)

### 400 — The body could not be read as this type's payload (`INVALID_BODY`); for `azuremonitor`, the common alert schema is not enabled (`INVALID_SCHEMA`); for `alerts`, `title` is missing, or a resolve has neither `fingerprint` nor `title` (`VALIDATION_FAILED`, with `details`).

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required, example `INVALID_KEY`)
  - `message` (string, required, example `invalid integration key`)
  - `details` (array of object): Field problems, on `VALIDATION_FAILED`.
    - `field` (string)
    - `message` (string)

### 401 — `key` is missing, unknown, or names a disabled integration (`INVALID_KEY`).

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required, example `INVALID_KEY`)
  - `message` (string, required, example `invalid integration key`)
  - `details` (array of object): Field problems, on `VALIDATION_FAILED`.
    - `field` (string)
    - `message` (string)

### 403 — For `github`, `gitlab`, `jenkins` and `sonarqube`: the integration has a signing secret and the delivery carries no signature, or one that does not verify (`INVALID_SIGNATURE`). For `cloudwatch` and `eventbridge`: an SNS message whose SNS signature does not verify (`INVALID_SIGNATURE`). On any other type: the key belongs to an integration with a signing secret, which only accepts signed deliveries on its own type (`SIGNATURE_REQUIRED`).

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required, example `INVALID_KEY`)
  - `message` (string, required, example `invalid integration key`)
  - `details` (array of object): Field problems, on `VALIDATION_FAILED`.
    - `field` (string)
    - `message` (string)

### 413 — The body is larger than 1 MiB (`PAYLOAD_TOO_LARGE`).

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required, example `INVALID_KEY`)
  - `message` (string, required, example `invalid integration key`)
  - `details` (array of object): Field problems, on `VALIDATION_FAILED`.
    - `field` (string)
    - `message` (string)

### 500 — The alert could not be stored (`INTERNAL_ERROR`).

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required, example `INVALID_KEY`)
  - `message` (string, required, example `invalid integration key`)
  - `details` (array of object): Field problems, on `VALIDATION_FAILED`.
    - `field` (string)
    - `message` (string)

### 503 — The key, the integration's signing secret, or an SNS message's signature could not be checked right now (`INGEST_UNAVAILABLE`). Retry after the delay given.

Headers:

- `Retry-After` (integer): Seconds to wait before retrying.

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required, example `INVALID_KEY`)
  - `message` (string, required, example `invalid integration key`)
  - `details` (array of object): Field problems, on `VALIDATION_FAILED`.
    - `field` (string)
    - `message` (string)

## Example request

```bash
curl -X POST 'https://evohub.io/ingest/alerts?key=<INTEGRATION_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
  "title": "Disk almost full on web-03",
  "labels": {
    "host": "web-03.acme.example"
  },
  "source": "cron-disk-check",
  "severity": "high",
  "description": "/var is at 93%",
  "fingerprint": "web-03-disk-var"
}'
```
