> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omnia-voice.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OTLP trace ingest

> Send standard OpenTelemetry traces to Omnia — no SDK, no packages, three environment variables.

Omnia accepts OpenTelemetry traces over OTLP/HTTP at:

```
POST https://gateway.omnia-voice.com/v1/traces
Authorization: Bearer <OMNIA_API_KEY>
```

If your application already emits OTel (Vercel AI SDK telemetry, Pydantic AI,
an existing OTel SDK), integration is configuration only:

```bash theme={null}
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://gateway.omnia-voice.com/v1/traces
OTEL_EXPORTER_OTLP_TRACES_HEADERS="Authorization=Bearer ${OMNIA_API_KEY}"
OTEL_RESOURCE_ATTRIBUTES=omnia.tag=my-agent
```

No OTel yet? Use the [tracing SDK](/reference/tracing-sdk) instead.

## Accepted formats and dialects

* **Protocols:** OTLP/HTTP in protobuf (`application/x-protobuf`) or JSON.
  Batches are capped at 4 MB; keep your exporter's default batch size.
* **Attribute dialects:** model-call spans are recognized and normalized from
  the official `gen_ai.*` semantic conventions (including the structured
  message form and the older event form), the Traceloop/OpenLLMetry indexed
  form (`gen_ai.prompt.N.*`), the Vercel AI SDK's `ai.*` attributes, and
  OpenInference (`llm.*`). Whatever arrives, one canonical shape is stored.
* Spans in a grammar Omnia doesn't recognize are kept as trace structure, and
  the response's `unrecognized_attr_namespaces` names the attribute-key
  namespaces (never values) so you can tell us what to map next.

## What lands where

* **Model-call spans** become log entries (gradeable, judgeable, comparable)
  when your workspace has [request logging](/reference/request-logging)
  enabled. Content is stored under your retention window with the same
  scrubbing and size caps as gateway traffic.
* **Everything else** (tool calls, retrieval, your application logic) is kept
  as span structure: name, kind, status, timing, including **failed model
  calls**, which are stored with their ERROR status rather than dropped.
* **Population and grouping:** the `omnia.tag` resource attribute names the
  traffic population (falls back to `service.name`); trace ids group
  multi-step agent runs.

## Delivery semantics

Exporters retry, so ingest is idempotent: each span's log id is derived
deterministically from its trace and span ids, and retried batches
deduplicate instead of double-counting. Ingest has its own rate-limit bucket;
telemetry can never consume your inference budget.

## The response tells you what happened

```json theme={null}
{
  "accepted": 3,
  "duplicate": 0,
  "spans_stored": 5,
  "skipped_not_gen_ai": 0,
  "skipped_no_content": 0,
  "content_logging": "enabled",
  "stored_as_structure_only": 1,
  "unrecognized_attr_namespaces": {}
}
```

`accepted` counts gradeable log rows; `spans_stored` counts structure rows;
`stored_as_structure_only` counts model calls kept as structure (logging off,
redacting exporter, or a failed call with nothing to store);
`content_logging` says whether your workspace stores content at all; the
difference between "your instrumentation redacts" and "logging is off" is
visible here instead of producing an identical-looking empty timeline.
