The envelope
Every event you send is wrapped in the same envelope. Required fields apply to all event types.Validation rules at a glance
event_idmust be a valid ULID (the 26-char part after any prefix).event_typemust match one of the allowed values exactly.game_idandplayer_idare required and length-bounded.event_timerejected if more than 7 days in the past or future.device.typerejected if not in the allowed set.geo.countryrejected if not 2 uppercase letters.revenue_usdrejected if negative or non-numeric.customevents:properties.custom_propertiesmap is capped at 20 keys.- Per-type required
propertieslisted below — missing any of them rejects the event.
207 response — see REST API).
Examples by event type
session_start
No required properties. Send when the player opens the game.
level_complete
No strictly-required properties, but include level identity and outcome details.
currency_earned
Required: currency_type, amount, balance_after, source. The balance_after is critical — it’s how Qyren tracks economy inflation.
source is a free-form string — but be consistent. Always dungeon_reward, never sometimes dungeon_complete.
currency_spent
Required: currency_type, amount, balance_after, sink.
purchase
Required: offer_id, transaction_id, store, revenue_usd, is_first_purchase.
store is free-form — typical values are app_store, play_store, steam, direct. revenue_usd must always be in USD regardless of the player’s local currency, non-negative.
offer_impression
Required: offer_id, placement, position. Send one of these every time an offer is rendered on screen. Skip these and conversion rate becomes uncomputable.
placement is whatever name your game uses internally — shop_main, level_complete_popup, boss_defeat. position is a 0-indexed integer for where the offer appeared in the list. Including the request_id from the recommendation response lets Qyren tie the impression back to the call that produced it.
Best practices
- Generate ULIDs server-side. Sortable, unique, no coordination needed across instances.
- Be consistent with free-form strings. Pick one spelling for each
source,sink,placement, and stick to it. Inconsistency makes dashboards messy and recommendations weaker. - Never send PII. No emails, no real names.
player_idshould be opaque. - Buffer locally. If Qyren is slow or unreachable, queue events on disk and retry. Events up to 7 days old are still accepted.
- Retry on
429and5xxwith exponential backoff starting at 1 second.

