How ingest works
- You send batches over HTTPS to
logs.uptimeeye.comwith an ingest key. - The key resolves to your organization; lines are stored in your organization's isolated tenant.
- Each line becomes an entry with a message, a time and any number of fields. No schema, no index configuration.
- About a second later the entry is searchable on the Logs page; Live tail shows it after ~6 s.
Ingest keys
Create keys under API Keys → New API Key with type “Log ingest”. They start with ue_ingest_, are shown once, and can only write logs — a management key (ue_live_) is refused by the ingest endpoints, and an ingest key cannot read or change anything in your account.
Send the key as a bearer token, or as HTTP basic auth for tools that only know user/password (any user name, the key as password):
Authorization: Bearer ue_ingest_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# or
Authorization: Basic base64("key:ue_ingest_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")Endpoints
Base URL https://logs.uptimeeye.com. All endpoints accept gzip-compressed bodies (Content-Encoding: gzip) up to 16 MiB uncompressed.
| Endpoint | Format | Typical senders |
|---|---|---|
| POST /v1/ingest/jsonline | One JSON object per line (NDJSON) | curl, scripts, Fluent Bit http, logging libraries |
| POST /v1/ingest/text | Plain text, one entry per line; time and level detected, stack traces folded | log files, docker logs, Spring/log4j output |
| POST /v1/ingest/elasticsearch/_bulk | Elasticsearch bulk API (GET / and /_license answer the handshake) | Vector, Filebeat, Fluent Bit es |
| POST /v1/ingest/otlp/v1/logs | OTLP/HTTP logs (protobuf) | OpenTelemetry Collector and SDKs, Serilog |
| POST /v1/ingest/loki/api/v1/push | Loki push (JSON or snappy protobuf); labels become stream fields | Promtail, Grafana Alloy, Docker Loki driver |
Message, time and fields
An entry is a flat set of string fields. Three names are special; everything else is yours:
| Field | Meaning | Default |
|---|---|---|
| _msg | The message shown in the list and searched by word queries | the key named in _msg_field, else empty |
| _time | Event time, RFC 3339 / ISO 8601 or Unix seconds/millis/nanos | the key named in _time_field, else arrival time |
| _stream | Stream labels, built from _stream_fields | service,host if present |
Nested JSON is flattened to dotted names: {"http":{"status":500}} becomes the field http.status. Arrays are stored as JSON strings. Field names are case-sensitive.
Good field hygiene
- Always send
serviceandenv— they drive the fields panel, the setup examples and most filters. - Put identifiers (
order_id,user_id,trace_id) into fields, not into the message text. - Keep one name per concept across services (
duration_ms, notlatencyhere andtookthere). - Log levels as lowercase words (
info,warn,error) solevel:errorworks everywhere.
Stream fields
A stream is the set of entries sharing the same values of the stream fields — think {service="api", env="prod"}. Streams are stored together, so a filter on them (_stream:{...}, or simply a chip on a stream field) is the fastest way to narrow a search, and the fields panel lists stream fields first.
- Choose them per request with
_stream_fields=service,env(query arg orVL-Stream-Fieldsheader). Up to 6 fields; the default isservice,host. - Pick fields with few distinct values that you filter on constantly:
service,env,namespace,region,host. - Never use high-cardinality values (
request_id,podon a busy cluster,user_id) — every distinct combination is a separate stream.
Ingest options
Options are passed as query arguments on any endpoint, or as headers for agents that cannot set the URL. Query arguments win.
| Query arg | Header | Effect |
|---|---|---|
| _stream_fields | VL-Stream-Fields | comma-separated fields that form the stream (max 6) |
| _msg_field | VL-Msg-Field | which key holds the message (e.g. message, log, msg) |
| _time_field | VL-Time-Field | which key holds the timestamp (e.g. @timestamp, time, ts) |
| _ignore_fields | VL-Ignore-Fields | keys to drop before storing |
| _extra_fields | VL-Extra-Fields | constant fields to add, k1=v1,k2=v2 |
| _default_msg_value | VL-Default-Msg-Value | message to use when the entry has none |
The plain-text endpoint adds _time_source=ingest and _multiline=off, and treats every non-underscore query argument as a constant field.
Limits, quota, retention
| Limit | Value |
|---|---|
| Request body | 16 MiB uncompressed; gzip accepted |
| Stream fields | 6 per request |
| Monthly volume | per plan, measured in uncompressed bytes as received; shown on the Logs page |
| Retention | per plan; older entries are removed automatically and the search range is capped to it |
| Over quota | 429 Too Many Requests with a Retry-After header until the month rolls over; the batch that crosses the line is still accepted |
Response codes
| Status | Meaning | What to do |
|---|---|---|
| 200 | accepted (/text answers {"entries": N}) | — |
| 400 | malformed JSON, text without lines, or broken compression | fix the payload; the body names the first bad line |
| 401 | missing, malformed or unknown ingest key | check the Authorization header and that the key is of type Log ingest |
| 403 | the plan has no Logs, or the organization has no log tenant yet | upgrade, or create an ingest key first |
| 413 | body over 16 MiB | send smaller batches |
| 415 | unsupported Content-Encoding | use gzip or none |
| 429 | monthly quota exhausted | back off until Retry-After; agents retry on their own |
| 502 / 503 | storage or key lookup temporarily unavailable | retry with backoff; nothing was accepted |
Choose an integration
Verify
Open Logs, choose the 15m range and search service:=<your service>. If nothing shows up, check the agent's log for the HTTP status of its last request (see the table above), and the time: an agent that sends timestamps from a clock that is off by minutes puts lines outside the 15m window — try 24h.
Then continue with Searching logs.
FAQ
- Can several services share one ingest key?
- Yes. A key identifies the organization, not the service — use the
servicefield to tell them apart. Separate keys per environment or team make rotation easier. - What happens if I revoke a key?
- New batches are refused with
401within about 30 seconds (the gateway caches key lookups briefly). Lines already accepted stay searchable. - Are timestamps required?
- No. Without
_time(or the key named in_time_field) the arrival time is used. Send timestamps when you replay files or when agents batch for more than a few seconds. - Do you support syslog or gRPC?
- Not directly. Point a syslog-capable agent (Vector, Fluent Bit, Alloy) at the HTTP endpoints. OTLP is accepted over HTTP/protobuf, not gRPC.
- What happens to my logs when I delete the organization?
- Deleting the organization queues the deletion of its complete log tenant. Ingest keys stop working immediately, and the stored log data is removed from our storage — normally within an hour. Independently of that, entries older than your plan's retention are removed automatically.
- Is anything parsed on the server?
- JSON keys are stored as fields as-is (nested objects flattened to dotted names). The plain-text endpoint additionally detects a leading timestamp and a level word. Everything else — regex extraction, multiline joining for JSON agents — belongs in your agent's pipeline.