Skip to content

Ludex ingestion — HTTP contract reference

This document is the canonical reference for the Ludex telemetry ingestion HTTP API: routes, headers, JSON models, status codes, and behavior.

Principle: Direct HTTP is the supported integration path. Optional SDKs are thin clients over this same API.


Base URL and versioning

All ingest routes live under the /v1 prefix.

Environment Example base
Production https://ingest.ludexstudio.com (or the URL Ludex provides)

Full URLs below are written as {base}/v1/....


Authentication

Every ingest request must include:

Authorization: Bearer <api_key>

The server validates the Bearer token and derives organization_id, project_id, and environment_id from the credential.

Required alignment: The JSON body must include:

  • project_id — must exactly match the credential's project_id.
  • environment — must exactly match the credential's environment_id.

Mismatch yields 403 with project_mismatch or environment_mismatch (see error-catalog.md).

Scopes on the credential:

Endpoint Required scope
POST /v1/ingest/event ingest:events
POST /v1/ingest/batch ingest:batch

Missing scope → 403 insufficient_scope.


Content type

Use JSON bodies:

Content-Type: application/json

Optional headers

Header Purpose
Idempotency-Key Opaque string. When present, a 202 success response for the same credential + key is cached and replayed within a server-side TTL (default 300 seconds). The server only inspects the header when sent as Idempotency-Key or idempotency-key (these spellings only). Do not assume other casings are honored.
X-Correlation-Id Correlation id attached to downstream processing and traceability.
X-Request-Id If provided, used in request-scoped logging; otherwise the server generates one.

CORS: Production ingest is expected to be server-to-server or from controlled clients. Do not rely on browser CORS in production.


Data models (JSON)

SdkInfo (optional on each event)

Field Type Required
name string yes, if sdk is present
version string yes, if sdk is present

SdkEvent (single event payload / batch item)

Field Type Required Notes
event_name string yes Logical event type name.
timestamp string yes ISO-8601 timestamp (UTC recommended). Accepts Z suffix or offset. If timezone is omitted, UTC is assumed.
player_id string or null no Optional end-user identifier.
session_id string or null no
platform string or null no
build_version string or null no
game_version string or null no
event_id string or null no Client-supplied stable id (UUID recommended). Used for deduplication when provided. If omitted, server generates a UUID.
properties object no Arbitrary JSON object; default {}. Values are JSON-serializable types.
sdk SdkInfo or null no Identifies the sending SDK.

POST /v1/ingest/event — request body

Field Type Required
project_id string yes
environment string yes — must match credential environment_id
event SdkEvent yes

POST /v1/ingest/event — success 202

Field Type Notes
status string Always "accepted"
request_id string UUID for this ingest attempt
event_id string Echoes client event_id or server-generated UUID
duplicate boolean Default false. true when the same event_id was already ingested (deduplicated; still 202)

POST /v1/ingest/batch — request body

Field Type Required
project_id string yes
environment string yes
events array of SdkEvent yes — max 5000 events per request

POST /v1/ingest/batch — success 202 (full accept)

Field Type Notes
status string "accepted"
request_id string UUID
accepted_count integer Number of events accepted into the pipeline
rejected_count integer 0

POST /v1/ingest/batch — success 202 (partial)

Field Type Notes
status string "partial"
request_id string UUID
accepted_count integer
rejected_count integer Matches errors.length
errors array See BatchErrorDetail

BatchErrorDetail

Field Type Notes
index integer Zero-based index into request events
code string Machine-readable error code
message string Human-readable message

Batch deduplication: If an event is a duplicate (same event_id already ingested), it counts toward accepted_count and does not add to errors.


Endpoints

POST {base}/v1/ingest/event

  • Auth: Bearer required.
  • Scope: ingest:events
  • Rate limit (default): 1000 requests per minute per client IP.
  • Success: 202 — body as above.
  • Failure: 400 / 401 / 403 / 413 / 422 / 429 / 500 — see error-catalog.md.

POST {base}/v1/ingest/batch

  • Auth: Bearer required.
  • Scope: ingest:batch
  • Rate limit (default): 100 requests per minute per client IP.
  • Success: 202 — either full accepted or partial as above.
  • Failure: 400 / 401 / 403 / 413 / 422 / 429; per-item failures generally appear as 202 partial with errors.

GET {base}/v1/health

  • Auth: none
  • Success: 200{"status":"ok","message":"Healthy"} (use for liveness checks).

Idempotency semantics

When Idempotency-Key is sent:

  • The cache key is scoped to your credential and the header value (trimmed; empty after trim disables caching).
  • If a cached 202 body exists for that key, it is returned without re-processing the request.
  • Provides best-effort duplicate suppression for retries.

Client guidance

  1. Always send project_id and environment matching the API key.
  2. Generate a stable UUID per logical event for event_id when you need deduplication across retries.
  3. Use Idempotency-Key on retries after timeouts for stable 202 replay.
  4. Prefer batch for volume; respect max events and rate limits.
  5. Parse 202 partial batch responses and log or fix rows by errors[].index.

  • quickstart.md — first event in minutes
  • error-catalog.md — status codes, codes, retry policy
  • OpenAPI: {base}/docs, {base}/redoc when the service is running