Ingestion API
Ingestion is how metric points get into Lumetry. Both endpoints require the
CanIngestMetrics permission and are decoupled from evaluation: they durably accept
data and return immediately. Evaluation happens later, asynchronously.
Use an API token for ingestion:
Authorization: Bearer {apiToken}.
There are two endpoints for two different shapes of traffic:
| Endpoint | Use when |
|---|---|
POST /v1/metrics | Pushing a batch of points, optionally with labels — the normal high-throughput path. |
POST /api/metric-ingestion | Submitting a single point and wanting the durable evaluation job ID back. |
POST /v1/metrics — batch ingestion
The primary ingestion endpoint. Accepts many points in one call; each point may carry labels (which is what makes a metric multidimensional).
Request
{
"metrics": [
{
"metricName": "demo.api.response.duration.ms",
"namespace": "demo",
"timestamp": "2026-06-02T09:00:00Z",
"value": 214,
"source": "otel-collector",
"labels": { "instance": "mbl-web-07", "region": "eu" }
},
{
"metricName": "demo.api.response.duration.ms",
"timestamp": "2026-06-02T09:00:00Z",
"value": 198,
"labels": { "instance": "mbl-web-08" }
}
]
}
| Field | Type | Required | Meaning |
|---|---|---|---|
metrics | array | yes | At least one point. An empty array returns 400. |
metrics[].metricName | string | yes | The metric key — must match the catalog/the metric store name. |
metrics[].timestamp | ISO-8601 datetime | yes | Observation time. Stored in UTC. |
metrics[].value | number | yes | The observed value. |
metrics[].namespace | string | no | Logical grouping. Defaults to "default". |
metrics[].source | string | no | Origin label. Defaults to "custom". |
metrics[].labels | object | no | String→string labels. Dimensions for multidimensional metrics live here. |
Lumetry reserves a small dot-namespaced label vocabulary for host telemetry: host.id,
host.name, host.group, agent.id, collector.id, site.id, environment,
os.type, and arch. Lumetry agents and collectors emit these automatically, and the
platform may enrich incoming points with grouping labels (such as host.group) it
manages centrally — existing labels on a point are never overwritten. Custom labels
remain free-form alongside the reserved keys.
Response 202
{ "accepted": 2 }
accepted is the number of points accepted for processing. After processing, points are
available through metric activity, series reads, and any eligible evaluation flows.
curl -X POST http://localhost:8080/v1/metrics \
-H "Authorization: Bearer ${LUMETRY_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"metrics":[{"metricName":"demo.api.response.duration.ms","timestamp":"2026-06-02T09:00:00Z","value":214}]}'
Request limits
Batch ingestion enforces per-request guardrails (defaults shown; operators can tune them):
- at most 5,000 points per batch — larger batches return
413with a message asking to split the upload; - at most 8 MiB request body — larger payloads are rejected with
413before being read; - a per-credential rate limit (default 240 requests per minute) — exceeding it
returns
429with aRetry-Afterheader.
Rejected requests are safe to retry after splitting or backing off; nothing from a rejected request is partially ingested.
Delivery guarantees
- Ingestion is at-least-once. Points are buffered and flushed in batches; the buffer only advances after a batch is durably persisted.
- Malformed points and batches that repeatedly fail to persist are routed to a quarantine with the original payload and error, so bad data is preserved for inspection rather than silently dropped — and one poison message does not stall the pipeline.
POST /api/metric-ingestion — single point
Submits one point and returns the durable evaluation job created for it. Use this when you want a handle on the queued work (for example to confirm the job was created).
Request
{
"metricId": "demo.api.response.duration.ms",
"timestamp": "2026-06-02T09:00:30Z",
"value": 214
}
| Field | Type | Required | Meaning |
|---|---|---|---|
metricId | string or number | yes | The metric key. Accepts a JSON string or number; sent to the queue as its string form. |
timestamp | ISO-8601 datetime | yes | Observation time. Truncated to the minute (UTC) — the durable queue is keyed per metric-minute. |
value | number | yes | The observed value. |
Response 202 (with Location: /api/evaluation-jobs/{jobId})
{
"jobId": 84213,
"metricId": "demo.api.response.duration.ms",
"metricTimestamp": "2026-06-02T09:00:00Z",
"status": "Pending"
}
| Field | Meaning |
|---|---|
jobId | Integer ID of the durable evaluation job. |
metricId | The metric key the job is for. |
metricTimestamp | The minute-truncated timestamp the job represents. |
status | Initial queue status — Pending. |
Because the timestamp is truncated to the minute and the queue is unique per
(metric, minute), submitting two points for the same metric in the same minute updates the same job rather than creating two.
After ingestion
A 202 means durably accepted, not evaluated. The point becomes visible through the
series endpoint after processing. If the metric is active and
eligible for detection, resulting violations, alerts, and incidents appear through the
Alerts, Violations & Incidents API.