Skip to content

Recording runs

POST /api/v1/runs is the heart of the integration: one HTTP call per execution, from any tool that can speak HTTP.

Request

curl -X POST "$LUMATRACK_URL/api/v1/runs" \
  -H "Authorization: Bearer $LUMATRACK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "automation": "os-patching",
    "status": "success",
    "executed_at": "2026-06-11T14:30:00Z",
    "duration_seconds": 142,
    "source": "ansible",
    "external_id": "tower-job-99412",
    "metadata": {"hosts": 240}
  }'
Field Required Notes
automation yes The automation's slug. GET /api/v1/automations lists them.
status no success (default) or failure.
executed_at no ISO 8601. Defaults to now. Naive datetimes are treated as UTC. Timestamps more than a few minutes in the future are refused; frozen months are refused.
duration_seconds no Non-negative integer.
source no The reporting system, e.g. ansible, n8n, github-actions. Shows up in the run list.
external_id no, but send it Your system's run or job id. Makes ingestion idempotent.
ai no Token usage for AI runs: {"model", "input_tokens", "output_tokens", "cached_tokens", "cost"?}. LumaTrack prices it server-side; see AI workloads.
metadata no Arbitrary JSON kept with the run (token counts, hosts touched, ticket ids). Capped at 16 KB; store a reference, not a full payload or transcript.

Responses

Code Meaning
201 Recorded.
200 Replay: this external_id already exists. The body carries the original run and "deduplicated": true.
202 Recorded but held: you are over the plan's monthly event cap. The run is stored and excluded from value math until you upgrade or the month resets. The body says so in warning.
400 Something in the body is wrong, or executed_at falls in a frozen month. The error string names the exact field.
401 Missing or invalid API key.
404 No automation with that slug in your organization.
429 Two distinct cases, told apart by the Retry-After header. With Retry-After: the org's per-minute rate limit; back off for that many seconds and retry (see Rate limits). Without it: past 3x the plan's monthly cap; the event was refused (with a durable record kept on our side); held events release when you upgrade.

Held events are released automatically when capacity allows (an upgrade, or the monthly reset). A released event keeps its original executed_at and posts to that month; it counts against the event cap of the month it is released in. If its month has frozen in the meantime, the frozen figures stay as published and the event books a closed-period correction instead: held evidence is never dropped and never re-dated.

Every non-2xx body is {"error": "..."} with a message written for a human.

Practices that pay off

Always send external_id. Delivery code retries; networks flake. With an external_id, a duplicate POST is a no-op instead of double-counted savings. Use the id your platform already has: the n8n execution id, the Ansible Tower job id, the GitHub Actions run id.

Report failures. Wire your error path to send "status": "failure". Failure runs subtract real cost and earn no savings, and the reliability chart needs them to tell the truth. An integration that only reports success produces a number nobody should sign.

Let executed_at default for live events. Set it only when reporting something that genuinely happened earlier. If the timestamp falls in a frozen month you get a 400; resubmit without executed_at to land the evidence in the current period, or use backfill for real historical loads.

Put measurements in metadata. Token usage, hosts patched, tickets closed. It is stored with the run and comes back on GET /api/v1/runs.

Reading runs back

curl -s "$LUMATRACK_URL/api/v1/runs?automation=os-patching&status=failure&since=2026-06-01T00:00:00Z&limit=50" \
  -H "Authorization: Bearer $LUMATRACK_KEY"

Newest first. Filters: automation (slug), status, since (ISO 8601), limit (default 100, max 500). To page past the window, pass before=<id of the last run you received> (an opaque run_... id) and repeat while the response's has_more field is true. Held runs are included and flagged, and each run carries its metadata.