// Reference

HTTP API for ingestion and export.

Two endpoints right now: POST /v1/ingest for the Unity SDK to push events, and GET /v1/export for Pro/Studio tier customers to pull their data back out. Both authenticate via X-API-Key — no JWT.

Base URL

https://<your-supabase-project>.supabase.co/functions/v1/

The dashboard's quickstart covers SDK configuration. The URL is set in TracedConfig.IngestUrl on the Unity side.

Auth

Every request must include an X-API-Key header. Keys are scoped to a single project. Keys with the sp_test_ prefix are for development and don't count toward your monthly quota; sp_live_ keys go in shipped builds.

POST /v1/ingest

Used by the SDK. You almost never call this directly — the SDK batches, gzips, and retries automatically. Spec is documented here for SDK developers and self-host integrators.

Headers

  • X-API-Key: sp_live_… (required)
  • Content-Type: application/json
  • Content-Encoding: gzip (optional; SDK uses it by default)

Body (JSON, gzipped or plain)

{
  "project_id": "uuid",
  "session_id": "string",
  "sdk_version": "0.2.0",
  "sent_at_ms": 1700000000000,
  "session_context": { "map": "arena_01", "mode": "deathmatch" },
  "events": [
    {
      "shape": "point|oriented|pair|volume|frustum|point_with_trail",
      "event_id": "death",
      "ts": 1700000000000,
      "player_id": "p_42",
      "position": { "x": 0, "y": 0, "z": 0 },
      "rotation": { "x": 0, "y": 90, "z": 0 },
      "from": { "x": 0, "y": 0, "z": 0 },
      "to":   { "x": 0, "y": 0, "z": 0 },
      "center": { "x": 0, "y": 0, "z": 0 }, "radius": 1.5,
      "fov": 90, "range": 25,
      "metadata": { "weapon": "sniper" }
    }
  ],
  "position_samples": [
    { "ts": 1700000000000, "player_id": "p_42",
      "position": { "x": 0, "y": 0, "z": 0 },
      "rotation": { "x": 0, "y": 0, "z": 0 },
      "velocity": { "x": 0, "y": 0, "z": 0 } }
  ]
}

Responses

  • 202 Accepted — events ingested. Body: { ok, events, positions, session }.
  • 400 — invalid body / missing session_id.
  • 401 — bad / missing API key.
  • 403project_id_mismatch or position_streams_require_pro.
  • 500 — backend error. Retry; the SDK will queue on disk and retry automatically.

GET /v1/export

Read-only bulk export of events and (optionally) position samples for a single project. Pro / Studio tier only — Free returns 403. Use this for compliance audits, custom dashboards, or feeding event data into ML pipelines.

Query parameters

ParamTypeDefaultNotes
sinceISO 8601noneLower bound (inclusive) on timestamp.
untilISO 8601noneUpper bound (inclusive).
event_idstringanyFilter to a single event_id.
shapestringanyOne of point / oriented / pair / volume / frustum / point_with_trail.
session_idstringanyFilter to a single session.
limitinttier capMax rows. Capped to 50,000 (Pro) or 250,000 (Studio).
formatjson / ndjsonjsonNDJSON streams; recommended for > 10k rows.
include_positionsboolfalseAlso export position_samples (same filters).

Example

# Last week's death events as NDJSON
curl -H "X-API-Key: sp_live_..." \
  "https://<project>.supabase.co/functions/v1/export?event_id=death&since=2026-05-08T00:00:00Z&format=ndjson"

Pagination

For datasets larger than your tier cap, walk forward by passing the last response's most-recent timestamp as the next request's since. NDJSON responses include an x-spatialpulse-event-count header.

Coming soon

  • POST /v1/projects — programmatic project creation (Studio tier).
  • POST /v1/event-styles — bulk style overrides via API.
  • Webhooks — fire on aggregate events (e.g., death cluster threshold exceeded).

For self-hosted deployments, all functions live in backend/functions/ in the monorepo. Deploy via supabase functions deploy <name>.