Ingesting logs

Every integration guide ends up at one of five HTTP endpoints with the same key, the same fields model and the same limits. This page is that common ground — read it once, then pick your integration.

How ingest works

  • You send batches over HTTPS to logs.uptimeeye.com with 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):

headers
Authorization: Bearer ue_ingest_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# or
Authorization: Basic base64("key:ue_ingest_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
Note: Rotate by creating a second key, switching your agents, then revoking the old one. Revocation takes effect within about 30 seconds.

Endpoints

Base URL https://logs.uptimeeye.com. All endpoints accept gzip-compressed bodies (Content-Encoding: gzip) up to 16 MiB uncompressed.

EndpointFormatTypical senders
POST /v1/ingest/jsonlineOne JSON object per line (NDJSON)curl, scripts, Fluent Bit http, logging libraries
POST /v1/ingest/textPlain text, one entry per line; time and level detected, stack traces foldedlog files, docker logs, Spring/log4j output
POST /v1/ingest/elasticsearch/_bulkElasticsearch bulk API (GET / and /_license answer the handshake)Vector, Filebeat, Fluent Bit es
POST /v1/ingest/otlp/v1/logsOTLP/HTTP logs (protobuf)OpenTelemetry Collector and SDKs, Serilog
POST /v1/ingest/loki/api/v1/pushLoki push (JSON or snappy protobuf); labels become stream fieldsPromtail, 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:

FieldMeaningDefault
_msgThe message shown in the list and searched by word queriesthe key named in _msg_field, else empty
_timeEvent time, RFC 3339 / ISO 8601 or Unix seconds/millis/nanosthe key named in _time_field, else arrival time
_streamStream labels, built from _stream_fieldsservice,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 service and env — 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, not latency here and took there).
  • Log levels as lowercase words (info, warn, error) so level:error works 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 or VL-Stream-Fields header). Up to 6 fields; the default is service,host.
  • Pick fields with few distinct values that you filter on constantly: service, env, namespace, region, host.
  • Never use high-cardinality values (request_id, pod on 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 argHeaderEffect
_stream_fieldsVL-Stream-Fieldscomma-separated fields that form the stream (max 6)
_msg_fieldVL-Msg-Fieldwhich key holds the message (e.g. message, log, msg)
_time_fieldVL-Time-Fieldwhich key holds the timestamp (e.g. @timestamp, time, ts)
_ignore_fieldsVL-Ignore-Fieldskeys to drop before storing
_extra_fieldsVL-Extra-Fieldsconstant fields to add, k1=v1,k2=v2
_default_msg_valueVL-Default-Msg-Valuemessage 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

LimitValue
Request body16 MiB uncompressed; gzip accepted
Stream fields6 per request
Monthly volumeper plan, measured in uncompressed bytes as received; shown on the Logs page
Retentionper plan; older entries are removed automatically and the search range is capped to it
Over quota429 Too Many Requests with a Retry-After header until the month rolls over; the batch that crosses the line is still accepted
Note: Agents with a disk buffer (Vector, Fluent Bit, Alloy) keep lines while you are over quota or offline and deliver them later — with their original timestamps, so nothing is misplaced in time.

Response codes

StatusMeaningWhat to do
200accepted (/text answers {"entries": N})
400malformed JSON, text without lines, or broken compressionfix the payload; the body names the first bad line
401missing, malformed or unknown ingest keycheck the Authorization header and that the key is of type Log ingest
403the plan has no Logs, or the organization has no log tenant yetupgrade, or create an ingest key first
413body over 16 MiBsend smaller batches
415unsupported Content-Encodinguse gzip or none
429monthly quota exhaustedback off until Retry-After; agents retry on their own
502 / 503storage or key lookup temporarily unavailableretry 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 service field 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 401 within 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.