Skip to content
Maple Docs
Open app
Browse the docs
On this page

Ingest API

The OTLP ingest endpoint: paths, authentication, content types, compression, request limits, status codes, and how to retry.

Every signal reaches Maple through one OTLP/HTTP gateway. Any OpenTelemetry SDK or Collector that can export OTLP over HTTP works without a Maple-specific exporter.

Base URLhttps://ingest.maple.dev, or your region’s ingest host
ProtocolOTLP over HTTP, POST
AuthAuthorization: Bearer maple_pk_… (or maple_sk_…)
EncodingsProtobuf (recommended) or JSON, optionally gzip
Max body20 MiB per request, measured on the compressed body
Request time30 seconds per request

Endpoints

PathPayload
POST /v1/tracesOTLP ExportTraceServiceRequest
POST /v1/logsOTLP ExportLogsServiceRequest
POST /v1/metricsOTLP ExportMetricsServiceRequest
POST /v1/eventsProduct events
POST /v1/sessionReplays/*Session replay chunks, sent by the browser SDK
POST /v1/sessionEventsSession timeline events, sent by the browser SDK

Use the ingest host of your organization’s region. A key from one region is rejected by the other. A standard exporter appends the signal path itself:

export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.maple.dev"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer maple_pk_…"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"

Authentication

Send your ingest key on every request, either as a Bearer token or in the x-maple-ingest-key header. The Bearer prefix is case-insensitive.

Authorization: Bearer maple_pk_…
x-maple-ingest-key: maple_pk_…

Ingest keys can only send data, and each belongs to one organization. Use the public key (maple_pk_…) in browsers and mobile apps, where it ships to end users, and the private key (maple_sk_…) on servers. Find both under Settings → Ingestion in the dashboard. Authentication explains the difference.

The literal key MAPLE_TEST is accepted and returns 200, but the data is discarded. Use it in CI or example code where you want the exporter to run without sending anything.

Content types and compression

Content-TypeRead as
application/x-protobuf, application/protobufOTLP protobuf
application/octet-streamOTLP protobuf
anything containing json (application/json)OTLP JSON
header missingOTLP protobuf
anything else415

For compression, send Content-Encoding: gzip. Omit the header (or send identity) for an uncompressed body. gzip is the only compression supported. zstd, deflate and br are rejected with 415, so set your exporter’s compression to gzip or none.

Browsers

The gateway answers CORS preflights from any origin, so a browser can export directly. Allowed request headers are Authorization, Content-Type, Content-Encoding, x-maple-ingest-key and the x-maple-* headers the browser SDK sends. No response headers are exposed to scripts, so browser code cannot read Retry-After; back off on a fixed schedule instead.

Status codes

Errors carry a JSON body with the same envelope as the Maple API:

{
	"error": {
		"_tag": "@maple/ingest/OrgQueueThrottled",
		"type": "rate_limit_error",
		"code": "ingest_queue_throttled",
		"title": "Ingest queue full for this org",
		"message": "This org's ingest queue is at capacity. No data was written; resend this batch after the suggested delay.",
		"retryable": true,
		"recovery": "retry",
		"retry_after_seconds": 1
	}
}
FieldMeaning
_tagThe exact failure, stable across releases. Branch on this
typeThe status family: invalid_request_error, authentication_error, payment_error, rate_limit_error or api_error (5xx)
codeThe short code in the table below
title, messageHuman-readable text
retryableWhether resending the same batch can succeed
recoveryfix_request, reauthenticate, retry or contact_support
retry_after_secondsPresent when a retry makes sense. The same value is in the Retry-After header

Checks run roughly in the order below, so a request fails on the first one it trips.

Statuscode_tagCauseRetry?
200Accepted and durably queued
401ingest_unauthorized@maple/ingest/UnauthorizedMissing, malformed or unknown ingest key, or a key sent to the other region’s ingestNo. Fix the key
429ingest_rate_limited@maple/ingest/RateLimitedMore than 1,000 requests in flight for your organizationYes, after 1 s
413ingest_payload_too_large@maple/ingest/PayloadTooLargeBody over 20 MiBNo. Send smaller batches
415ingest_unsupported_media_type@maple/ingest/UnsupportedMediaTypeUnknown Content-Type or Content-EncodingNo. Fix the exporter config
400ingest_bad_request@maple/ingest/BadRequestInvalid gzip, a body that is not valid OTLP, or a malformed product event, session event or replay headerNo
400ingest_replay_body_not_gzip@maple/ingest/ReplayBodyNotGzipA session replay chunk that is not a gzip streamNo
402ingest_plan_limit_reached@maple/ingest/PlanLimitReachedNo active subscription, or the plan’s limit is reachedNo. Check Settings → Billing
429ingest_queue_throttled@maple/ingest/OrgQueueThrottledYour organization’s ingest queue is full. Nothing was writtenYes, after 1 s
429ingest_export_lane_full@maple/ingest/ExportLaneBackpressureThe write path for your organization is backed up. Nothing was writtenYes, after 2 s
503ingest_unavailable@maple/ingest/ServiceUnavailableKey lookup or another dependency is temporarily unavailableYes, after 5 s
503ingest_queue_unavailable@maple/ingest/QueueUnavailableThe batch could not be written to the durable queue. Nothing was writtenYes, after 5 s
503ingest_collector_unavailable@maple/ingest/CollectorUnavailableAn upstream collector failed or its response could not be readYes, after 5 s
503ingest_request_timeout@maple/ingest/RequestTimeoutThe request took longer than 30 secondsYes, after 5 s
503ingest_encode_failed@maple/ingest/PayloadEncodeFailedThe batch could not be encoded for storage. Resending the same batch fails the same wayNo. Contact support
500ingest_internal_error@maple/ingest/InternalErrorUnexpected gateway errorNo. Contact support

OpenTelemetry SDKs and the Collector already retry 429 and 503 with backoff, and drop on other 4xx codes. That is the right behavior for every code above except ingest_encode_failed, which an exporter retries even though it cannot succeed.

Batching

A request is limited by its compressed size (20 MiB), not its span or record count. The default batch sizes of the OpenTelemetry SDKs (512 spans or log records per export) and of the Collector’s batch processor (8,192 items) stay far below that. If you raise them and a batch reaches the limit, the gateway answers 413 and the exporter drops the whole batch.