OTLP ingest
axonpush accepts OpenTelemetry logs and traces in the standard OTLP/HTTP/JSON format. Point any OpenTelemetry Collector, OTel SDK, or otlphttp exporter at the endpoints below and every LogRecord / Span lands as an axonpush event — no proprietary wire format required.
Endpoints
Section titled “Endpoints”| Method | URL | Body |
|---|---|---|
POST | https://api.axonpush.xyz/v1/logs | OTLP LogsExportRequest (resourceLogs[]) |
POST | https://api.axonpush.xyz/v1/traces | OTLP TracesExportRequest (resourceSpans[]) |
Only JSON-encoded OTLP is supported today. Binary protobuf is on the roadmap.
Required headers
Section titled “Required headers”| Header | Purpose |
|---|---|
X-API-Key: ak_... | Auth — a standard axonpush API key. |
X-Axonpush-Channel: <id> | Numeric channel ID that should receive the events. |
Content-Type: application/json | Standard. |
X-Axonpush-Environment: <slug> (optional) | Override the environment bound to the API key. Only honored when the key has allowEnvironmentOverride=true. See Environments. |
OTel Collector config
Section titled “OTel Collector config”The simplest way to forward existing OTel traffic is an otlphttp exporter block:
exporters: otlphttp/axonpush: endpoint: https://api.axonpush.xyz encoding: json headers: X-API-Key: ${env:AXONPUSH_API_KEY} X-Axonpush-Channel: "1" X-Axonpush-Environment: production
service: pipelines: logs: receivers: [otlp] exporters: [otlphttp/axonpush] traces: receivers: [otlp] exporters: [otlphttp/axonpush]Point the collector’s exporter at https://api.axonpush.xyz (no /v1/... suffix — the OTel otlphttp exporter appends /v1/logs and /v1/traces itself).
Python (OTel SDK, no axonpush SDK)
Section titled “Python (OTel SDK, no axonpush SDK)”from opentelemetry.sdk.trace import TracerProviderfrom opentelemetry.sdk.trace.export import BatchSpanProcessorfrom opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
exporter = OTLPSpanExporter( endpoint="https://api.axonpush.xyz/v1/traces", headers={ "X-API-Key": "ak_prod_...", "X-Axonpush-Channel": "1", },)
provider = TracerProvider()provider.add_span_processor(BatchSpanProcessor(exporter))Response shape
Section titled “Response shape”On success the endpoint returns an empty JSON object:
{}If some records failed validation but others were accepted, you get a partial-success hint matching the OTLP spec:
{ "partialSuccess": { "rejectedLogRecords": 3, "errorMessage": "..." }}rejectedSpans is used on the /v1/traces endpoint.
axonpush also sets two response headers so you can verify routing from curl / the collector:
x-axonpush-resolved-environment: productionx-axonpush-resolved-via: api-keyErrors
Section titled “Errors”| Status | Meaning |
|---|---|
400 | Missing / invalid X-Axonpush-Channel, or body missing resourceLogs[] / resourceSpans[]. |
401 | Bad or missing X-API-Key. |
403 | Key doesn’t own the channel in the header. |
404 | Channel doesn’t exist. |
413 | Request body exceeds 6 MB. Split the export into smaller batches. |
429 | Ingest quota exceeded. |
When to use the SDK instead
Section titled “When to use the SDK instead”The OTLP endpoints are ideal for existing OTel-instrumented services — you get axonpush without touching application code. If you’re writing new code and want agent-semantic events (agent.tool_call.start, agent.handoff, …), the SDKs give you a sharper surface:
Both SDKs ultimately publish to the same ingest pipeline; they just wrap it with ergonomic instrumentation.
Related
Section titled “Related”- Environments — how the
X-Axonpush-Environmentheader is resolved - Sentry DSN ingest — same pipeline, Sentry wire format
- API Keys — minting keys with environment scoping