divergent/docs

Endpoint

POST https://api.divergentlabs.xyz/api/otlp/v1/traces

The endpoint receives OTLP/HTTP trace exports. It does not receive gRPC, metrics or logs. Set the base URL, and your exporter adds /v1/traces:

export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.divergentlabs.xyz/api/otlp
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer%20$DIVERGENT_API_KEY"

If you also set OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, it must be the full URL, ending in /v1/traces.

Request

Header Values
Authorization Bearer <key>. The key needs the traces:write scope.
Content-Type application/x-protobuf or application/json (OTLP/JSON, with hex trace and span ids).
Content-Encoding gzip, or none.

The body is an ExportTraceServiceRequest, at most 4 MiB as sent and 16 MiB uncompressed. A request with no spans succeeds.

Responses

Every response is encoded like the request: protobuf for a protobuf request, JSON for a JSON request. Errors are a google.rpc.Status whose message is the error code, a colon and what to do.

Status Code Meaning Exporter retries
200 Every span was stored, or had been stored before. No
200 Some spans were refused. partial_success has their count and the reason. See Refused spans. No
400 invalid_otlp The body is not an ExportTraceServiceRequest in its content type and encoding. No
401 unauthorized The key is missing or invalid. No
403 tracing_not_enabled The org is not in the tracing beta. Request access on the Tracing page in the dashboard. No
403 insufficient_scope The key lacks traces:write. Run div login, or add the scope to the key under Settings. No
413 payload_too_large Over 4 MiB as sent or 16 MiB uncompressed. Set OTEL_BSP_MAX_EXPORT_BATCH_SIZE lower and OTEL_EXPORTER_OTLP_COMPRESSION=gzip. No
415 unsupported_media_type A content type other than protobuf or JSON, or an encoding other than gzip. No
503 tracing_unavailable Nothing from the request was stored. Sent with Retry-After. Yes

Sending a span again is safe. A span with a trace id and span id that tracing has already stored succeeds and is not stored or counted twice.

Refused spans

A refused span is counted in partial_success.rejected_spans, and partial_success.error_message says why, for example:

Rejected 312 spans: this org has kept 1,000,000 spans in October 2026, the most tracing keeps during the beta. Spans are accepted again on 2026-11-01.
Reason Message
Bad id <n> had a trace or span id that is missing, all zeros or the wrong length.
Bad time <n> had a start or end time past 2262.
Trace full <n> would have taken a trace past 10,000 spans.
Deleted trace <n> belong to traces deleted in the last 24 hours.
Monthly spans this org has kept 1,000,000 spans in <month>, the most tracing keeps during the beta. Spans are accepted again on <date>.
Monthly data this org has kept 5 GiB of spans in <month>, the most tracing keeps during the beta. Spans are accepted again on <date>.

Within one request, spans are accepted in the order they were sent until a limit is reached.

Limits

Limit Value
Request body 4 MiB as sent, 16 MiB uncompressed
Spans per org per UTC month 1,000,000
Stored span data per org per UTC month 5 GiB
Spans per trace 10,000
Span name 256 bytes
Input, output 128 KiB each, encoded as JSON. The longest strings are cut first, and input_truncated or output_truncated is set.
Other string values 8 KiB
Attributes per span or event 128
Events per span 128
Links per span 32
Resource attributes 4 KiB
Span, in all 384 KiB
Retention 30 days from when tracing first received a span of the trace. Spans that arrive later are deleted with the trace.

A longer string is cut at a character boundary and ends …[truncated <n> bytes].

Attributes tracing reads

Tracing reads these attributes into a span’s kind, model, tokens, input, output, session and user. The first attribute in each list that a span has is used. Attributes that become input or output are removed from the span’s attributes, so they are stored once. Other attributes are stored as they were sent.

Kind

Kind Read from
generation openinference.span.kind LLM or EMBEDDING; gen_ai.operation.name chat, text_completion, generate_content or embeddings; AI SDK ai.operationId ending .doGenerate, .doStream or .doEmbed; llm.request.type chat, completion or embedding
tool openinference.span.kind TOOL; gen_ai.operation.name execute_tool; ai.operationId ai.toolCall; traceloop.span.kind tool
agent openinference.span.kind AGENT or CHAIN; gen_ai.operation.name invoke_agent or create_agent; any other ai.operationId; traceloop.span.kind agent or workflow
retrieval openinference.span.kind RETRIEVER or RERANKER
span anything else

A trace’s tokens are the sum over its generation spans. Agent spans repeat the usage of the calls inside them and are not added again.

Model and tokens

Field Read from
Model gen_ai.response.model, gen_ai.request.model, llm.model_name, ai.response.model, ai.model.id
Input tokens gen_ai.usage.input_tokens, gen_ai.usage.prompt_tokens, llm.token_count.prompt, ai.usage.inputTokens, ai.usage.promptTokens
Output tokens gen_ai.usage.output_tokens, gen_ai.usage.completion_tokens, llm.token_count.completion, ai.usage.outputTokens, ai.usage.completionTokens

Input and output

Convention Attributes
GenAI gen_ai.input.messages, gen_ai.output.messages, gen_ai.system_instructions, or the same on a gen_ai.client.inference.operation.details event
GenAI, indexed gen_ai.prompt.<n>.role, gen_ai.prompt.<n>.content, gen_ai.completion.<n>.*, including tool_calls
GenAI tool calls gen_ai.tool.call.arguments, gen_ai.tool.call.result
AI SDK ai.prompt.messages, ai.prompt, ai.response.text, ai.response.toolCalls, ai.toolCall.args, ai.toolCall.result
OpenInference llm.input_messages.<n>.message.*, llm.output_messages.<n>.message.*, input.value, output.value
Traceloop traceloop.entity.input, traceloop.entity.output

Messages are stored as {"messages": [{"role": ..., "parts": [...]}]}, with text, tool_call and tool_call_response parts. Other input and output is stored as {"value": ...}, parsed as JSON when it is JSON.

Session, user, service and environment

Field Read from
Session session.id, gen_ai.conversation.id, langfuse.session.id, ai.telemetry.metadata.sessionId, ai.settings.context.sessionId, traceloop.association.properties.session_id
User user.id, enduser.id, langfuse.user.id, ai.telemetry.metadata.userId, ai.settings.context.userId, traceloop.association.properties.user_id
Service resource service.name
Environment resource deployment.environment.name, deployment.environment

A trace takes each of these from its root span, or from its earliest span that has one.

Removed before storing

Tracing removes credentials from every span before storing it. See What tracing stores. A span’s redacted_count is the number of values removed.

esc