Integrate
Risk and chat
Fraud signals over your own data, and the moderated room your players talk in.
Two things that sit between your players and your balance: signals about unusual activity, and the room they talk in.
Risk signals are rules, not a model
!This is deterministic scoring over your own data. It is not machine learning.
VELOCITYsignal | Rounds arriving faster than a person can plausibly play them. |
STAKE_ESCALATIONsignal | A stake far outside this player's own median — not a fixed amount, because 500 is unremarkable for one player and a takeover for another. |
WIN_RATE_ANOMALYsignal | Realised return well above the game's, over enough rounds to be worth a look. |
LARGE_PAYOUTsignal | One payout big enough to warrant a human glance. |
BONUS_ABUSEsignal | Free bets or rain claimed at a rate that suggests farming. |
MULTI_ACCOUNTsignal | Several accounts from one address. Shared connections are ordinary, so this is low by default. |
WALLET_FAILURESsignal | A burst of wallet failures: your integration faulting, or somebody probing it. |
What it will and will not do
- It never moves money and never blocks a player. A false positive that freezes a real balance costs more than most of the fraud it would catch. Acting is your decision.
- It never delays a bet. Scoring runs after settlement and its failures are logged and dropped — a slow risk query must not look like a declined stake.
- Events deduplicate and only escalate. A bot at ten rounds a second is one row holding the worst observation, not a firehose.
iA win-rate anomaly is not evidence of anything
Dismissals are recorded in your audit log with who and when. "Who decided this was fine" is the question an investigation opens with.
Available on Growth and above.
In-game chat
A shared room per game, rendered inside the game frame. Everything below is driven from your own servers — you do not need the console for any of it.
Turning it off
/v1/catalogue/{gameId}operator-apiSend { "chat_enabled": false }. Off is a legitimate setting: an operator who cannot supervise a room should not have one, and some markets will not permit player-to-player messaging at all. It is per game rather than account-wide, so a crash table can have a room while everything else does not.
iIt takes effect on the next connection
What the filter removes, before anyone sees it
Links, email addresses, phone numbers and messenger handles are stripped from every message as it arrives. A player being talked into moving off-platform is a player being set up to be defrauded, and that conversation is the one thing a casino chat room reliably attracts.
iOrdering matters, and it bit us
[email protected] had its domain stripped and leaked the rest. Email is matched first now. Mentioned because it is the kind of bug that looks like it works right up until it does not.Your own word list
/v1/chat/blocklistoperator-api/v1/chat/blocklistoperator-apiThe filter above stops at the mechanical on purpose. Past that point what counts as unacceptable is a decision about your market and your brand — one operator needs a competitor's name gone, another needs religious terms left alone — and it is not a rule we can make on your behalf. So the list is yours: up to 200 words, each up to 40 characters.
Whole words onlyrule | Case-insensitive and boundary-matched, so rival does not touch arrival. Phrases work. |
Masked, not withheldrule | The word becomes ··· and the sentence survives — proportionate for a list whose reasoning is yours rather than ours. |
Evasion is withheldrule | A message spelling one of your words as r1valbet does not land at all. Writing it that way proves the sender knew. |
PUT replacesrule | Send the whole list every time. One word replaces the list with that word. |
iWe audit the count, never the words
Keep the list short. A withheld message tells the sender only that it did not send — it cannot name your word without handing your list to anyone willing to probe for it. So every word you add is one an honest player can trip with nothing to learn from, and they will simply believe the room ate their message. The rules above earn that silence by being published; a private list cannot, and pays for each entry in players who do not know what they did.
Which makes the useful question not "what would we rather not read" but "what is worth a player being confused by". The mechanical abuse is already gone before you start. What is left is usually smaller than it first appears — and sometimes it is not a word problem at all: a complaint that keeps recurring in the room is a complaint about something, and filtering it is the one response guaranteed not to fix it.
How long chat is kept
/v1/chat/retentionoperator-api/v1/chat/retentionoperator-api/v1/chat/clearoperator-apiChat is what your players typed, and you decide how long it is kept: 24, 48 or 72 hours, 7, 14, 30 or 90 days. If you never choose, it is 720 hours (30 days). Messages are removed within the hour after they pass the window, and choosing a shorter window applies immediately rather than at the next pass.
hoursinteger | null | One of 24, 48, 72, 168, 336, 720, 2160, or null for the platform default. Anything else is refused. |
messages_heldinteger | How many messages you hold right now, so the setting can be read against what it is governing. |
held_for_open_reportsinteger | Messages kept past the window because a player reported them and nobody has reviewed the report yet. |
POST /v1/chat/clear removes messages now — all of them, or only those older than older_than_hours, optionally in one game_id. Players in the room see the cleared lines disappear rather than keeping them until they reload.
iA reported message outlives the timer
What the sender is told
A message the filter withholds sends a chat_rejected frame back to that player and nobody else, carrying their own text so your client can put it back in the box rather than making them retype it.
contact_detailsreason | A link, address, phone number or messenger handle was all the message contained. These rules are published, so naming them helps an honest player rephrase. |
not_deliveredreason | Everything else. A slur and a word on your list are deliberately indistinguishable — a rejection that said which would let a player recover your blocklist one message at a time. |
iA mute stays silent, and that is different
Moderation
/v1/dashboard/chat/messagesdashboard/v1/chat/messagesapi keyEverything said in your rooms, filterable to just what the filter acted on with ?flagged=true. Messages listed here have already been shown in their filtered form — removing one takes it out of the record, muting stops the next one.
/v1/chat/messages/{messageId}/removeoperator-apimessageId is the id the room delivered with the message, so a client can offer a remove button without a lookup. Removal is recorded rather than destructive: the message stays in your review history marked removed.
/v1/chat/mutesoperator-apiA mute stops somebody talking; it does not stop them playing. Empty duration mutes indefinitely, 0 unmutes. player_id takes your own id for the player. Both are audited with the actor and reason.
What your players reported
/v1/game/chat/reportgame-launcher/v1/chat/reportsoperator-api/v1/chat/reports/{reportId}operator-apiThe filter removes what is mechanical. Everything past that is a judgement call, a judgement call needs a person, and a person needs to be told — so a player reports a message from inside the game and it lands in your queue, open first and oldest complaint first.
Each report carries the message, what the filter had already done to it, message.id for removal and message.author_id for a mute, so you can act on one without another request. Marking a report reviewed records that somebody looked; it does not remove anything or mute anybody, because those stay deliberate acts with their own audit entries.
iA report is not a vote