> Section: [6. Ingest](https://jaque.sh/docs/ingest/passive-checks.md)
> Next: deployment/overview
> Index: https://jaque.sh/llms.txt


jaque has no trap listener, no MIB parser and no SNMP trap dependency in
the binary. A trap reaches jaque as an ordinary [passive check
result](passive-checks.md), produced by a translator the operator runs
alongside it. The shape is the same one jaque takes with legacy config:
translate outside the binary, never absorb the legacy tooling. The cost
is two daemons beside jaque instead of one flag; the benefit is a pipeline
that survives a trap storm, because nothing in it forks per trap, which
is the one thing Nagios's `traphandle` never managed.

## 1. The recipe

```text
snmptrapd ---(traps.log, one line per trap)---> Vector ---(batch POST)---> jaque
```

`snmptrapd` receives traps and logs each one as a single line
(`peer|trapOID|varbinds`). [Vector](https://vector.dev) tails that log,
maps each trap OID to a service, a status and an output through a CSV
lookup table, and posts the mapped results to
`CommandService/ProcessCheckResults` in a batch. A translator receiving
bursts is exactly the batch RPC's use case, so this is the API door, not
the FIFO; see [FIFO and API](https://jaque.sh/docs/ingest/fifo-and-api.md), section 2.1. A
syslog variant swaps the source and keeps the same OID mapping and
posting shape.

## 2. What `traphandle` cost

A classic `traphandle` script forks a process per trap and does not
survive a storm. Here `snmptrapd` runs once as a daemon and only appends
lines to a file; Vector runs once too, holding one persistent connection
to jaque. Nothing is spawned per trap, and a burst becomes one batch call
that either enqueues whole or fails whole.

## 3. A trap is an event; a service is a state

This is the part a naive integration gets wrong. A trap fires once and is
gone; a jaque service holds a status until something changes it. The
recipe pairs up and down traps onto the same service: a `linkDown` trap
sets CRITICAL and the matching `linkUp` clears it to OK, the same shape
as an active check flipping status between runs.

For a trap type with no recovery counterpart, jaque never self-clears.
`stale_status` on a passive check only accepts `UNKNOWN | WARNING |
CRITICAL`; it exists to alarm on staleness, not to reset a problem back
to OK, so a bare `freshness_threshold` cannot stand in for a recovery
trap. Either the translator (or a cron job beside it) posts the
`STATUS_OK` that clears the condition once it is genuinely resolved, or
that trap is not modelled as an object's state at all and flows only to
an archive or a sink for the record.

## 4. Security considerations

The trap listener in this recipe is `snmptrapd`, not jaque, and its
exposure (UDP 162, community strings, v3 users) is configured there. The
translator holds the credential for jaque's API (`-api-token`) and is the
only thing that needs it. A trap is an unauthenticated datagram in v1 and
v2c; the OID-to-service lookup table is what decides which traps may
assert state on which objects, and a trap with no row in it should map to
nothing rather than to a default service.
