Hosted OpenTelemetry ingestion
Send OTLP/HTTP JSON GenAI traces directly to SuperPenguin without installing an SDK.
Hosted OpenTelemetry ingestion accepts GenAI traces from a provider or exporter and turns generation spans into the same request-cost rows used by SDK attribution. It is a receiver, not the in-process TypeScript OpenTelemetry helper.
Endpoint
POST https://app.superpenguin.ai/api/otel/v1/traces
Authorization: Bearer <dedicated SuperPenguin source key>
Content-Type: application/jsonCreate a source under API Keys → Hosted OpenTelemetry. The dashboard shows the secret once. Use a different source and key for each destination so it can be disabled or revoked independently.
The receiver is fail-closed per environment. Operators enable it only after the source-control-plane and BigQuery ingest_origin schema gates have been applied and provider fixtures have passed qualification.
This release accepts OTLP/HTTP JSON traces with identity or gzip encoding. It does not accept metrics, logs, OTLP/gRPC, or protobuf. The maximum wire body and decompressed body size is 4 MiB.
Provider flavors
| Flavor | Status | Provider behavior |
|---|---|---|
| OpenRouter Broadcast | Qualified | Pins provider=openrouter and supports OpenRouter generation and cost aliases |
| Generic GenAI OTLP JSON | Qualified semantic-convention subset | Uses gen_ai.provider.name / gen_ai.system; no provider-specific fields are guessed |
| Other provider-specific exporters | Not yet qualified | Use only after their span selection and accounting semantics are documented |
The source record selects the adapter. A payload cannot change its source flavor by claiming a different service.name or gen_ai.provider.name.
Supported envelope and attributes
The receiver decodes resourceSpans[] → scopeSpans[] → spans[], including OTLP integer strings and bounded AnyValue scalar, array, and key/value forms. Unknown protocol fields are ignored. Type-confused spans are reported through OTLP partialSuccess without exposing their values.
Only generation spans become request rows. Tool, retrieval, workflow, and repeated parent spans are ignored. Duplicate gen_ai.response.id values collapse inside an envelope; otherwise identity uses trace ID plus span ID. Replaying the same payload produces the same logical request ID.
| Meaning | Preferred attribute | Accepted fallback |
|---|---|---|
| Provider | gen_ai.provider.name | gen_ai.system |
| Requested model | gen_ai.request.model | llm.request.model |
| Response model | gen_ai.response.model | requested model |
| Input tokens | gen_ai.usage.input_tokens | gen_ai.usage.prompt_tokens |
| Output tokens | gen_ai.usage.output_tokens | gen_ai.usage.completion_tokens |
| Cache read | gen_ai.usage.cache_read.input_tokens | qualified provider alias |
| Response ID | gen_ai.response.id | qualified provider generation ID |
| User/session | user.id / session.id | gen_ai.conversation.id for session |
Modern attributes win over legacy aliases; values are never summed merely because both names are present.
Attribution metadata
user.id maps to customer_id; session.id maps to session_id. These OpenRouter/custom trace fields map to first-class dimensions:
trace.metadata.featuretrace.metadata.teamtrace.metadata.environmenttrace.metadata.prompt_keytrace.metadata.prompt_version
Other bounded scalar trace.metadata.* values become custom tags after reserved-name validation. Prefer stable internal or hashed identifiers rather than names or email addresses.
Delivery and errors
SuperPenguin returns 200 only after every accepted row is acknowledged by the durable Pub/Sub pipeline. An empty envelope or a valid trace with no generation spans is a successful no-op.
| Status | Meaning |
|---|---|
200 | Accepted, no-op, or partial success with permanent span rejections |
400 | Malformed JSON or OTLP envelope |
401 | Missing, invalid, or revoked key |
403 | Key has no active source, or workspace ingestion is paused |
413 | Body or decoded structure exceeds a receiver limit |
415 | Content type/encoding is unsupported (use JSON with identity or gzip) |
429 | Source rate limit; follow Retry-After |
503 | Source lookup or durable publication is temporarily unavailable; retry |
Sampling, privacy, and billing
Any declared sampling rate from 0 to 1 is supported. Below 100%, request-level users, features, tokens, counts, and attributed cost are incomplete. SuperPenguin does not silently extrapolate sampled dollars.
The receiver never persists prompt, completion, system instruction, tool argument/result, or binary attribute content in request rows, tags, logs, Pub/Sub, or the DLQ. That does not prevent content from traversing the network before it is discarded; use the provider's privacy controls when content must not be transmitted.
Hosted OTLP is request-level attribution, not guaranteed invoice truth. Sampling, credits, settlement, and BYOK can create differences. Keep provider billing connected for complete reconciliation.