Skip to content

Payload Schema

Canonical contract for the Ingestor. Matches ingestor/ingest-api.md and Edge ingest_queue flush.

Two credential options on the same route — X-Device-Key/mTLS for Edge appliances (all kinds), or Authorization: Bearer <host_token> for a Host Agent posting host_inventory directly when no local Edge gateway is reachable:

POST /v1/ingest
X-Device-Key: <api_key from claim-complete>
Content-Type: application/json
{
"device_id": "550e8400-e29b-41d4-a716-446655440000",
"items": [
{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"kind": "telemetry",
"payload": { "cpu_percent": 12.5, "ts": "2026-05-27T12:00:00Z" }
}
]
}
FieldNotes
device_idUUID of the Edge device (omitted/ignored on the Bearer host_token path — the token alone identifies the host)
itemsMax ~100 per flush (Edge agent drain limit)
items[].idUUID for idempotency / dedup
items[].kindWhitelist below
items[].payloadOpaque JSON per kind

Response: 200 with empty JSON object on success. Non-2xx → caller keeps the batch for retry.

kindSourceTypical cadence
telemetryedgezu-telemetry~60s
logedgezu-logbuffer flush
security_alertedgezu-securityon alert
discoveryedgezu-discoveryafter scan
backup_eventedgezu-backupafter backup run
host_inventoryedgezu-hostagent-gateway (proxied) or hostzu-agent (direct)per-site snapshot_interval_hours policy

Anything else is rejected on device enqueue and should be rejected by Ingestor. A Bearer-authenticated (host_token) request is rejected if it sends anything other than host_inventory — host tokens are inventory-only.

{
"ts": "2026-05-27T12:00:00Z",
"cpu_percent": 12.5,
"memory_total": 17179869184,
"memory_used": 4294967296,
"disk_total": 500000000000,
"disk_used": 120000000000,
"uptime_secs": 86400
}

Payload shapes evolve with Edge modules — treat payload as opaque and follow ingestor/ingest-api.md + Edge crate sources for field-level detail.

Cloud Backend has no ingest endpoint at all — every ingest kind, including host_inventory, is handled here. It doesn’t fit the generic single-table routeItem/insertSQL pipeline the other five kinds use, so it’s dispatched separately in internal/domain/ingest/service.go to a dedicated internal/domain/hostinventory package instead:

  • Raw payload JSON → Azure Blob Storage (internal/domain/hostinventory/blob.go; local-disk fallback for dev via HOST_AGENT_BLOB_LOCAL_ROOT).
  • Trimmed summary → upsert host_inventory_snapshots, append host_ingest_events, refresh host_agents.last_seen_at/agent_version/os_family/last_transport.
  • MAC addresses → internal/domain/hostinventory/asset_merge.go correlates against assets/asset_network_interfaces; single match updates the Asset’s agent fields, no match creates a new Asset (source: host_agent), ambiguous match (>1 candidate) goes to asset_merge_review_queue instead of a silent merge.

The target host_agent is resolved differently depending on which auth path produced the item:

  • Bearer host_token (Host Agent posting directly, no local Edge gateway): the token itself already identifies exactly one host_agent_id/tenant_id/site_id — resolved by internal/middleware/host_token.go.
  • X-Device-Key (Edge-proxied via edgezu-hostagent-gateway): the caller authenticates as the EdgeZu device, not the individual host, so the target is looked up via ResolveByTenantAndHostID using the host_id embedded in the item’s own payload JSON.

Full payload shape: Host Agents payload and hostzu/spec.md section 6.

Ingestor routes each kind to dedicated tables (e.g. device_telemetry, device_logs) via ingestor/internal/domain/ingest/router.go — except host_inventory, which uses the multi-table write path described above. The older edge_ingest_events / V23 path is legacy — do not document it as the current write path.