Endpoint
Request body
- Up to 100 events per batch.
- Up to 10 KB per event.
- Batches above either limit are rejected.
The event envelope
Every event, regardless of type, has this shape:device (optional)
geo (optional)
Allowed event types
Session
Monetization
Progression
Economy
Engagement
System
Custom
Property notes
revenue_usdmust be a non-negative number.is_first_purchaseis a boolean.source(forcurrency_earned) andsink(forcurrency_spent) are free-form strings. Be consistent —quest_rewardeverywhere, not sometimesquest_complete.placementis free-form — whatever names you use internally.position(inoffer_impression) is a 0-indexed integer for where the offer appeared in a list.
Example: a single purchase event
Example: a currency flow
Response codes
Partial failure example (207)
Validation rules in one place
event_id: valid ULID (optionalevt_or similar prefix before the ULID).event_type: one of the allowed values above.schema_version: non-empty string. Use"1.0".game_id: 1–64 chars.player_id: 1–64 chars,[a-zA-Z0-9_-]only.event_time: within 7 days of server clock, past or future.device.type: one of the allowed device types, if present.geo.country: ISO 3166-1 alpha-2 uppercase, if present.revenue_usd: non-negative number, if present.customevents:properties.custom_propertiesmax 20 fields.- Per-type required properties as listed in the tables above.
Best practices
- Generate ULIDs server-side. They’re sortable and guaranteed unique across your fleet.
- Batch aggressively but not slowly. Flush every 2–5 seconds or at 50 events, whichever comes first.
- Retry on 429 and 5xx with exponential backoff starting at 1 second.
- Never send PII. No emails, no real names.
player_idshould be opaque. - Log locally on failure. If we’re down or slow, queue events on disk and retry later. Events up to 7 days old are still accepted.

