# Event fields and severities

> Every field POST /v1/events accepts, severities, dedup, recovery and error responses.

Web page: https://infrainbox.app/docs/reference/event-fields/

`POST /v1/events`, authenticated with a source key (`Authorization: Bearer iik_src_…`), takes either one event's fields at the top level, or a batch as `{"events": [...]}` of up to **100** events. `title` is required either way. See [Events API](https://infrainbox.app/docs/sources/events-api.md) for worked examples.

## Fields

| Field | Type | Required | Limit | Notes |
|---|---|---|---|---|
| `title` | string | yes | 256 characters (truncated) | What happened, in one line. Blank is rejected (422). |
| `severity` | string | no | — | See [Severities](#severities) below. Missing means `INFO`. |
| `action` | string | no | — | `trigger` (default) or `resolve`. `resolve` needs a `dedupKey`. |
| `type` | string | no | 128 characters | Lowercase, `[a-z0-9][a-z0-9_.-]*`, e.g. `backup.failed`. |
| `resource` | string | no | 128 characters | What it's about, as `kind:name`, e.g. `vm:103`. |
| `dedupKey` | string | no | 255 characters | The strongest grouping key — see [Fingerprint and dedup](https://infrainbox.app/docs/incidents/how-incidents-work.md#fingerprint-and-dedup). Compared verbatim, case-sensitively. |
| `body` | string | no | 16,384 characters (truncated) | Plain-text detail. |
| `tags` | array of string | no | 20 tags, 64 characters each (extra dropped/truncated) | Free-form labels. |
| `url` | string | no | 2,048 characters | Absolute `http(s)` link to the sender's own view. Anything else is dropped with a warning. |
| `occurredAt` | string (RFC 3339) | no | — | When it happened. More than 7 days in the past or 5 minutes in the future is replaced by the received time and flagged `clock_skew`. Missing means the received time. |
| `externalId` | string | no | 255 characters | The sender's own reference. Never used for grouping. |
| `idempotencyKey` | string | no | 255 characters | This event's own retry identity — takes precedence over the `Idempotency-Key` header. |
| `metadata` | object | no | 256 keys, 32 KB total (largest values truncated beyond that) | Integration-specific data. |
| `events` | array of the above | no | 1–100 items | The batch form. Not combined with the top-level fields. |

Oversized content is truncated rather than rejected — Proxmox and similar senders deliver once and never retry — but identity fields (`title` when blank, the batch size) are rejected outright, because truncating one could merge unrelated events. A batch is all-or-nothing: if any item fails validation, none of them are stored.

InfraInbox keys are removed from an event's text before it's stored. An `iik_…` key, a `whsec_…` secret or a password written into a URL (`https://user:password@host`) in `title`, `body`, `resource`, `type`, `tags`, `links` or `metadata` becomes `iik_[REDACTED]`, `whsec_[REDACTED]` or `//[REDACTED]@`. So a tool that quotes its own command, such as a cron mail subject carrying a `curl` to your heartbeat URL, never shows the key in the inbox or on a phone. `dedupKey` and the other identity fields keep their value.

## Severities

`DEBUG`, `INFO`, `SUCCESS`, `WARNING`, `ERROR`, `CRITICAL`, ranked in that order (`INFO` and `SUCCESS` rank equally). Requests also accept the aliases `warn`, `err`, `crit` and `fatal`, case-insensitively; responses always use the canonical names. By the shipped default route:

| Severity | Default disposition |
|---|---|
| `CRITICAL`, `ERROR`, `WARNING` | Opens or updates an incident |
| `INFO`, `SUCCESS`, `DEBUG` | Logged to History › Events received only |

`SUCCESS` always acts as a recovery, whatever `action` says.

## Idempotency

Send an `Idempotency-Key` header to make a retried request safe: a replay within at least 24 hours returns the original response unchanged, and the same key reused with a different body is rejected (422 `idempotency_mismatch`). A key is scoped to the exact call it was sent with (method and path). An event's own `idempotencyKey` field takes precedence over the header for that one event. Without either, InfraInbox falls back to (source, fingerprint, `occurredAt`) when `occurredAt` was sent.

## Recovery

Resolve an incident from its source in one of two ways:

- Send `"action": "resolve"` with the matching `dedupKey`.
- Send an event with `"severity": "SUCCESS"` and the matching `dedupKey` — this always resolves, regardless of `action`.

## Errors

| Status | Code | Meaning |
|---|---|---|
| 400 | `bad_request` | The body isn't valid JSON, or not the expected shape. |
| 401 | `unauthenticated` | The credential is missing, malformed, unknown, revoked, or the wrong type for this route. |
| 413 | `payload_too_large` | The request body is over the route's cap (2 MiB for `POST /v1/events`). |
| 422 | `validation_failed` | One or more fields are invalid — the response lists a `pointer` and `detail` per field. |
| 422 | `idempotency_mismatch` | The `Idempotency-Key` was reused with a different body. |
| 429 | `rate_limited` | Too many requests; retry after the `Retry-After` header's seconds. |

Every error is an [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem, `application/problem+json`, with a stable `code`, a human `title`, and a `requestId` for support. See [REST API](https://infrainbox.app/docs/reference/rest-api.md#errors).
