How the agent communicates
The direct HTTP/JSON protocol under /api/machine/agents/*, why it is not OpenTelemetry, the heartbeat as a control channel, the two authentication models, the separate inventory channel, and the X-Agent-Kind header that tells Scout and the Machine Agent apart.
Direct protocol, not OpenTelemetry
A question worth answering plainly: does the Machine Agent use OpenTelemetry? No. The agent talks to the VerOps backend over a direct, purpose-built HTTP/JSON protocol rooted at /api/machine/agents/*. There is no OTLP exporter, no gRPC, and no OpenTelemetry SDK in the agent. Telemetry is modelled by VerOps's own endpoints, and control flows back to the agent through the heartbeat response — a design OTLP does not offer.
Why not OTLP: OTLP is a one-way push of spans, metrics, and logs. The Machine Agent needs a two-way relationship: the platform hands work back (log reads, process watches, config) on each check-in. That control channel is the whole point of the custom protocol, so the agent uses it instead of OTLP.
The core endpoints
Every call in this channel authenticates with the connection key in X-Machine-Key; after the agent registers, it also sends the assigned X-Agent-ID.
| Method & path | Purpose | Auth headers |
|---|---|---|
POST /api/machine/agents/authenticate |
Validate the connection key, obtain the agent identity. | X-Machine-Key |
POST /api/machine/agents/register |
Register the host (name, OS, version, capabilities) and receive an agent ID. | X-Machine-Key |
POST /api/machine/agents/{id}/heartbeat |
Check in, report host metrics, and receive pending commands + config. | X-Machine-Key + X-Agent-ID |
POST /api/machine/agents/{id}/scrape-result |
Return the result of a metric scrape. | X-Machine-Key + X-Agent-ID |
POST /api/machine/agents/{id}/process-snapshot |
Return a process-watch snapshot (top processes by CPU/memory). | X-Machine-Key + X-Agent-ID |
POST /api/machine/agents/{id}/command-result |
Return the result of an ad-hoc command (e.g. a READ_LOG). |
X-Machine-Key + X-Agent-ID |
The heartbeat is a control channel, not just a ping
The agent never listens for the platform. Instead it pulls: each heartbeat is a question — "any commands for me?" — and the backend's response is the answer. The response carries a list of pending_commands and any updated process-watch configuration. The agent dispatches each command, executes it locally, and posts the outcome back to command-result (or process-snapshot). This is why lowering heartbeat_interval_secs makes commands arrive sooner — there is no separate push path.
Agent ──POST /heartbeat──────► Backend "here are my metrics; any commands?"
Agent ◄──200 {pending_commands}─ Backend READ_LOG /var/log/app.log patterns=[ERROR]
Agent (reads file, applies filters locally)
Agent ──POST /command-result───► Backend matching_lines + match_count
Two authentication models
The agent uses different credentials for different channels — an important security boundary:
| Channel | Endpoints | Authenticates with |
|---|---|---|
| Core telemetry & control | /api/machine/agents/* |
The machine connection key (X-Machine-Key) + X-Agent-ID. |
| Inventory module (optional) | /api/v1.0/inventory/* |
A per-device device key (X-Device-Key, obtained by exchanging a limited-use enrollment token at /api/v1.0/inventory/enroll), or an ingest key (X-Api-Key, ta_live_…), which the Machine Agent still supports. The machine connection key cannot authenticate inventory. |
The inventory channel (when the module is enabled)
The optional inventory module reports on its own paths, still direct HTTP/JSON — not OTLP:
| Method & path | Purpose |
|---|---|
POST /api/v1.0/inventory/enroll |
One-time exchange of an enrollment token (sce_…) for a revocable per-device key (scd_…), sent with agentKind=server. |
POST /api/v1.0/inventory/report |
The primary reporting path — the host's inventory (report schema v2) and per-app activity. |
POST /api/v1.0/inventory/agent-config |
Pull the effective tracking config and collection policy (what to collect, in which mode, how often). |
In short: One agent, two doors. Logs, host metrics, and commands go through the direct/api/machine/agents/*protocol keyed by the connection key. Inventory goes through/api/v1.0/inventory/*keyed by its own enrolled device credential, or by an ingest key. Neither door is OpenTelemetry.
Which agent is calling: X-Agent-Kind
Every inventory request carries an X-Agent-Kind header naming the product that sent it — machine-agent from this agent, scout from VerOps Scout. It is how the platform applies rules that differ between the two: inventory ingest refuses org-wide API-key authentication from a Scout (enrollment-only since Scout v0.6.0) while continuing to accept it from the Machine Agent.
Note this is not the same thing as the agentKind field inside an inventory report, which describes the device's role — server or workstation. One says which software is talking; the other says what kind of machine it is talking about.