Sending Traces
Mibo accepts traces on a single endpoint, POST /public/traces, with two supported request shapes. Both produce the same canonical trace internally — pick whichever fits your stack.
The two paths
Section titled “The two paths”Both paths are first-class. Neither is a workaround for the other.
Which one fits your stack
Section titled “Which one fits your stack”| You’re on… | Use |
|---|---|
| A service emitting OTel via the Vercel AI SDK, OpenLLMetry, or another GenAI instrumentation | OTLP. See the Vercel AI SDK and OpenLLMetry quickstarts. |
| LangChain or LangGraph agents | OTLP through OpenLLMetry, which instruments LangChain |
| An OpenTelemetry Collector that already exports to another backend | OTLP. Add Mibo as a second exporter. See Collector fan-out. |
| n8n self-hosted ≥ 2.19 using n8n’s native OTLP export (Preview) | OTLP. Node content is not exported, so evaluation is mostly structural. See Send traces from n8n. |
| n8n that needs node input and output, including n8n Cloud | Your API through the n8n community node |
| Flowise self-hosted with native OTel enabled | OTLP |
| Flowise Cloud (no host-level OTel) | Your API via the Flowise template |
| Your own code without OpenTelemetry, scripts, or curl | Your API |
If you can choose OTLP, it usually wins — your existing exporter is already batched, retried, and instrumented. Your API exists so users on managed hosts (n8n Cloud, Flowise Cloud, anything where you can’t touch host env vars) get the same first-class trace ingestion.
What’s the same across both paths
Section titled “What’s the same across both paths”- Endpoint:
POST https://api.mibo-ai.com/public/traces - Auth:
x-api-keyheader. See API Keys & Trace Routing. - Identity: Your API uses the
x-request-idHTTP header. Present → replaces the trace with that id. Absent → server-generated UUID, so each POST creates a new trace. OTLP usestraceIdto merge batches and ignoresx-request-id. - Agent resolution: Your API uses a single-agent key automatically; otherwise it requires
platformId(top level) ormetadata.mibo.platform_id. OTLP routes single-Agent keys directly. Other keys matchservice.namewithin their allowed Agents. A key for all agents in the workspace can fall back to its only active non-demo Agent when the service name is unconfigured. - Canonical span model: spans with
span_id,parent_span_id,name,attributes, optional timing and status.span.nameis always the user-facing display label of the step. - Redaction: Mibo always redacts secrets before it stores a trace. Personal data redaction is an opt-in workspace setting. See Data handling.
What’s different
Section titled “What’s different”| OTLP | Your API | |
|---|---|---|
| Body shape | resourceSpans[].scopeSpans[].spans[] (OTel envelope) |
{ spans: [...] } (flat) |
| Attributes encoding | OTel key/value list ({ key, value: { stringValue: "..." } }) |
Plain JSON object |
| Batching | Multi-POST: server merges by traceId/span_id |
One POST per trace; create-or-replace by externalId |
| Best for | Long-lived processes, SDK-instrumented services | Synchronous flows, short scripts, managed-host integrations |
Mibo reads the same attributes on both paths — gen_ai.response.text, gen_ai.usage.input_tokens, gen_ai.tool.name, http.response.status_code, and the rest of the GenAI / HTTP semconv keys. Your assertions don’t change.
What every span should carry
Section titled “What every span should carry”Whichever path you send on, these are the attributes assertions look up. Emit what you have; missing data surfaces as missing instrumentation in the dashboard rather than silent pass/fail.
| Attribute | What it powers |
|---|---|
gen_ai.response.text |
Semantic assertions, response_regex, default text extraction |
gen_ai.output.messages |
Same as above when present (preferred over response.text) |
gen_ai.usage.input_tokens / output_tokens / reasoning.output_tokens |
token_limit |
gen_ai.tool.name + gen_ai.tool.call.arguments |
tool_call (the span becomes a child tool call of its parent) |
http.response.status_code |
http_status |
Span name |
node_call (case-insensitive substring match) |
Root span start/end_time_unix_nano |
response_time.max_ms |
See Assertion Reference for the full mapping.