EvoHub Docs Sign in
EnglishEN

Integrations

Alert API and generic webhook

Use with AI
View as MarkdownThis page as plain text, for pasting into an AI tool Open in ClaudeAsk Claude questions about this page Open in ChatGPTAsk ChatGPT questions about this page
Connect to Cursor / VS Code / ClaudeSearch and read these docs from your AI tool (MCP server)

MCP server URL

https://docs-dev.evohub.io/mcp

Claude Code

claude mcp add --transport http evohub-docs-docs https://docs-dev.evohub.io/mcp

Claude (claude.ai and Claude Desktop): Settings → Connectors → Add custom connector, and paste the URL above.

Claude Desktop — claude_desktop_config.json

{
  "mcpServers": {
    "evohub-docs-docs": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://docs-dev.evohub.io/mcp"
      ]
    }
  }
}

Cursor — ~/.cursor/mcp.json

{
  "mcpServers": {
    "evohub-docs-docs": {
      "url": "https://docs-dev.evohub.io/mcp"
    }
  }
}

VS Code — .vscode/mcp.json

{
  "servers": {
    "evohub-docs-docs": {
      "type": "http",
      "url": "https://docs-dev.evohub.io/mcp"
    }
  }
}

If your tool is not in the catalog, or you want to raise alerts from your own code, use the API integration. It accepts a small JSON body in which only a summary is required, and it can also acknowledge and resolve alerts. Its body is compatible with the Events v2 shape used by other paging tools, so a tool that already speaks it only needs a new URL and key.

Set up the API integration

Create the integration

Go to On-Call → Integrations → + Add Integration, choose API, choose an Escalation Policy and click Create Integration.

Copy the URL and key

Open the integration. The Webhook URL is https://evohub.io/ingest/api?key=<key>; the API Key is the key on its own.

Send a test event

Run the curl example below with your key and check that an alert appears in On-Call → Alerts.

Send an event

POST https://evohub.io/ingest/api with a JSON body. Send the integration key in whichever way your tool makes easiest:

  • "routing_key" in the body,
  • ?key= in the URL, or
  • an Authorization: Bearer <key> header.

Minimal trigger

curl -X POST 'https://evohub.io/ingest/api' \
  -H 'Authorization: Bearer YOUR_INTEGRATION_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"summary": "Database primary is down"}'

Full trigger

curl -X POST 'https://evohub.io/ingest/api' \
  -H 'Content-Type: application/json' \
  -d '{
    "routing_key": "YOUR_INTEGRATION_KEY",
    "event_action": "trigger",
    "dedup_key": "db-primary-down",
    "payload": {
      "summary": "Database primary is down",
      "source": "db-01.prod.acme.example",
      "severity": "critical",
      "component": "postgres",
      "group": "payments",
      "custom_details": { "region": "eu-central" }
    }
  }'

Resolve

curl -X POST 'https://evohub.io/ingest/api' \
  -H 'Content-Type: application/json' \
  -d '{
    "routing_key": "YOUR_INTEGRATION_KEY",
    "event_action": "resolve",
    "dedup_key": "db-primary-down"
  }'

Request fields

You can send the alert details nested in payload (Events v2 style) or as flat fields at the top level. A flat field fills the matching payload field when that one is empty.

Field Required Description
routing_key No* The integration key. *Required unless sent as ?key= or a bearer token.
event_action No trigger (default), acknowledge or resolve.
dedup_key For acknowledge and resolve Identifies the alert. On a trigger without one, EvoHub derives a key from the summary and source and returns it.
payload.summary / summary / title For trigger The alert's title.
payload.severity / severity No critical, high, medium, low or info. The Events v2 values are accepted too: error is read as high and warning as medium. Anything else, or nothing, is medium.
payload.source / source No Where the problem is, for example a host name. Stored as the source label.
description / payload.description No The alert's description.
payload.component, payload.group, payload.class No Stored as labels of the same name.
payload.custom_details No An object; each entry becomes a label, its value as text.
payload.timestamp, client, client_url No Accepted for compatibility and ignored. The alert is stamped when it arrives.

Response

A processed event returns 202:

{
  "data": {
    "status": "success",
    "message": "Event processed",
    "dedup_key": "db-primary-down"
  },
  "success": true
}

Keep the dedup_key if you let EvoHub derive it — you need it to resolve the alert later.

A request that was not processed returns the same envelope with "status": "invalid event" and a message:

Status When Example message
400 The body is not JSON, a trigger has no summary, an acknowledge or resolve has no dedup_key, or event_action is unknown. summary is required
401 No key was sent, or it names no enabled integration. invalid routing_key
500 The alert could not be created, acknowledged or resolved. failed to create alert
503 The key could not be checked right now. Retry after the Retry-After seconds. could not verify routing_key right now; retry later

How events behave

  • Trigger opens an alert and starts the integration's escalation policy. A trigger whose dedup_key matches an alert that is still open does not open a second one; it is recorded as Retriggered on the existing alert.
  • Acknowledge acknowledges the open, triggered alert with that dedup_key.
  • Resolve resolves the open alert with that dedup_key.
  • Acknowledging or resolving a dedup_key that has no open alert does nothing and still returns 202.
  • The integration's escalation policy always applies; the request cannot choose another one.

Generic alert webhook

EvoHub also accepts a simpler, flat alert format at /ingest/alerts. Use it with the key of your API integration:

curl -X POST 'https://evohub.io/ingest/alerts?key=YOUR_INTEGRATION_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Disk almost full on web-03",
    "description": "/var is at 93%",
    "severity": "high",
    "source": "cron-disk-check",
    "fingerprint": "web-03-disk-var",
    "labels": { "host": "web-03.acme.example" },
    "annotations": { "runbook": "https://wiki.acme.example/disk" }
  }'
Field Required Description
title Yes The alert's title.
description No The alert's description.
severity No critical, high, medium (default), low or info.
source No Shown as the alert's source. Defaults to webhook.
fingerprint No Deduplicates repeated sends while the alert is open.
labels, annotations No String-to-string maps, shown on the alert and usable in the voice template.
escalation_policy_id No Used only when the integration has no escalation policy of its own.

The key goes in ?key= only. A missing title returns 400 with the code VALIDATION_FAILED and the field in details; a bad key returns 401 with INVALID_KEY. A successful call returns 200 with {"data": {"received": 1, "created": 1, "resolved": 0}, "success": true}. This format cannot acknowledge or resolve; use the API events above for that.

Tips

  • Choose a stable dedup_key (or fingerprint) per problem, such as <host>-<check>, so repeats while the problem lasts do not open new alerts and your resolve finds the right alert.
  • Send a resolve when your check passes again. Without one, the alert stays open until someone resolves it.
  • Only new alerts count toward usage; retriggers of an open alert do not. See How billing works.

Last updated