Ingest
POST /v1/sdk/ingest is the durable mobile-event endpoint. The React Native,
iOS, Android, and Flutter SDKs handle sessions, subject credentials, stable
event IDs, batching, and retries for you. Do not treat the public write key as
proof of user identity.
Endpoint
POST /v1/sdk/ingest HTTP/1.1
Host: api.usergist.com
Authorization: Bearer rk_live_abcdef
X-UserGist-Subject-Token: st_anonymous_or_identified_subject
Content-Type: application/jsonBody
{
"context": {
"anonymousId": "anon_1a2b3c",
"externalId": "user_42",
"sdkVersion": "0.1.4",
"platform": "ios",
"appVersion": "1.4.0",
"locale": "en-DE"
},
"events": [
{
"eventId": "00000000-0000-4000-8000-000000000001",
"name": "checkout_completed",
"timestamp": "2026-05-12T10:30:00Z",
"anonymousId": "anon_1a2b3c",
"externalId": "user_42",
"properties": {
"orderId": "ord_991",
"amountUsd": 49
}
}
]
}Top-level fields
| Field | Type | Required | Notes |
|---|---|---|---|
context | object | ✓ | Subject identity plus SDK/platform metadata. |
events | array | ✓ | 1–500 events, all owned by the context subject. |
delivery | object | — | Request immediate engagement evaluation for event IDs in this batch; see below. |
Event shape
| Field | Type | Required | Notes |
|---|---|---|---|
eventId | UUID | Recommended | Stable across retries; every production SDK supplies it. |
name | string | ✓ | Snake-cased, past tense recommended. |
timestamp | ISO 8601 | ✓ | Must fall within the configured past/future ingestion windows. |
anonymousId | string | ✓ | Must match the authenticated subject and batch context. |
externalId | string | — | Must match the identified subject token when supplied. |
properties | object | — | JSON-compatible values. |
Response
{
"data": {
"accepted": 1,
"rejected": 0,
"errors": []
}
}Events are committed to a durable Postgres outbox before acknowledgment. Analytics
and trigger projection retry asynchronously. A request with delivery can also
evaluate engagement after the commit and return an optional instructions array
inside data. Event-level preprocessing failures appear in errors; a
contract-invalid request is rejected as a whole.
Immediate engagement
The React Native and web SDKs in the immediate-delivery release manage this optional protocol extension:
{
"delivery": {
"eventIds": ["00000000-0000-4000-8000-000000000001"],
"screenName": "movies"
}
}Include this object alongside context and events. eventIds accepts 1–20 UUIDs
that belong to this batch. screenName is optional and at most 120 characters.
Web additionally supplies clientId, the UUID of its active browser session,
bound to the current subject token; a different user's or ended session is rejected.
The server evaluates canonical committed events through the existing trigger engine and may return authorized feedback, in-app or survey instructions. Coordinated surveys can include an authorized attempt to avoid an additional start request. Consent, audience, platforms, configured delays and frequency limits still apply. This does not make push provider delivery synchronous.
An empty or absent instructions array is not a promise that a campaign will
never appear: worker processing and normal polling remain recovery paths.
Immediate responses do not advance the polling cursor past older instructions.
Clients must deduplicate presentations and acknowledge through their existing
instruction protocol. Preserve stable event IDs and event order across retries;
resending an ID with different properties does not replace its committed data.
Anonymous-only
Before identify, the SDK uses a server-bound anonymous subject token. After
your backend supplies an identified subject token, aliases are linked to one
canonical dashboard user without rewriting historical events.
Batching
React Native ordinarily flushes every 15 seconds or 100 events, subject to host configuration, and flushes known server-dependent engagement triggers immediately. Earlier queued activity keeps its order, so a watch event can precede its reminder. Web queues tracked events for prompt transmission and consumes immediate instructions from the response. Other SDK versions can retain their previous batching and polling behavior. Use normal batching for bulk analytics.
Protocol example
Normally you should use the SDK for your app's platform. A custom low-level
client must first call
POST /v1/sdk/session with its write key and anonymous ID, retain the returned
subject token, and send that token with every later request:
curl https://api.usergist.com/v1/sdk/ingest \
-H "Authorization: Bearer $USERGIST_WRITE_KEY" \
-H "X-UserGist-Subject-Token: $USERGIST_SUBJECT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"context": {
"anonymousId": "anon_1a2b3c",
"sdkVersion": "0.1.4",
"platform": "react-native"
},
"events": [
{ "eventId": "00000000-0000-4000-8000-000000000001",
"anonymousId": "anon_1a2b3c",
"name": "subscription_renewed", "timestamp": "2026-08-17T10:00:00Z",
"properties": { "plan": "pro", "monthlyUsd": 19 } }
]
}'