Ingest API

Ingest API reference

Five endpoints against one stream namespace. Batches are acknowledged at the region that receives them and replicated asynchronously to the rest of the fleet.

Base URLhttps://ingest-eu-2.pabogate.com
01

Authentication

Every endpoint except /v1/health expects a stream key sent as a bearer token. Keys are issued per stream and revoked independently. There are no session cookies and no ambient credentials.

Request
$ curl -sS -X POST https://ingest-eu-2.pabogate.com/v1/telemetry/events \ -H "Authorization: Bearer $STREAM_KEY" \ -H "Content-Type: application/json" \ -d '{"events":[{"metric":"api.latency","value":42.7}]}'
Preflight OPTIONS is answered with permissive CORS headers and an empty 200 body before the stream key is checked. Ingest from a server, not from browser JavaScript, where the key would be readable by the page.
02

Endpoints

GET/v1/healthPublic

Readiness of the node that served the request. Reports the legend API version and the region.

Responses

CodeMeaning
200Node is healthy and accepting writes

Example

GET /v1/health
$ curl -sS https://ingest-eu-2.pabogate.com/v1/health {"status":"healthy","version":"2.4.1","region":"eu-2","timestamp":"2026-08-30T08:00:19+00:00"}
POST/v1/telemetry/eventsBearer

Accepts a batch of events and queues it. The batch is acknowledged as soon as it is committed at this region, before replication elsewhere completes.

Headers

NameValue
AuthorizationBearer <stream key>
Content-Typeapplication/json

Responses

CodeMeaning
202Batch accepted and queued
401Missing or invalid stream key
405Method is not POST
503Rate limit exceeded

Example

POST /v1/telemetry/events
$ curl -sS -X POST https://ingest-eu-2.pabogate.com/v1/telemetry/events \ -H "Authorization: Bearer $STREAM_KEY" \ -d '{"events":[{"metric":"api.latency","value":42.7}]}' HTTP/2 202 {"accepted":1,"batch_id":"4f1a2c9e","status":"queued"}
GET/v1/streams/{streamId}/wsBearer

Upgrades the connection and holds a full-duplex channel open until either side closes it.

Path parameters

NamePattern
streamId^live-[a-f0-9]{8}$

Responses

CodeMeaning
101Switching protocols
401Missing or invalid stream key
404No stream with that id

Example

GET /v1/streams/{streamId}/ws
$ curl -sS -i -N \ -H "Connection: Upgrade" \ -H "Upgrade: websocket" \ -H "Sec-WebSocket-Version: 13" \ -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \ https://ingest-eu-2.pabogate.com/v1/streams/live-a1b2c3d4/ws HTTP/2 101
POST/v1/ingest/push/{streamKey}Bearer

Long-lived upload channel for high-throughput batches. The connection stays open across successive batches instead of being re-established per request.

Path parameters

NamePattern
streamKey^live-[a-f0-9]{8}$

Responses

CodeMeaning
200Batch acknowledged
401Missing or invalid stream key
404No stream with that key

Example

POST /v1/ingest/push/{streamKey}
$ curl -sS -X POST https://ingest-eu-2.pabogate.com/v1/ingest/push/live-a1b2c3d4 \ -H "Authorization: Bearer $STREAM_KEY" \ -H "Content-Type: application/octet-stream" \ --data-binary @batch.bin HTTP/2 200
GRPC/ingest.v1.IngestService/StreamMetadata

Bidirectional gRPC channel with flow control. Requires HTTP/2 and the gRPC content type; the stream key travels in request metadata rather than an Authorization header.

Headers

NameValue
content-typeapplication/grpc
tetrailers

Responses

StatusMeaning
OKStream closed cleanly
UNAUTHENTICATEDStream key missing or invalid
UNAVAILABLENode is draining

Example

ingest.v1.IngestService/Stream
$ grpcurl -v \ -H "authorization: Bearer $STREAM_KEY" \ -d '@' ingest-eu-2.pabogate.com:443 ingest.v1.IngestService/Stream < frames.bin grpc-status: 0
03

Rate limits

PathZoneRateBurstMax body
/v1/telemetry/eventsanti_ingest5 r/s1064 KiB
/v1/schemas/{hash}.binanti_subs10 r/s20
everything else1 MiB
Over the limit Excess requests are rejected immediately with 503 and are not queued. Back off and retry; the burst allowance refills at the zone rate.
04

Errors

CodeRaised whenBody
401Stream key missing or wrong{"error":"unauthorized","message":"missing or invalid stream key"}
404No route matches{"error":"Not Found","code":404}
405Wrong method for the route{"error":"method_not_allowed","message":"telemetry ingest requires POST"}
503Rate limit exceedednginx default error page
Inconsistent shape Route handlers return error and message. The catch-all 404 handler returns error and code instead. Branch on the status code, not on the field names.