Rounds of games that run through GA’s aggregation come from GA: never send them (see the note before §1). This chapter and §6–§7 cover account events and the rounds of games not on GA.
5.1 Identifiers
| Field | What it is | Rule |
|---|---|---|
brand | your brand | the code of the brand as registered for you in GA; we confirm the list at onboarding. Required when one connection carries events of several brands; omitted when it carries one brand |
player_ref | your player | the player’s id on your side — the same value as external_player_id in your player tokens (§3.2). Up to 255 bytes of UTF-8. Another id splits one person into two players |
event_id | the event | yours; unique forever within your feed; a resend of the same event carries the same event_id |
round_id | the round | the same for every event of one round |
game.id | the game | the id of the game in the catalogue you send us (§8.1) |
All your transports share one space of event_ids and round_ids unless you tell us otherwise in the form: an event sent through two of them is one event, and a refund sent by webhook reverses the bet of the same round sent over Kafka.
Bonus-money sessions: promo_player_ref
Some operators run bonus money under a separate session, for example b7~1001~55, while the player’s promotions should count for b7~1001. Pass the attribute promo_player_ref in
LaunchGame.attributes, set to the player’s normal player_ref (1 to 255 characters, no whitespace). GA Promo then credits the round to that player instead of the bonus session’s player.
Only promo accounting changes: wallet calls, balance and the session’s own player_ref stay as they are. The ref must belong to the same operator or brand as the session; an invalid value makes the launch fail with InvalidArgument.
5.2 The event: promo.event.v1
JSON Schema: schema/promo-event-v1.schema.json. One event is one JSON object; the webhook also takes a batch {"events": [ … ]} (§6.1).
{
"spec": "promo.event.v1",
"event_id": "01J8Z3K9T6-bet-778812",
"brand": "partner-sandbox-eu",
"player_ref": "u-123",
"kind": "bet",
"round_id": "r-99812",
"game": {
"id": "book-of-x"
},
"amount": "1.50",
"currency": "EUR",
"occurred_at": "2026-09-24T12:00:00Z"
}
| Field | Required | Rule |
|---|---|---|
spec | yes | exactly promo.event.v1 |
event_id | yes | non-empty string (§5.1) |
brand | see §5.1 | string, up to 255 bytes of UTF-8 |
player_ref | yes | non-empty string, up to 255 bytes of UTF-8 |
kind | yes | a round kind — bet, win, settled, refund — or an account kind — deposit, withdrawal, login (§5.4) |
round_id | round kinds | non-empty string; not read for account kinds |
game.id | no | string; not read for account kinds; a round event without a game counts only in promotions that list no games |
amount | all but login | a string with a decimal number in the major units of currency (§5.3); not read for login |
currency | all but login | a code from Appendix C, any letter case; not read for login |
occurred_at | yes | RFC 3339 with a zone (Z or ±hh:mm); fractions of a second allowed |
Fields you add beyond these are ignored, at the top level and inside game: the format grows by adding fields. The byte limits count UTF-8 bytes, not characters.
5.3 Amount
A JSON string: digits, optionally a dot and more digits. It is converted to minor units of the currency exactly; more decimals than the currency has is refused, never rounded.
amount | currency | Result |
|---|---|---|
"1.50", "1.5" | EUR | 1.50 EUR |
"100" | JPY | 100 JPY |
"0.00012345" | BTC | 0.00012345 BTC |
"0.00" | EUR | a bet or settled of zero is set aside (skipped/zero_amount) |
"1.505" | EUR | refused — three decimals, EUR has two |
"100.0" | JPY | refused — JPY has no decimals |
1.5, 150 (JSON numbers) | any | refused |
"-1.50", "1e2", "1,50", "01.50", ".5", "1.", "" | any | refused |
5.4 Kinds
Round kinds — every money operation of a game round:
kind | Send when | amount |
|---|---|---|
bet | a stake is placed | the stake |
win | a payout is made | the payout |
refund | money of a round is returned | the returned amount |
settled | the round is over — exactly one per round | the sum of the round’s bets |
Events of a round do not have to arrive in order. Promotions that collect items credit on settled
only: a feed without settled counts nothing there.
A refund takes the whole round out of promotions, whatever its amount: what was already counted for the round’s bet and settled is reversed, and a bet or settled of that round that arrives after the refund is set aside as skipped/round_refunded. Send refund only for a round whose stake is returned.
Account kinds — events of the player’s account, not of a round:
kind | Send when | amount |
|---|---|---|
deposit | the player’s deposit is credited | the deposit |
withdrawal | the player’s withdrawal is paid out | the withdrawal |
login | the player signs in | none |
They count in promotions built on them — a login streak, a deposit or withdrawal target — and never in the promotions of rounds: they need no round_id or game, take no minimum bet, and a zero
amount is decided, not set aside.
One file per kind is in examples/events/ of the pack: bet.json, win.json, refund.json and settled.json
carry brand, for a connection of several brands; deposit.json, withdrawal.json and
login.json are account events; batch.json has no brand, for a connection of one brand — its second event has an unknown kind and is refused, the other two are accepted.