Collect analytics events

Send browser and backend events, pageviews, identity updates, and group traits.

POST https://api.embrasure.ai/collect/v1/batch

Start with the JavaScript quickstart, or submit JSON directly. The OpenAPI schema provides the native request and response models.

Authentication

Send the public project_key in the JSON body. It permits event submission only, and resolves the workspace, project, and environment on the server. Do not send workspace IDs or storage destinations.

Browser requests must match the project's exact allowed origin. Backend requests can also supply Authorization: Bearer <server-key> with an active project key to mark their source as trusted. Public keys and browser origins do not authenticate individual users or grant report access. Do not put server keys in browser code.

Request

Send Content-Type: application/json. JSON and gzip-compressed JSON are supported.

curl --request POST 'https://api.embrasure.ai/collect/v1/batch' \
  --header 'Content-Type: application/json' \
  --data '{
    "project_key": "pk_your_project_key",
    "events": [{
      "id": "signup_started:request_123",
      "type": "track",
      "timestamp": "2026-09-15T12:00:00Z",
      "anonymous_id": "visitor_123",
      "event": "signup_started",
      "properties": { "source": "pricing" }
    }]
  }'

Use the actual event time with a timezone and a new ID for every new action. Keep the ID unchanged across retries of that action.

Every message requires id, timestamp, and type:

TypeAdditional required fieldsTypical optional fields
trackevent and either user_id or anonymous_idproperties, groups, context, session_id
pageEither user_id or anonymous_idproperties, context, session_id
identifyuser_idanonymous_id, traits, set_once
groupgroup_type, group_keytraits, set_once, actor identity

Identifiers are nonblank strings up to 200 characters. Custom event names cannot start with $. Only track messages take an event name. Properties, context, and traits are JSON objects; group associations map a group type to a group key. Unknown top-level fields are rejected. See the schema for the complete model.

Limits and retries

  • 1 to 100 events per batch.
  • 1 MiB for both the incoming body and decoded JSON; 32 KiB per event.
  • At most 10 levels of property nesting and 20 group associations per event.
  • Whole-batch validation: an invalid event rejects the entire request before delivery.
  • 429 includes Retry-After. Request guards apply per project and collector process.
  • Retry network errors, 408, 429, and 5xx with backoff and unchanged event IDs. A partial delivery failure can return 503; stable IDs allow storage to deduplicate the retry.

Stored events deduplicate by workspace, project, environment, and event ID. The first stored value wins; sending a changed payload with the same ID does not correct the original event.

Response

Successful native collection returns HTTP 202:

{
  "status": "accepted",
  "received": 1,
  "received_at": "2026-09-15T12:00:01Z",
  "request_id": "example-request-id"
}

accepted means the collection sink acknowledged the batch. It does not mean warehouse processing is complete or a report can already read it. received is the batch count, not the number of new unique stored events. Responses also include X-Request-ID and X-Embrasure-Collection-Status.

Local discard mode returns HTTP 200 with status: "discarded"; it does not persist events.

Errors

Errors return detail containing message, code, request_id, and an optional hint. Invalid event contents are not echoed back.

StatusMeaning
400Malformed body or compression
401Unknown/revoked project key or invalid server credential
403Browser origin is not allowed
408Request body read timed out
413Request body exceeds limits
415Unsupported content type or encoding
422Invalid event schema or unsupported PostHog event
429Request rate guard reached; honor Retry-After
503Collection disabled or delivery temporarily unavailable

Supported PostHog transport

The collector accepts an analytics subset at /collect/e/, /collect/i/v0/e/, and /collect/batch/. Supported payloads are a single event, a browser event array, or { "api_key": "pk_...", "batch": [...] }. These routes return HTTP 200 with the same receipt fields; inspect status to distinguish acceptance from discard mode. Their flexible request bodies are documented here rather than modeled in OpenAPI.

For posthog-js version 1.427.2, use the compatibility helper:

import posthog from "posthog-js";
import { posthogConfig } from "@embrasure/analytics/posthog";

posthog.init("pk_your_project_key", {
  ...posthogConfig("https://api.embrasure.ai/collect"),
});
posthog.capture("signup_started", { source: "pricing" });
posthog.capture("$pageview");

Keep the helper settings intact: they disable unsupported remote configuration, automatic capture, and replay. Explicit custom events, $pageview, $identify, $set, $set_once, and $groupidentify are supported, subject to identity requirements. This is not full PostHog compatibility: alias/merge, anonymous profile updates, screen events, autocapture, historical import, replay, flags, surveys, query/admin APIs, and v1 capture protocol are unsupported. Unsupported reserved events return 422; unsupported endpoints return 404.

The compatibility helper does not apply the native SDK's privacy defaults to PostHog. Apply your application's consent and property-filtering policy. Use the native server SDK when you need a separate server credential.