Skip to main content
Your game client sends analytics events to PlaySmart in batches. On the server side, events are placed into an in-memory buffer and flushed to the database asynchronously — either on a timed interval or when the buffer reaches its configured maximum size. This design keeps the ingest endpoint fast under load: you receive an HTTP 202 Accepted immediately, before the events have been written to persistent storage.

Available event types

PlaySmart recognises the following named event types:
Event typeDescription
AppOpenThe player opened the parent app. Updates last-seen timestamps and session tracking.
LevelCompletedThe player finished a level. Triggers a coin award when coins_enabled is true for the game.
GameEndA game round ended (win or loss). Updates total_games_played and score fields.
AdImpressionAn ad was shown to the player. Contributes to ad revenue tracking used in elastic conversion mode.
IAPPurchaseThe player made an in-app purchase. Recorded for analytics purposes.
CustomA custom game-defined event. Supply a customEventName string to distinguish between custom event types.

Event object structure

Each event in a batch must conform to the following shape:
FieldRequiredDescription
typeYesOne of the event type strings listed above.
customEventNameNoA string identifier for your custom event. Only used when type is Custom.
timestampYesISO 8601 datetime string with a timezone offset (e.g. 2024-03-15T14:30:00+00:00). Represents when the event occurred on the client.
customdataNoA free-form object containing any key-value pairs you want to associate with this event. Values can be any JSON type.
{
  "type": "LevelCompleted",
  "timestamp": "2024-03-15T14:30:00+00:00",
  "customdata": {
    "level_number": 12,
    "duration_seconds": 47,
    "perfect_run": true
  }
}
For a Custom event, include customEventName:
{
  "type": "Custom",
  "customEventName": "boss_defeated",
  "timestamp": "2024-03-15T14:31:22+00:00",
  "customdata": {
    "boss_id": "fire_dragon",
    "attempts": 3
  }
}

Batch structure

You send events to POST /ingest/events as a single batch object. Every batch must include:
FieldRequiredConstraintsDescription
user_idYesNon-empty stringThe player’s ID. Must match the sub claim in the bearer token.
game_idYesNon-empty stringThe ID of the game the events came from.
eventsYes1–200 itemsArray of event objects as described above.
{
  "user_id": "device-abc-123",
  "game_id": "64f1a2b3c4d5e6f7a8b9c0d1",
  "events": [
    {
      "type": "LevelCompleted",
      "timestamp": "2024-03-15T14:30:00+00:00",
      "customdata": { "level_number": 12 }
    },
    {
      "type": "AdImpression",
      "timestamp": "2024-03-15T14:30:05+00:00",
      "customdata": { "ad_unit": "interstitial_post_level" }
    }
  ]
}
A single batch accepts a maximum of 200 events. If you have more than 200 events to send, split them into multiple requests.

Buffering and persistence

The ingest endpoint does not write directly to the database. Instead, events are pushed into an in-memory buffer. The buffer is flushed to the database in two situations:
  1. Timed flush — the buffer flushes on a regular interval (typically every few seconds).
  2. Size flush — if the buffer accumulates a large number of events, it flushes immediately regardless of the timer.
An HTTP 202 Accepted response means the batch was accepted into the buffer — not that it has been persisted to the database yet.
{
  "success": true,
  "message": "accepted:2 buffered:47"
}
The message field tells you how many events from your batch were accepted and how many events are currently waiting in the buffer across all recent requests.
If the server restarts before the buffer is flushed, buffered events that have not yet been written to the database will be lost. For critical game events, ensure your client retries on network failure but be aware that duplicate events sent within the same session may appear more than once in raw storage.

How events drive coin rewards

LevelCompleted events are the primary driver of coin awards in PlaySmart. When the event processor picks up a LevelCompleted event, it checks:
  1. Is coins_enabled set to true on the game?
  2. Is level_completion_enabled set to true in the game’s config?
If both are true, a coin transaction is written with trigger: "level_complete" and the player’s coins_balance increases. Custom events can also drive coin awards when event_trigger_enabled is true in the game’s config. The processor counts custom events and fires a coin award once the count reaches event_trigger_threshold. Each award uses trigger: "event_trigger". See the coin economy page for details on how coin amounts are calculated and how coins eventually convert to USD.

Stored event fields

Once flushed, each event is stored in the raw_events collection with additional server-set fields alongside the client-provided data:
FieldDescription
server_timeWhen the server received the event. Immutable.
ingested_atWhen the event was written to the database. Immutable.
processed_atWhen the event processor handled this event. null until processed.
attempt_countNumber of processing attempts made.
last_errorThe last processing error, if any.
Raw events are retained for 180 days before automatic expiry.