# Generic JSON Alerts

> Send alerts to Edesy OnCall from any script or tool with one JSON POST - status, title, message and dedup_key fields, accepted status words, curl examples, responses and limits.

Source: https://edesy.in/docs/oncall/ingest/generic-json

Anything that can make an HTTP POST can raise an OnCall incident: a deploy script, a queue consumer, a CI job or another monitoring tool. Create an **Alert webhook** monitor and post JSON to its URL.

```
POST https://oncall.edesy.in/ingest/<token>
Content-Type: application/json
```

## Fields

| Field | Required | Description |
|---|---|---|
| `status` (or `state`) | Yes | Whether the problem is happening (see below) |
| `title` | No | Short name, read aloud on the call. Default "Alert". Up to 200 characters |
| `message` | No | Detail, shown in the incident and in emails. Up to 300 characters |
| `dedup_key` | No | Alerts with the same key update one incident instead of opening new ones |

### Status words

| Opens (or keeps open) an incident | Resolves it |
|---|---|
| `down`, `firing`, `critical`, `alert`, `alerting`, `error`, `fail`, `failed`, `problem`, `trigger`, `triggered` | `up`, `resolved`, `ok`, `recovered`, `normal` |

Case doesn't matter. Any other value returns `400`.

## Examples

```bash
# Open (or keep open) an incident
curl -fsS -X POST https://oncall.edesy.in/ingest/<token> \
  -H 'Content-Type: application/json' \
  -d '{"status":"down","title":"Order sync down","message":"503 from the load balancer","dedup_key":"order-sync"}'

# Resolve it
curl -fsS -X POST https://oncall.edesy.in/ingest/<token> \
  -H 'Content-Type: application/json' \
  -d '{"status":"resolved","title":"Order sync down","dedup_key":"order-sync"}'
```

To resolve, send the same `dedup_key` you used to open. Without a `dedup_key`, keep it consistent (an empty key is a key too), or resolve from the portal.

## How OnCall picks the format

The ingest URL accepts several formats and detects them from the body:

| Body has | Treated as |
|---|---|
| `alerts` plus `orgId`, `dashboardURL` or `panelURL` | [Grafana](https://edesy.in/docs/oncall/ingest/grafana) |
| `alerts` | [Prometheus Alertmanager](https://edesy.in/docs/oncall/ingest/alertmanager) |
| `heartbeat` or `monitor` | [Uptime Kuma](https://edesy.in/docs/oncall/ingest/uptime-kuma) |
| Anything else | Generic JSON (this page) |

If your own JSON happens to contain one of those keys, add `?format=generic` to the URL. The other values are `alertmanager`, `grafana` and `uptimekuma`.

## Responses and limits

| Status | Body |
|---|---|
| `202` | `{"data":{"accepted":1}}` |
| `400` | `invalid_payload`, for example `"status" must be "down" or "up"` |
| `404` | `not_found`: unknown ingest URL |

- Body up to 1 MB.
- 120 requests a minute per IP address.
- No API key: the secret token in the URL identifies the monitor. Keep it private and rotate it on the monitor page if it leaks.
- A paused monitor accepts alerts but ignores them.

## FAQ

**Can one URL handle several different problems?**
Yes. Use a different `dedup_key` for each; each key gets its own incident, and they all use the monitor's escalation policy.

**What does the person on call hear?**
"This is an alert from *your organisation*. *Monitor name* is down since *time*. Reason: *title: message*." Keep both short.

**Is there a signature or HMAC?**
No. The token in the URL is the secret.
