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

# OpenTelemetry Ingestion

> Send traces and metrics from any OTLP-compatible agent to MeshAI

MeshAI accepts standard [OTLP/HTTP JSON](https://opentelemetry.io/docs/specs/otlp/#otlphttp) exports. Point any OpenTelemetry-instrumented agent at MeshAI and it will auto-discover agents, extract token usage, and populate the registry automatically.

## Endpoints

| Endpoint                    | Method | Description                                     |
| --------------------------- | ------ | ----------------------------------------------- |
| `/api/v1/ingest/v1/traces`  | POST   | OTLP trace export (JSON)                        |
| `/api/v1/ingest/v1/metrics` | POST   | OTLP metrics export (JSON, processing deferred) |

Both require an API key with the `telemetry:write` scope.

## Quick Setup

Set the standard OpenTelemetry environment variable to point at MeshAI:

```bash theme={null} theme={null} theme={null} theme={null}
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.meshai.dev/api/v1/ingest
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer msh_YOUR_API_KEY"
export OTEL_SERVICE_NAME=my-agent
```

That's it. Any OTLP-compatible SDK or agent will now export traces to MeshAI.

<Note>
  The ingest endpoint accepts OTLP protobuf (`application/x-protobuf`, the stock
  OTLP SDK default), OTLP JSON, and gzip-compressed bodies (`Content-Encoding: gzip`).
  Set `OTEL_EXPORTER_OTLP_PROTOCOL=http/json` only if you need to force JSON.
  `OTEL_SERVICE_NAME` sets the `service.name` attribute MeshAI uses to name your
  auto-discovered agent. If you use a real OpenTelemetry SDK and leave it unset,
  the SDK itself injects a default of `unknown_service:<language>` (for example
  `unknown_service:python`). If your OTLP payload omits the `service.name`
  resource attribute entirely, such as from a hand-rolled emitter that doesn't
  use an OTel SDK, MeshAI falls back to naming the agent `unknown-agent`.
</Note>

## What Gets Extracted

When MeshAI receives trace data, it automatically:

1. **Discovers agents** from the `service.name` resource attribute (set via `OTEL_SERVICE_NAME` or your SDK's `Resource`). Each distinct `service.name` becomes its own agent in the registry. On the free tier only one agent is admitted: the first `service.name` claims the single free slot and spans from any other `service.name` are dropped until you upgrade, so emit under one `service.name` on the free tier and split into per-service agents once on a paid plan
2. **Extracts token usage** from `gen_ai.usage.input_tokens` and `gen_ai.usage.output_tokens` attributes
3. **Records model info** from `gen_ai.request.model` and `gen_ai.system` attributes
4. **Registers new agents** in your registry if they don't already exist

## Python Example

Using the OpenTelemetry Python SDK:

```python theme={null}
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

# Configure exporter to send to MeshAI
exporter = OTLPSpanExporter(
    endpoint="https://api.meshai.dev/api/v1/ingest/v1/traces",
    headers={"Authorization": "Bearer msh_YOUR_API_KEY"},
)

provider = TracerProvider(
    resource=Resource.create({"service.name": "my-agent"})
)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

tracer = trace.get_tracer("my-agent")

# Your agent code, spans are automatically exported
with tracer.start_as_current_span("agent.run") as span:
    span.set_attribute("gen_ai.request.model", "gpt-4o")
    span.set_attribute("gen_ai.usage.input_tokens", 1500)
    span.set_attribute("gen_ai.usage.output_tokens", 800)
    # ... agent logic ...
```

## Node.js Example

```javascript theme={null}
const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-http");

const exporter = new OTLPTraceExporter({
  url: "https://api.meshai.dev/api/v1/ingest/v1/traces",
  headers: { Authorization: "Bearer msh_YOUR_API_KEY" },
});
```

## Framework Integration

Most agent frameworks support OpenTelemetry natively or via plugins:

| Framework       | OTel Support                                   |
| --------------- | ---------------------------------------------- |
| LangChain       | `langchain-opentelemetry` package              |
| CrewAI          | Built-in `OTEL_EXPORTER_OTLP_ENDPOINT` support |
| AutoGen         | OpenTelemetry tracing via `autogen-ext`        |
| Semantic Kernel | Built-in `ActivitySource` (maps to OTel)       |
| Custom agents   | Use any OTLP SDK                               |

Set the environment variables above and these frameworks will export traces to MeshAI automatically.

## Response Format

```json theme={null}
{
  "success": true,
  "data": {
    "accepted_spans": 12,
    "agents_discovered": 1
  }
}
```

| Field               | Description                                                |
| ------------------- | ---------------------------------------------------------- |
| `accepted_spans`    | Number of spans that carried token usage and were recorded |
| `agents_discovered` | Number of new agents auto-registered from this batch       |

<Note>
  A `200` is returned even when `accepted_spans` is `0`. `accepted_spans` counts only spans that carry `gen_ai.usage.input_tokens`/`output_tokens`, so a span with no token usage is admitted (its agent is registered and appears in `agents_discovered`) but records nothing. If you see `accepted_spans: 0` with `agents_discovered` of `1` or more, your agent is connected but the span carried no token usage: add the `gen_ai.usage.*` attributes to record cost and usage. `accepted_spans: 0` with `agents_discovered: 0` means the batch was dropped, usually the free-tier single-agent slot being held by a different `service.name`.
</Note>

## Metrics (Preview)

The metrics endpoint (`/api/v1/ingest/v1/metrics`) accepts OTLP metric exports and acknowledges them. Metrics-based anomaly detection is coming in Phase 2.
