Introduction

Welcome to ThrillTech's technology and integration documentation!

This document is structured as a searchable online book and aims to provide you, our partner, with all the technical information you need to build successful integrations, understand our platform and most importantly, have a readily available reference in the future.

To search from anywhere within the documentation, please s and enter your search term in the search box

ThrillPots Overview

Welcome to the ThrillPots Integration Guide.

ThrillPots is an advanced standalone Jackpot Platform that allows casinos to offer their players jackpots over "everything". Be it offering a sitewide jackpot across games from various providers, to a seasonal Raffle jackpot for the 12 days of Christmas or even a Bad Beat jackpot for your poker players, ThrillPots can do it all (and more).

The goal of this guide is to make integrating with ThrillPots as painless as possible by providing you, the technical reader, with all the information you need and taking you step by step through a standard integration process.

Release Notes - October 2024

General

New Features

ThrillPots

  • Multi-strategy Community Payouts

    • Up until now, community payouts were limited to a single payout strategy (Active Players, Highest Lifetime Contributor, or the new Highest Contribution Per Win). With this release, it is now possible to define multiple community payout strategies for a single community win.

    For example, if you allocate 50% of the pot to be paid out to the community, you are now able to create sophisticated community payout strategies such as:

    • Pay 20% to X random players that were active contributors to the jackpot in the last n hours
    • Pay 20% to the top Y highest contributors to the pot
    • Pay the remaining 10% to the top Z highest contributors of the jackpots lifetime

    NOTE: Community payout strategies are defined as part of the jackpot mathematical model. If you would like to migrate your model to take advantage of multi-strategy community payouts in the future, please contact your Customer Success manager or technical point of contact to discuss further.

  • New Community Payout Strategy: Highest Contributor Per Win

    • In previous versions, the Highest Contributor strategy would track and reward the highest contributors for all time against a jackpot instance.
    • This new strategy provides the following capabilities:
      • Contributions are tracked per player, per pot (jackpot tier)
      • When this strategy is used to select community winners for a pot that has been won, the contribution values per pot are used for the selection.
      • When a specific pot is won by a player, all players have their contribution counters for that pot reset
    • This strategy provides a fair way to introduce new brands to a multi-brand community jackpot by eliminating any advantage players from longer-participating brands may have had.
  • Raffle Ticket Accumulation Mode

    • As of this release, Raffle Tickets can be awarded based on accumulated contributions or base wager costs.
    • What this means is that you can set the "price" of a raffle ticket to be X (eg €2.00), and as players contribute or wager, the system will accumulate the selected metric until the cost of the ticket has been reached, at which point a ticket will be awarded.
    • For example:
      • A ticket's cost is set to €2.00 of base wager
      • A player is playing a slot game for €0.10 spins at a time.
      • After 20 spins at €0.10 per spin, the player will be awarded a raffle ticket.
  • Winners Feeds from ThrillPots Gateway

    • Implemented functionality to retrieve latest winners per pot, as well as over all pots.

    • APIs are served from ThrillPots Gateway at the following routes:

      • GET /jackpots/instances/jackpot/:instance_id/pot_winners
      • GET /jackpots/instances/jackpot/:instance_id/latest_winners
    • Both APIs accept the following query parameters:

      • brand_id (Optional) - filters the winners by brand_id. If not provided, winners across all brands will be returned.
      • limit (Optional, default: 10) - limits the number of winners returned. In the case of pot_winners_for_instance, limit is considered per pot

Changes/Improvements

ThrillPots

  • Events sent from ThrillPots Gateway now carry a unique event_id identifier for each event.
    • This can be used to detect already-processed events in your downstream listeners (if you have more than one listener subscribed to events)

Bug Fixes

ThrillConnect

  • Service connections to ThrillConnect did not receive events that they were subscribed for. This has now been fixed and any Service based event subscribers listening to ThrillConnect events will once again start receiving events.

SaaS Integrations

Welcome to the SaaS integration guide for the ThrillPots Platform! Please read through the guide carefully as we have done our best to ensure that we explain each step of the integration as clearly as possible to ensure that you're efforts are as straighforward as possible.

How do SaaS integrations work?

When integration with the SaaS version of ThrillPots, you will be integrating your services with those of ThrillTech which are hosted in ThrillTech's hosting environment. There are 3 steps to the integration (as visualised in the diagram below):

1. Event Processor -> ThrillPots integration

This part of the integration connects enables your system to react to events occurring within your platform (such as bet events) and make jackpot contributions on behalf of players.

2. ThrillGate -> Wallet integration

This part of the integration enables the Thrillpots to communicate with your wallet system in order to be able to authenticate players and perform transactions for player jackpot bets and wins.

3. ThrillConnect -> Frontend integration

This part of the integration connects your player facing frontend(s) with the ThrillPots system and provides you with real time jackpot events and specific client-facing functionality (such as opting players in and out of jackpots)

We will discuss each of these steps in detail in the coming chapters.

ThrillPots Terminology

Before you start integrating, it would helpful to understand the terminology that is used in the context of ThrillPots.

TermDefinition
SourceA 'source' refers to any user interaction that can occur on your site. For example, a 'source' may be a game, a sports bet, a successful deposit and so forth.

It is common to think of sources as games (and more specifically, their corresponding game codes) but there is no reason that the definition needs to be limited to games.
Bearer TokenA Bearer token is a security token that is sent using the Authorization header of an HTTP request. Typically, a Bearer token looks as follows:

Authorization: Bearer token_goes_here
Jackpot TemplateA 'jackpot template' contains the ruleset that is used to create one or more Jackpot Instances
Jackpot InstanceA 'jackpot instance' refers to a live jackpot that can be in one of many Jackpot States
Jackpot StateA jackpot instance can be in one of the following Jackpot States:

Pending
A pending jackpot is a scheduled jackpot that has not started to accept contributions or opt-ins from players
Active
An active jackpot is a jackpot that is accepting contributions and opt-ins, and can be won
Paused
A paused jackpot does not accept contributions but can be "unpaused" by setting its state back to Active
Terminated
A terminated jackpot is one that has ended due to either operator decision and manual intervention, or a scheduled jackpot that has reached the end of its lifetime. Terminated jackpots do not accept contributions or opt-ins and can not be re-activated.
ContributionA jackpot bet made on behalf of a player
Owner IDAn owner_id specifies the organisation or organisational unit that created and owns the resource. The structure of an owner ID is: operator_id:brand_id, where the brand_id portion is optional. For example, it is valid to have an owner id only be the operator_id on its own, which means that the resource is owned by the organisation, and not a specific brand.
Operator IDAn operator ID defines the identifier for a specific operator within the system. An operator can be considered an 'organisation' which has one or more brands
Brand IDA brand ID defines the identifier for a specific brand that an operator owns

Event Processor Integration

In this section, we will discuss the Event Processor integration component that is required in order to enable the ability to make contributions to jackpots.

In general, this integration component needs to be able to receive the events that will drive jackpot contributions on behalf of users/players.

In a standard ThrillPots-powered system, it is usually gameplay that causes jackpot contributions to be made on behalf of players, but you are not limited to just this single use case.

From a simplistic perspective, the general logic should look something like this:

Authenticate your integration service with ThrillPots Gateway
Subscribe to gameplay/bet events from your event stream
When an event is received from your event stream:
    - Read the properties of the event for game code, player ID and bet amount
    - Make a contribution call to ThrillPots using these (and other values)

From here, it is relatively easy to see how you could expand the use case to create a Deposit jackpot. Lets imagine that the deposit flow was identified by source DEPOSIT. Lets also assume that when a successful deposit has been made by a player, that an event is published by the operator's platform. For argument's sake, lets call this event DEPOSIT_SUCCESS.

If we wanted to create a deposit jackpot, the logic could look as follows:

Subscribe to DEPOSIT_SUCCESS event
When an event is received:
    - Read the properties of the event for the player ID and deposit amount
    - Make a contribution call to ThrillPots using the DEPOSIT source_id and other properties

Sequence Diagram for the Event Processor integration

Event Processor Integration Sequence Diagram

Authenticating via ThrillPots Gateway

The ThrillPots Gateway service exposes a REST endpoint which your event stream process can authenticate itself with Thrill-ID. The endpoint is POST /authenticate/service and accepts a payload which contains the connecting service's username and password.

If authentication is successful, you will receive a response which contains token which must be used as a Bearer token in subsequent API requests to the ThrillPots Gateway service. Service tokens do not expire and therefore you do not need to be concerned with refreshing your token once it has been received.

NOTE: As part of your SaaS integration info pack, you will have received the details of the Service account that you must use for your Event Processor authentication.

Additional Information

If your event processor service is processing gameplay bet events, you should remember to filter out any and all events related to Jackpot Contributions as this could create loop of contributions on behalf of players

Contributing to Jackpots

Now that you are processing events from your platform, you want to be able to make Contributions on behalf of players to the jackpot. The process of contributing is quite straight forward and does not require your service to be aware of player opt-in status. You will however need to decide which jackpot to contribute to and this can be done in one of two ways:

  • Contribute by source
  • Contribute direct to jackpot

Sources

A Source can be thought of as an operator-defined identifier for a user journey, a group of games, or even a single game. You can read more about Sources here,

Example: Sitewide Jackpot

If you wanted to create a site-wide jackpot for your casino vertical, you could create a Source named casino-sitewide, map a jackpot to the source and then send all contributions to that specific Source.

{
    "token": "token_00001",
    "brand_id": "thrilltech:brand1",
    "player_id": "player_00001",
    "player_country": "UK",
    "source_id": "casino-sitewide",
    "gameround_id": "1",
    "currency": "EUR",
    "base_wager": 1
}

Example: Deposit Jackpot

If you wanted to create a deposit jackpot, you can create a source called deposit, map the relevant jackpot to the source and then send all deposit-based contributions ot that source

{
    "token": "token_00001",
    "brand_id": "thrilltech:brand1",
    "player_id": "player_00001",
    "player_country": "UK",
    "source_id": "deposit",
    "gameround_id": "DEPOSIT_TX_ID",
    "currency": "EUR",
    "base_wager": 1
}

Example: Game Group Jackpot

If you wanted to create a jackpot for a specific set of games, for example, a jackpot for all egyptian themed games, you can create a source called egyptian-games and use that for contributions each time a player bets into a game that is egyption themed. This would naturally require your integration service to know which games are matched to which Game Group source.

{
    "token": "token_00001",
    "brand_id": "thrilltech:brand1",
    "player_id": "player_00001",
    "player_country": "UK",
    "source_id": "egyptian-games",
    "gameround_id": "1",
    "currency": "EUR",
    "base_wager": 1
}

Example: Game Specific Jackpots

If you want to split your liquidity by game title, you can create sources that correspond to the game codes of games in your system. Each source would need a jackpot mapped to it, but once that is done, you are able to make contributions to the source based on the game code of the base game bet.

{
    "token": "token_00001",
    "brand_id": "thrilltech:brand1",
    "player_id": "player_00001",
    "player_country": "UK",
    "source_id": "provider-game-code",
    "gameround_id": "1",
    "currency": "EUR",
    "base_wager": 1
}

Direct to Jackpot Contribution

An alternative to using sources is to make contributions directly to Jackpot Instances by their ID. For example, if you have created a Jackpot instance, you will have its ID available to you. This ID will not change over the lifetime of the jackpot. Making contributions directly to a Jackpot ID incurs less processing cost, but may also reduce the flexibility you may have in changing which jackpot players contribute to based on the content or user flows.

The only difference in the contribution payload is that the source_id is replaced with an instance_id field as seen below:

{
    "instance_id": "0a1cfeea-5b07-4f2b-b2f1-2e4cd2aa991d",
    "token": "token_00001",
    "brand_id": "thrilltech:brand1",
    "player_id": "player_00001",
    "player_country": "MT",
    "gameround_id": "1000",
    "base_wager": 2,
    "currency": "EUR"
}

Synchronous vs Asynchronous contribution

The default contribution mechanism is synchronous. However, depending on your system architecture (and system load), you may prefer to make use of asynchronous contribution mechanics. In order to make asynchronous contributions, you need to provide a webhook that the ThrillPots system can call once the result of a contribution has been determined.

In order to make a contribution asynchronously, you simple need to add a callback property to either of the contribution payloads above to specify the webhook to call and which results you are interested in receiving.

The structure of the callback property is as follows:

{
    "web_hook": "https://your.host/webhook",
    "win_result_only": false
}

The web_hook field indicates the fully qualified HTTP path to your webhook and the win_result_only property indicates whether the webhook should only receive win results or all contribution results.

Therefore, an asynchronous contribution for a sitewide casino jackpot would look like this:

{
    "token": "token_00001",
    "brand_id": "thrilltech:brand1",
    "player_id": "player_00001",
    "player_country": "UK",
    "source_id": "casino-sitewide",
    "gameround_id": "1",
    "currency": "EUR",
    "base_wager": 1,
    "callback": {
        "web_hook": "https://your.host/webhook",
        "win_result_only": false
    }
}

When making an asynchronous contribution, the ThrillPots system will either return 200 OK with a JSON payload that contains a trace_id for the request when it has successfully accepted the contribution request for processing, or you will receive an error due to the request being malformed.

Any contribution request errors will be send to the webhook. The structure of the webhook payload is defined as follows:

Successful contribution result

{
    "type": "data",
    "contribution_amount": Number,
    "contribution_currency": String,
    "gameround_id": String,
    "instance_id": String,
    "metadata": null | Object,
    "tickets_awarded": null | Number,
    "timestamp": Number,
    "win_amount": Number,
    "win_pot_id": null | String,
    "win_withheld": Boolean
}

Error result

{
    "type": "error",
    "status_code": Number,
    "code": String,
    "message": String,
}

The data portion will either be a ContributionResult structure or an Error structure. You can find more information on these structures in the API documentation.

Examples of payloads sent to the web hook

Contribution Result

{
    "type": "data",
    "contribution_amount": 0.1,
    "contribution_currency": "EUR",
    "gameround_id": "cc83c1cc-6260-44fc-822b-d3c03acf2d89",
    "instance_id": "a49ff35f-6ecd-491f-b373-85e6caabacf1",
    "metadata": null,
    "tickets_awarded": null,
    "timestamp": 1715714218408,
    "win_amount": 0,
    "win_pot_id": null,
    "win_withheld": false
}

Error Result

{
    "type": "error",
    "status_code": 404,
    "code": "GAME_NOT_FOUND",
    "message": "sitewide-casino2",
}

Contribution Request Errors

A contribution request may result in a direct or a downstream error. A direct error is an error that is the result of the ThrillPots system return an error to the contribution request itself. A downstream error is an error that is propogated to the contribution request caller from a downstream system, such as ThrillGate or the operator wallet itself.

List of Direct Errors

For Direct Errors, you can expect:

Error CodeDescription
CONTRIBUTION_REJECTEDThe contribution was rejected due to a contribution rule failing, The rule in question will be contained within the CONTRIBUTION_REJECTED message
GAME_NOT_FOUNDthis occurs when making a contribution to source and the source does not exist
CURRENCY_MULTIPLIERS_NOT_FOUNDself explanatory
SYSTEM_ERRORThis is what you get with 500 http responses from ThrillPots
OPTIN_ERRORThis occurs if the player;s optin record could not be updated
SOURCE_JACKPOT_NOT_FOUNDThis occurs if the jackpot mapped to the source could not be found
SOURCE_JACKPOTS_NOT_ALLOWEDThis occurs if the jackpot mapped to the source does not allow a contribution from this player (either country or brand not allowed)
DB_ERRORAn internal DB ERROR
UNSUPPORTED_BRANDThis is returned when the brand of the player (specified in contribution) is not supported by the jackpot or system

Passing Metadata

If you need to pass contextual metadata from your event processor to your wallet, you can do so by adding a metadata field to the Contribution Request. This data will be passed through the system and attached to transaction requests to your wallet.

The metadata field can be any valid JSON value, for example:

Metadata containing an Object:

{
    "token": "token_00001",
    "brand_id": "thrilltech:brand1",
    "player_id": "player_00001",
    "player_country": "UK",
    "source_id": "casino-sitewide",
    "gameround_id": "1",
    "currency": "EUR",
    "base_wager": 1,
    "metadata": {
        "value1": "some value",
        "value2": 1234
    }
}

Metadata containing a String:

{
    "token": "token_00001",
    "brand_id": "thrilltech:brand1",
    "player_id": "player_00001",
    "player_country": "UK",
    "source_id": "casino-sitewide",
    "gameround_id": "1",
    "currency": "EUR",
    "base_wager": 1,
    "metadata": "This is an arbitrary string value"
}

Contribution Sources

Contribution Sources are a concept in ThrillPots that allow operators create well-known identifiers for one or more Jackpot Instances. A contribution source is bound to an operator and brand ID.

Contribution Sources are valid targets/identifiers for jackpot contribution bets (as described in the Contributing to Jackpots section).

Why use sources instead of Jackpot Instance IDs

Sources provide a mechanism of indirection to Jackpot Instances. Since a Source will usually have a well-known and human-defined identifier, and can represent one or more Jackpot Instances at any point in time, they provide a very convenient way for Integrating services and frontends to work with Jackpot Instances.

For example, instead of hard coding a specific Jackpot Instance ID into your frontend or backend services, you can simply configure the more human-readable source_id and use the Source to determine at runtime which Jackpot Instance ID is being used. This is especially useful when Jackpot models are changed over time since your integrated product will not need to be modified unless there is a fundamental structural change to the jackpot itself (which is rarely the case).

Example

An early, but very common use-case Contribution Source can be seen below, where a Source has been created for Operator thrilltech, Brand brand1 and is the source for the "site wide casino jackpot".

In this case, the contribution flow would look like this:

┌──────────────────────────────┐
│Contribution to Source Request│   (POST https://thrillpots_gateway_host/jackpots/contribute/source)
└──────────────┬───────────────┘
               │                
               │                
               │                
               ▼                
           ┌────────┐           
           │ Source │           
           └────────┘           
               │                
               │                
               │                
               ▼                
      ┌──────────────────┐      
      │ Jackpot Instance │      
      └──────────────────┘      

Under the covers (in the data), this Contribution Source will most probably look something like this:

{
  "owner_id": "thrilltech:brand1",
  "source_name": "Casino Sitewide Source",
  "source_id": "sitewide-casino",
  "jackpots": [
    {
      "priority": {
        "$numberLong": "0"
      },
      "owner_id": "thrilltech:brand1",
      "instance_id": "12231b6a-a774-4a93-8f16-f8af9aee2076"
    }
  ]
}

The jackpots array in this Contribution contains a single Jackpot Instance ID because in this case, there is only one Jackpot Instance required. We will discuss use cases where having multiple Jackpot Instances in this array can be useful.

Retrieving the Jackpot Instance from a source

To retrieve that relevant Jackpot Instance for a specific source, you can use the following methods:

ThrillPots Gateway

GET /jackpots/instances/source/:source_id/brand/:brand_id?player_id=:player_id

The parameters in the url above are:

ParameterDescription
source_idThe Source ID (for example, sitewide-casino from the example above)
brand_idThis is the identifier for the brand in question, which is comprised of the operator_id:brand_id pairing
player_id[OPTIONAL] If a player_id is specified, the returned Jackpot Instance will also contain the opt-in details for the specified player

ThrillConnect (used by the Frontend)

GET /v1/thrillpots/instances/source/:source_id/brand/:brand_id?player_id=:player_id

The parameters in the url above are the same as for ThrillPots Gateway:

ParameterDescription
source_idThe Source ID (for example, sitewide-casino from the example above)
brand_idThis is the identifier for the brand in question, which is comprised of the operator_id:brand_id pairing
player_id[OPTIONAL] If a player_id is specified, the returned Jackpot Instance will also contain the opt-in details for the specified player

Retrieving all sources in the System

To retrieve a list of sources for a specific operator brand, you can use one of the following methods:

ThrillPots Gateway

GET /sources?owner_id=:brand_id

The brand_id parameter in the URL is once again comprised of the operator_id:brand_id pair which identifies a specific brand. If any sources have been configured for the operator_id:brand_id specified, they will be returned in a response which contains a list of Source JSON objects and will look similar to this example:

[
    {
        "owner_id": "thrilltech:brand1",
        "source_name": "Casino Sitewide Source",
        "source_id": "sitewide-casino",
        "jackpots": [
            {
                "priority": 0,
                "owner_id": "thrilltech:brand1",
                "instance_id": "12231b6a-a774-4a93-8f16-f8af9aee2076"
            }
        ]
    }
]

ThrillConnect (used by the Frontend)

GET /v1/thrillpots/sources?owner_id=:brand_id

As in the ThrillPots Gateway example above, the brand_id parameter in the URL is once again comprised of the operator_id:brand_id pair which identifies a specific brand. The response payload will look exactly the same as the response from the ThrillPots Gateway service above.

ThrillPots Events

ThrillPots publishes a number of events which your integration service can subscribe to. There are a number of reasons you may want to consume these events, for example:

  • Synthesizing related Kafka/RabbitMQ events
  • Storing the events for BI / Analysis purposes

The following events are currently published by ThrillPots Gateway:

  • JackpotUpdateEvent - contains the latest jackpot values for the specified Jackpot Instance
  • Reference
{
    "event_type": "JackpotUpdateEvent",
    "event_id": "d6f05820-1da2-4152-bcba-6c0186f6cd77"
    "data": {
        "id": "jackpot instance ID",
        "status": String,
        "currency": String,
        "allowed_brands": [String],
        "allowed_sources": [String],
        "pots": [
            {
                "id": String,
                "is_progressive": Boolean,
                "current_value": Number
            }
        ],
        "last_updated": Number
    }
}
  • JackpotWinEvent - contains the details of a jackpot win
  • Reference
{
    "event_type": "JackpotWinEvent",
    "event_id": "3fe809f4-c94f-4950-9b86-5f2d0b8f604f"
    "data": {
        "brand_id": String,
        "player_id": String,
        "source_id": String | null,
        "instance_id": String,
        "jackpot_name": String,
        "timestamp": Number,
        "win_pot_it": String,
        "win_amount": Number,
        "currency_multipliers": {
            "brand_id": String,
            "base_currency": String,
            "multipliers": {
                "EUR": Number,
                "GBP": Number,
                "ZAR": Number,
                ...
                "NZD": Number,
                "SEK": Number
            }
        }
        "games_in_jackpot": [String],
        "seed": Number,
        "win_withheld": Boolean,
        "seed_deficit": Number,
        "community_winners": null | [{
            "player_id": String,
            "brand_id": String,
            "currency": String,
            "win_amount": Number
        }]
    }
}
  • RaffleWinEvent - contains the details of a Raffle Win
  • Reference
{
    "brand_id": String,
    "instance_id": String,
    "jackpot_name": String,
    "jackpot_currency": String,
    "currency_multipliers": {
        "brand_id": String,
        "base_currency": String,
        "multipliers": {
            "EUR": Number,
            "GBP": Number,
            "ZAR": Number,
            ...
            "NZD": Number,
            "SEK": Number
        }
    }
    "timestamp": Number,
    "winners": [
        {
            "player_id": String,
            "brand_id": String,
            "currency": String,
            "win_amount": Number
        }
    ],
    "win_withheld": bool
}
  • OptInEvent - contains the details of a player opt-in or opt-out into a Jackpot Instance Reference
{
    "event_type": "OptInEvent",
    "event_id": "27045bf8-78d2-4f99-97f1-e7d2e3aa434d"
    "data": {
        "instance_id": String,
        "player_id": String,
        "ext_player_id": String,
        "player_brand_id": String,
        "preferred_contribution_value": [Number],
        "contribution_count": Integer,
        "contribution_value": Number,
        "opted_in": Boolean,
        "last_updated": Integer
    }
}
  • CommunityPayoutErrorEvent - sent in case of an error that is encountered when processing community payouts Reference
{
    "event_type": "CommunityPayoutErrorEvent",
    "event_id": "c034a751-cf91-4722-bc89-a2f8af472805"
    "data": {
        "instance_id": String,
        "gameround_id": String,
        "tx_credit_id": String,
        "failed_payouts": [
            {
                "player_id": String,
                "brand_id": String,
                "currency": String,
                "win_amount": Number
            }
        ]
    }
}
  • RafflePayoutErrorEvent - sent in case of an error that is encountered when processing raffle payouts Reference
{
    "event_type": "RafflePayoutErrorEvent",
    "event_id": "e981296b-199f-4454-b4ec-b3f36910c2cc"
    "data": {
        "instance_id": String,
        "failed_payouts": [
            {
                "player_id": String,
                "brand_id": String,
                "currency": String,
                "win_amount": Number
            }
        ]
    }
}

The ThrillPots events are published via the WebSocket endpoint /events.

Authenticating the Websocket connection to receive events

Once you have established a WebSocket connection from your event processor service to ThrillPots Gateway, you will need to send an Authenticate message which contains your Thrill-ID JWT token to authenticate your service to receive events.

{
    "action": {
        "Authenticate": {
            "auth_token": "{{thrill-id-jwt}}"
        }
    }
}

If the authentication fails, the connection will be closed. Once you have authenticated, you should start receiving the events from the ThrillPots service.

Wallet Integration

Introduction

When integrating ThrillPots to your wallet, you will need to implement what is known as the "Standard Wallet API". This API has been defined by ThrillTech and is what our ThrillGate services uses to communicate with your backend to process:

  • Player Authentication
  • Transactions
  • Transaction cancellations
  • Batch transactions
  • Batch transaction cancellations

All communications from ThrillGate are conducted over secure SSL REST calls to your system.

As part of all calls to your system, ThrillGate sends an HMAC in the X-Server-Authorization header which is calculated from the body of the request only. You can use this HMAC value to verify that the request is coming from the expected ThrillGate server.

NOTE: During integration you will receive the secret key that you can use to verify the HMAC value with.

Sequence Diagram for Wallet integration with ThrillGate

Standard Wallet API: Player Authentication

In order for the ThrillPots system to take wagers (debit the player's wallet) and payout winnings (credit the player's wallet), it needs to be able to authenticate the player with the operator wallet.

This is done by calling the Standard Wallet's auth endpoint, passing in the provided player token and game code to the operator wallet and receiving the required player details (including the token that should be used for transaction calls)

This is done by ThrillGate calling the endpoint defined in endpoints.auth of the Standard Wallet's configuration. An example call's payload would look as follows:

{
    "operator_id": "your_operator_id",
    "brand_id": "your_brand_id",
    "player_token": "token_00001",
    "game_code": "AwesomeJackpotGameCode",
    "currency": "EUR"
}

If successful, the operator wallet must respond with a valid session token and player details that can be used for future transaction calls for this player.

Response example:

{
    "id": "player_00001",
    "token": "session_token_00001",
    "currency": "EUR",
    "balance": 100001927.79,
    "operator_id": "thrilltech",
    "brand_id": "brand1",
    "nickname": null,
    "gender": "?",
    "country": "MT",
    "jurisdiction": null,
    "segments": null
}

Standard Wallet API: Transactions

Transactions

Once the player token has been authenticated, the ThrillPots system can start making transaction calls through ThrillGate.

In standard operation, the first transaction call will be a Debit transaction request to fetch funds from a player's wallet for the Jackpot Contribution bet. This call is also intended to open the game round for the jackpot contribution.

If successful, ThrillPots will process the jackpot contribution and determine if a win occurred.

The next transaction call that will be made will be a Credit transaction request. This call is intended to pay any winnings to the player account and to close the game round that was opened with the Debit transaction.

Transaction Errors

If an error occurs while executing transactions with the operator wallet, ThrillGate and ThrillPots cooperate to ensure that the transaction error is handled correctly.

When an error occurs, ThrillGate will attempt to retry the transaction request a set number of times. If all retries fail, the error will be sent to ThrillPots for further handling.

If there are certain wallet errors that you do not wish ThrillGate to perform its retry logic, you can configure that as part of the wallet configuration in ThrillGate.

Please see the ThrillGate section on Configuring Wallet Error Behaviour for more information on how to configure ThrillGate's wallet error handling.

Once an error has been sent back to ThrillPots, ThrillPots will decide whether a transaction needs to be cancelled or not. Transaction cancellation is discussed next.

#@ Transaction Cancellation

In certain situations (as described in the errors section above), it is necessary for transactions to be cancelled. In general, ThrillPots handles transaction cancellation logic as follows:

If the Debit transaction failed

ThrillPots will send a cancellation request for the Debit transaction using the Debit transaction ID.

If the Credit transaction failed

ThrillPots will first send a cancellation request for the Credit transaction and then a separate cancellation request for the Debit transaction. Both requests will be sent with the respective transaction IDs.

Transaction Batches (Credit only)

ThrillPots uses Transaction Batch requests to communicate payouts to multiple players.

These types of payouts are only relevant to jackpots that are either:

  • Multi-player payouts (community payouts)
  • Raffle jackpot payouts

In both situations, since multiple players are considered winners from a single jackpot win, ThrillPots needs a way to credit wins to multiple players. Since these players are not guaranteed to be online at the time of the win, ThrillPots will not have access to any session token information for all the winners.

Transaction Batches are used in these special situations to communicate a set of credit operations that need to be applied to multiple players accounts.

Although unlikely, it is possible that not all the specified player accounts will be able to be credited with the winnings. Such a situation may arise if, for example, the player account has been banned/blocked or is self-excluded at the time of the jackpot win.

In these cases, the operator wallet is expected to flag the player account as an exception and continue to pay the remaining players in the transaction batch.

It is not considered an error if a player account in a transaction batch cannot be paid. The operator wallet should simply indicate this exception in the response and attempt to pay all other players.

Transaction Batch Cancellation

We have discussed what Transaction Batch exceptions are and how they are handled.

There is another limited set of errors that require Transaction Batches to be cancelled.

These errors are typically (but not limited to) errors such as network errors and timeouts. When an error occurs that leads ThrillGate to not be sure whether the operator's wallet has handled the transaction batch request, the request will first be retried, but after failing a specific number of times, the transaction batch will be cancelled.

Each transaction batch request has a unique identifier, and this identifier will be sent as part of the transaction batch cancellation request.

Frontend Integration

The final piece of the ThrillPots integration puzzle is the frontend integration. The frontend is responsible for displaying the Jackpot Ticker widget, showing players what the value of the various pots within the Jackpot are, the opt-in widget, allowing players to opt-in or opt-out of participation in the jackpot and so on.

The ThrillConnect Service has been specifically developed to provide an API and event stream over WebSockets to frontend clients to be able to interact with the ThrillPots system.

Integration Options

When integrating the frontend, there are two options that you can take:

  1. Use the existing libraries/components that ThrillTech has built to ease the effort of frontend integration:
  2. Develop your own integration with ThrillConnect and your own animation layer for the win animations

The sections below will detail the low level integration approach to help you understand how things work. You can then decide which of the options mentioned above you wish to take.

Sequence Diagram for the frontend to ThrillConnect integration

Integration Flow in detail

Fetching a Jackpot's details

One of the first things your frontend will most likely need to do is to retrieve jackpot details for your jackpot widget to display.

If you have followed the section on settings up the AIO container, you would have created a Source called sitewide-casino.

If you haven't gone through the process of setting up a source, we suggest that you review and understand sources and how they are used before continuing

To retrieve the jackpot for the sitewide-casino source, you will need to call:

GET /v1/thrillpots/instances/source/:source_id/brand/:brand_id?player_id=:player_id

replacing the :source_id and :brand_id values with the appropriate values that have been configured. If you used the default values from the Postman collection, you can use sitewide-casino for the source_id and thrilltech:brand1 for the brand_id.

If the player is already logged in, you can also pass the ID of the player via the query parameter player_id. Doing so will ensure that the player's opt-in status is returned in the jackpot instance information.

Establishing a WebSocket connection

In order to receive ThrillPots events and be able to opt players in or out of the jackpot, you will need to establish a websocket connection.

Once a player is logged into an operator's site, you can establish a WebSocket connection with ThrillConnect, passing in the player's session token.

NOTE

WebSocket connections are protected and can only be established by logged in players to prevent unauthorized and potentially dangerous abuse by attackers. Requiring a player a valid player session token in order to establish a WebSocket connection is a security-driven decision

To establish a WebSocket connection with ThrillConnect, open a WebSocket to:

/v1/events/{operator_id}/{brand_id}?token=PLAYER_TOKEN&currency=PLAYER_CURRENCY

ThrillConnect will authenticate the token (the Player session token) from the query parameters with the operator's platform via ThrillGate. If the token is valid, the websocket connection will be established. If the token is invalid, the connection will receive a 403 FORBIDDEN error.

Subscribing to ThrillPots events

Once you have successfully established a WebSocket connection, you can now subscribe to ThrillPots events. This is done by sending a subscription request via the WebSocket to ThrillConnect. See below for the SubscribeRequest message that should be sent to subscribe to all ThrillPots events:

{
    "SubscribeRequest": {
        "events": [{
            "source": "thrillpots",
            "event_type": "*"
        }]
    }
}

If you would like to subscribe to only certain events, you can do so by explicitly specifying the events by source one-by-one.

ThrillPots currently publishes the folliowing event types:

  • JackpotUpdateEvent
  • WinEvent
  • RaffleWinEvent
  • OptInEvent

For more information about the structure of each of these events, see ThrillPots Event Structures

Player Opt-in / Opt-out

To opt a player in or out of a jackpot, you must send a PlayerOptInRequest message via the WebSocket connection.

Below are a few examples of opting a player in and out of a jackpot instance (please note, you will need to have the jackpot instance ID):

Opting in

{
    "PlayerOptInRequest": {
        "instance_id": "8dcc9f5a-f1c5-466f-83e9-928277d8bfb7",
        "player_id": "player_00001",
        "brand_id": "thrilltech:brand1",
        "player_country": "MT",
        "opt_in": true
    }
}

Opting in with a preferred contribution value of 0.20

{
    "PlayerOptInRequest": {
        "instance_id": "8dcc9f5a-f1c5-466f-83e9-928277d8bfb7",
        "player_id": "player_00001",
        "brand_id": "thrilltech:brand1",
        "player_country": "MT",
        "opt_in": true,
        "contribution_value": 0.2
    }
}

Opting out of a Jackpot

{
    "PlayerOptInRequest": {
        "instance_id": "8dcc9f5a-f1c5-466f-83e9-928277d8bfb7",
        "player_id": "player_00001",
        "brand_id": "thrilltech:brand1",
        "player_country": "MT",
        "opt_in": false
    }
}

Retrieving Exchange Rates

You may need to convert the values of a jackpot instance from the Jackpot currency to a player's currency. To help facilitate this, ThrillConnect exposes a currency endpoint which allows you to fetch the exchange rates used by ThrillPots.

To retrieve the 202408-1 exchange rates, you can call:

GET /v1/currencies

Retrieving a player's raffle ticket count

If player's are contributing to a Raffle jackpot, you may want to show the player how many tickets they have earned so far in the raffle. You can retrieve the player's current ticket count by requesting it via the WebSocket connection:

To retrieve a player's ticket count, send a PlayerRaffleTicketsRequest message:

{
    "player_id": String,
    "instance_id": String,
    "brand_id": String
}

The instance_id is the instance ID of the Raffle jackpot, and the brand_id is in the format operator_id:brand_id.

If the request can be serviced, you should received a PlayerRaffleTicketsResponse message back:

{
    "msg_type": "Message",
    "source": "thrillpots",
    "msg_name": "PlayerRaffleTicketResponse",
    "operator_id": "OPERATOR_ID",
    "brand_id": "BRAND_ID",
    "player_id": "PLAYER_ID",
    "data": {
        "ticket_count": 4
    },
    "timestamp": 1711452762485
}

If there was an error processing the request, you will receive an Error message in response which will contain the message name that errored, as well as any relevant error details. For example:

{
    "msg_type": "Error",
    "source": "thrillpots",
    "msg_name": "PlayerRaffleTicketRequest",
    "operator_id": "OPERATOR_ID",
    "brand_id": "BRAND_ID",
    "player_id": "PLAYER_ID",
    "data": {
        "status_code": 404,
        "code": "",
        "message": "Error 404 Not Found from http://localhost:8084/instances/raffle/e0dee1ae-6231-458a-ad6d-4dc0c941e5c3/tickets/player_00001/brand/thrilltech:brand1"
    },
    "timestamp": 1711452757807
}

In this case, the request Jackpot instance ID could not be found.

ThrillConnect JS Client

ThrillConnect Client is the glue that connects your Portal and ThrillTech systems to provide seamless experience for your players. It is designed with minimialistic, yet powerful API, that can be easily consumed and covers all the narrow and tricky edgecases of the frontend integration. It's purpose is to make your frontend development trivial and expose the full API surface with minimum effort.

On this page you can find all the relevant details on how to use the Client, as well as examples and use cases.

Client version will be aligned with service version and just like that you'll be subscribed to all the latest and greatest features of our platform.

Source

Source code is avaiable for review & fork for all ThrilTech customers. You can find the client at https://github.com/thrilltech-io/connect-client.

Initialization

Client constructor needs the host address and BrandContext. Player context can optionally be passed on initialization or later on via authenticate method. Additionally one can specify dev options, like the use of unsecure http/ws and client internal logs for dev convenience.
All the events of interest must be passed on to the constructor in the events array so that client can subscribe to relevant systems on the WS channel.

Player context

Player context type provides all necessary player details for establishing the WSS connection and interacting with the Jackpots from player perspective.

type PlayerContext = {
    id: string,
    token: string,
    currency: string,
    country: string,
}

Initialization without player context

Prior to having a valid player session and auth token, one can initialize the client without PlayerContext. In this limited mode the WS events will not be available and only public REST endpoints can be used to make requests. ( see API section for what is available )

import { ThrillConnect, ConnectEvents } from "./thrillconnect.js"

const client = new ThrillConnect({
    host: "localhost:11000",
    brand: {
        operator_id: "thrilltech",
        brand_id: "brand1",
    },
    dev: {
        secure: false
    },
    events: [
        ConnectEvents.JackpotUpdateEvent,
        ConnectEvents.RaffleWinEvent,
        ConnectEvents.JackpotWinEvent,
        ConnectEvents.OptInEvent,
    ]
})

Later on, once we have player details, we can authenticate and subscribe to full functionality of the client.

client.authenticate({
    id: "player_id_token_00001",
    token: "token_00001",
    country: "USA",
    currency: "USD",
})

Initialization with player context

Alternatively, if player details are known from the start, those can be passed directly to the client constructor.

const client = new ThrillConnect({
    host: "localhost:11000",
    player: {
        id: "player_00001",
        token: "token_00001",
        country: "USA",
        currency: "USD",
    },
    brand: {
        operator_id: "thrilltech",
        brand_id: "brand1",
    },
    dev: {
        secure: false
    },
    events: [
        ConnectEvents.JackpotUpdateEvent,
        ConnectEvents.RaffleWinEvent,
        ConnectEvents.JackpotWinEvent,
        ConnectEvents.OptInEvent,
    ]
})

API

Following is a list of all the available methods on connect client.

Adding an event listener

	client.on(ConnectEvent, handler)

Adding an once off event listener

	client.once(ConnectEvent, handler)

Removing an event listener

	client.off(ConnectEvent, handler)

Passing player context

	client.authenticate(PlayerContext)

Fetching the currency multipliers

	const multipliers = await client.request().getCurrencies()

Fetching the list of defined sources for the provided BrandContext

	const sources = await client.request().getSources()

Getting the Jackpot instance that maps to a source

	const sourceId = "sitewide-jackpot"
	const instance = await client.request().getJackpotForSource(sourceId)

Getting the player OptIn status for a source

Note: PlayerContext is required for this request.

	const sourceId = "sitewide-jackpot"
	const status = await client.request().getOptInStatusForSource(sourceId)

Opting in/out from a source

Note: PlayerContext is required for this request. This request uses the authenticated WS channel. When jackpot allows for variable contribution, preferred contribution value can be passed as 3 parameter.

	const sourceId = "sitewide-jackpot"
	const optIn = true
	const preferredContributionValue = undefined

	client.request().optIntoSource(sourceId, optIn, preferredContributionValue)

Opting in/out from an instance

Note: PlayerContext is required for this request. This request uses the authenticated WS channel. When jackpot allows for variable contribution, preferred contribution value can be passed as 3 parameter.

	const instanceId = "dd7243ea-9992-47ae-a2a6-531b3f0e2197"
	const optIn = true
	const preferredContributionValue = undefined

	client.request().optIntoInstance(instanceId, optIn, preferredContributionValue)

Events

Client receives events via the WS connection. In order to receive an event, it needs to explicitly be listed in the list of events in the Client constructor. All the available events are listed in ConnectEvents.

import { ConnectEvents } from "./thrillconnect.js"

function updateTickers(e:JackpotUpdateEvent) {
    console.log(e.status)
}
// subscribe to Jackpot updates
client.on(ConnectEvents.JackpotUpdateEvent, updateTickers)
// unsubscribe from Jackpot updates
client.off(ConnectEvents.JackpotUpdateEvent, updateTickers)

Animation Driver

ThrillTech supplies a default set of Jackpot win animations to enrich the player experience during a Jackpot win. The animations driver is a JS library that takes care of win animations loading and playback. Animations are easily customizable and the driver allows for flexible cusomizations of the playback.

Source

Source code is avaiable for review & fork for all ThrilTech customers. You can find the driver at https://github.com/thrilltech-io/animations-driver.

Overview

The JS driver exposes two functions:

  • preload(config, tier, muted) - loads the required assets per pased configuration object. When muted, sounds will not be loaded.
  • run(config, tier, amount, muted) - starts the animation sequence defined in the configuration. Run will do load if assets are not already loaded.

The preload function is intended to provide separation of the loading phase, so that in case of unreasonably slow connection, stale loading can be detected and acted upon (for example using a fallback alert / win message if assets load didnt complete in a certain period).

Mute state cannot be controlled after the animation is run. The current sound preference should be passed to the run ( and optionally preload ) and based on that the defined in configuration sfx are either loaded or not.

Usage

import { preload, run } from "./main.js"

const config = "/configs/example.json"
const tier = "super"
const amount = 10000
const muted = false

preload(config, tier, muted).then(()=>{
    run(config, tier, amount, muted)
})

Configuration

See example configurations in ./public/configs in the driver repository.

Following is a full possible configuration with all settings commented inline.

{
    "dom": {
        // optional - skip "top" section if no header is required
        "top": {
            // id of top container
            "id": "top-container",
            // messages to display during presentation phase
            "message": {
                "id":"top-message",
                // message during wheel spin
                "wheel": "Stop the wheel and win BIG! BIG!",
                // message during tickup
                "tickup": "Congratulations!"
            }
        },
        // optional - skip "bottom" section if no footer is required
        "bottom": {
            // id of bottom container
            "id": "bottom-container",
            // action button
            "button": {
                // id of the action button
                "id": "action-button",
                // actions during wheel phase
                "wheel": {
                    "stop": "STOP THE WHEEL",
                    "skip": "SKIP THE WHEEL"
                },
                // actions during tickup phase
                "tickup": {
                    "skip": "SKIP TICKUP"
                },
                // actions after tickup
                "end": {
                    "close": "CLOSE"
                }
            }
        },
        // enable touch controls during phase
        "touch": {
            // touch during wheel acts as stop / skip
            "wheel": {
                "stop": true,
                "skip": true
            },
            // touch during tickup acts as skip
            "tickup": true
        }
    },
    // ticker skin and font settings -
    // skin provided and customised by thrilltech
    "ticker": {
        "skin": "/ticker/Win_BG.skel",
        "font": "/fonts/rubik.woff",
        "fontFamily": "rubik",
        // maximum font size for the tickup
        "maxFontSize": 80,

        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
        // the currency for the win amount as per ISO 4217 currency codes
        // optional, leave empty for no currency or monetary amount format
        "currency":"JPY",
        // A string with a BCP 47 language tag, optional
        "currencyFormat":"en-US"
    },
    // wheel skin and segments settings -
    // skin provided and customised by thrilltech
    "wheel": {
        "rotate": 0,
        "base": "/wheel/Wheel_of_Fortune.skel",
        // wheel has 8 segments, following is the order of tiers per segments
        "segments": [
            "mini",
            "super",
            "mini",
            "epic",
            "mini",
            "super",
            "epic",
            "super"
        ],
        // map of segment textures
        "skins": {
            "mini": "/skins/demo/mini.png",
            "super": "/skins/demo/super.png",
            "epic": "/skins/demo/epic.png"
        }
    },
    // jackpot animation skin -
    // skin provided and customised by thrilltech
    "pots": {
        "mini": {
            // path of the spine export containing the mini tier animation
            "source": "/pots/mini/Thrillpot.skel",
            // prefix of the animation for this tier
            "prefix": "",
            // sound clips for all animation phases
            "sfx": {
                "intro": ["/sfx/base/mini/intro.mp3"],
                "particles": ["/sfx/base/mini/confetti.mp3"],
                "tickup_start": ["/sfx/base/mini/tickup-start.mp3"],
                "tickup_loop": ["/sfx/base/mini/tickup-loop.mp3"],
                "outro": ["/sfx/base/mini/outro.mp3]"
            }
        },
        "super": {
            // path of the spine export containing the mini tier animation
            "source": "/pots/super/Thrillpot.skel",
            // prefix of the animation for this tier
            "prefix": "",
            // sound clips for all animation phases
            "sfx": {
                "intro": ["/sfx/base/super/intro.mp3"],
                "particles": ["/sfx/base/super/confetti.mp3"],
                "tickup_start": ["/sfx/base/super/tickup-start.mp3"],
                "tickup_loop": ["/sfx/base/super/tickup-loop.mp3"],
                "outro": ["/sfx/base/super/outro.mp3]"
            }
        },
        "epic": {
            // path of the spine export containing the mini tier animation
            "source": "/pots/epic/Thrillpot.skel",
            // prefix of the animation for this tier
            "prefix": "",
            // sound clips for all animation phases
            "sfx": {
                "intro": ["/sfx/base/epic/intro.mp3"],
                "particles": ["/sfx/base/epic/confetti.mp3"],
                "tickup_start": ["/sfx/base/epic/tickup-start.mp3"],
                "tickup_loop": ["/sfx/base/epic/tickup-loop.mp3"],
                "outro": ["/sfx/base/epic/outro.mp3]"
            }
        },
    },
    // particles animation skin -
    // skin provided and customised by thrilltech
    "particles": {
        "mini": {
            "source": "/particles/confetti/Thrillpot.skel",
            "prefix": ""
        },
        "super": {
            "source": "/particles/confetti/Thrillpot.skel",
            "prefix": ""
        },
        "epic": {
            "source": "/particles/confetti/Thrillpot.skel",
            "prefix": ""
        }
    }
}

SFX

Config contains sound definitions for various phases of the animation. All sounds are optional. Sounds per animation phase are defined as an array. All elements of the phase array refer to the same sound effect. The intention is to provide multiple sfx formats and the runtime will automatically pick the one supported on the client system. Recommended formats to use are webm, wav and mp3. wav has the widest support accross devices, but is not as optimal as webm and mp3 in terms of filesize.

"sfx": {
    "intro": ["/sfx/base/epic/intro.webm", "/sfx/base/epic/intro.wav"],
    "particles": ["/sfx/base/epic/confetti.webm", "/sfx/base/epic/confetti.wav"],
    "tickup_start": ["/sfx/base/epic/tickup-start.webm", "/sfx/base/epic/tickup-start.wav"],
    "tickup_loop": ["/sfx/base/epic/tickup-loop.webm", "/sfx/base/epic/tickup-loop.wav"],
    "outro": ["/sfx/base/epic/outro.webm", "/sfx/base/epic/outro.wav"]
}

ThrillPots Event Structures

This section provides the data definitions (in JSON) for each of the ThrillPots events.

Event: JackpotUpdateEvent

{
    "id": String,
    "currency": String,
    "pots": [PotTicker],
    "allowed_brands": [String],
    "allowed_sources": [String],
    "status": String,
    "last_updated": Number
}

References:

Event: WinEvent

{
    "brand_id": String,
    "player_id": String,
    "source_id": String,
    "instance_id": String,
    "jackpot_name": String,
    "jackpot_currency": String,
    "timestamp": Number,
    "win_pot_id": String,
    "win_amounts": [CurrencyValue],
    "win_withheld": bool,
    "community_winners": [PayoutRecord],
    "games_in_jackpot": [String],
    "seed": Number
}

References:

Event: RaffleWinEvent

{
    "brand_id": String,
    "instance_id": String,
    "jackpot_name": String,
    "jackpot_currency": String,
    "currency_multipliers": {
        "brand_id": String,
        "base_currency": String,
        "multipliers": {
            "EUR": Number,
            "GBP": Number,
            "ZAR": Number,
            ...
            "NZD": Number,
            "SEK": Number
        }
    }
    "timestamp": Number,
    "winners": [
        {
            "player_id": String,
            "brand_id": String,
            "currency": String,
            "win_amount": Number
        }
    ],
    "win_withheld": bool
}

References:

The winners field contains an array of tuples. The structure of each tuples is (String, CurrencyValue). The first element in the tuple contains the ID of a winning player and the second element contains the amount that the player won.

Event: OptInEvent

{
    "instance_id": String,
    "player_id": String,
    "ext_player_id": String,
    "player_brand_id": String,
    "preferred_contribution_value": Number,
    "contribution_count": Number,
    "contribution_value": Number,
    "opted_in": Boolean,
    "last_updated": Number,
}

Event: CommunityPayoutErrorEvent

{
    "instance_id": String,
    "gameround_id": String,
    "tx_credit_id": String,
    "failed_payouts": [
        {
            "player_id": String,
            "brand_id": String,
            "currency": String,
            "win_amount": Number
        }
    ]
}

Event: RafflePayoutErrorEvent

{
    "instance_id": String,
    "failed_payouts": [
        {
            "player_id": String,
            "brand_id": String,
            "currency": String,
            "win_amount": Number
        }
    ]
}

Structure References

PotTicker

{
    "id": String,
    "is_progressive": Boolean,
    "current_value": Number
}

CurrencyValue

{
    "currency": String,
    "value": Number
}

PayoutRecord

{
    "player_id": String,
    "brand_id": String,
    "currency": String,
    "win_amount": Number
}

APIs

In this section, you will find the necessary API documentation for the relevant integration services for a SaaS integration:

Thrillpots Gateway

OpenAPI Spec: Download Open

Swagger API: Download Open

ThrillGate

OpenAPI Spec: Download Open

Swagger API: Download Open

ThrillConnect

OpenAPI Spec: Download Open

Swagger API: Download Open

NOTE: This is early documentation for the scheduling system and the documentation will be further extended over time with additional examples and more details

Advanced Scheduling

The ThrillPots system provides a relatively sophisticated sub-system which allows you to create schedules for your jackpot products.

It is important to understand what a schedule is in the context of ThrillPots.

At its core, a schedule is always bound to a Jackpot Instance. A schedule can be as simple as defining the date and time that a jackpot starts at, or defining an end date and time for jackpot.

Here are some interesting use cases that can be solved with schedules as well:

  • Happy Hour Jackpot: Creating a jackpot that only accepts contributions during 17:00 and 18:00
  • Promotional Jackpots: Creating a jackpot that only accepts contributions at peak times of site activity or to encourage players during low activity times
  • Weekend Jackpots: Creating a jackpot that is only available on weekends

Schedules become even more powerful when used together with Raffle Jackpots. Raffle Jackpots are jackpots that resolve at the end of a predefined period of time. While players participate in the Raffle Jackpot by way of contribution (as with any other jackpot), raffle jackpots issue tickets to players based on either their Contribution or the base wager that they make into games.

Recurrence Rulesets

All the rules for the scheduling system revolve around "recurrence rules". Currently, recurrence rules are implemented for "Daily" and "Weekly" rulesets.

Daily rules

Daily rules define a set of hours within which the jackpot is available in. Traditionally, jackpot contributions are allowed during all hours of the day, but lets imagine that you wanted to create a jackpot that was only available during your site's "Happy Hour" which was between the hours of 7pm to 9pm UTC.

For such a rule to exist, you would only need to define a Daily recurrence rule which stipulated that the hours of 19:00 to 21:00 UTC were valid.

Weekly rules

Taking the example from above, lets imagine that we wanted to further constrain the available days of the raffle to be from Monday to Friday (no weekend contributions allowed!). In this case, we would create a "Weekly" ruleset which define the following days as being valid: Monday through to Friday.

As a last minute change, business might want to allow contributions to happen on a Saturday, but only between 08:00 UTC to 20:00 UTC. To allow this specificity of ruleset, we can apply an additional override for Saturday for those specific hours at the Weekly schedule level.

Technical Example

For a technical example of what a complete schedule as described above would look like, the following JSON structure accurately describes the ruleset. For arguments sake, we will define the schedule to start on the 1st of January 2024 UTC, with no end to the schedule.

To summarise, we will be creating a schedule that:

  • Allows contributions to occur Monday, Tuesday, Wednesday, Thursday, Friday and Saturday
  • From Monday to Friday, contributions will be allowed between 19:00:00 UTC and 21:00:00 UTC
  • On Saturdays, contributions will be allowed between 08:00:00 UTC and 20:00:00 UTC
{
	"timestamp_start": 1704067200000,
	// No `timestamp_end` is specified since the schedule has no end
	"recurrence_rules": [
		{
			"frequency": {
				"Daily": {
					"hours": [
						[
							{ "hour": 19, "minute": 0, "sec": 0 }.
							{ "hour": 21, "minute": 0, "sec": 0 }
						]
					]
				}
			},
			"interval": 1, // 1 means "every day". 2 would mean "every second day"
		},
		{
			"frequency": {
				"Weekly": {
					"days": [
						["Mon", null].
						["Tue", null],
						["Wed", null],
						["Thu", null],
						["Fri", null],
						["Sat", {
							"Daily": {
								"hours": [
									[
										{ "hour": 8, "minute": 0, "sec": 0 },
										{ "hour": 20, "minute": 0, "sec": 0 }
									]
								]
							}
						}]
					]
				}
			}
		}
	]
}

As can be seen from this example, when defining the Weekly rule, each day of validity needs to be specified, along with any overrides to the underlying Daily rules that may exist.

Order of Precendence

It is important to note that any hourly overrides present in the Weekly ruleset will take precedence over those specified in the Daily rules.

How Scheduled Jackpots work

When a schedule is applied to a normal Jackpot Instance, the system performs some rudimentary initial checks (making sure that when the jackpot is created with a schedule in the future, that the status is correctly set to Pending).

Once the Jackpot Instance is Active, the applied schedule defines the periods of time during which contributions will be accepted by the Jackpot Instance. When the schedule is not accepting contributions, the Jackpot Instance will continue to be Active (this behaviour may change in the future).

How Scheduled Raffles work

When instantiating Raffle Jackpots, a schedule must be provided during instantiation time

The reason for this is due to the fact that raffles are fundamentally time-based entities with at least a start time and duration-per-raffle.

Raffles have an explicit duration which is defined as part of the Raffle Rules. Durations can be defined in units of Seconds, Minutes, Hours, Days or Weeks.

Raffles that have a schedule that is longer than a raffles duration are considered "recurring raffles" while raffles that have a schedule equal to their duration are considered "once-off raffles".

Lets examime a few examples to explore this concept:

Once off Raffles

Lets imagine a scenario where an operator wants to run a once-off raffle for the Festive season (Xmas) period which start from 00:00:00 UTC on the 1st of December 2024 and the raffle resolves (pays out) at 09:00:00 UTC on the 25th of December 2024.

Additional requirements for the raffle are that the raffle should only accept contributions between the hours of 8am CET until the end of each day.

In order to create a schedule for this type of raffle, we need to create rules that specify the hourly restrictions as well as the start and end of the raffle.

Example

{
	// Sunday, 1 December 2024 00:00:00
	"timestamp_start": 1733011200000,
	// Wednesday, 25 December 2024 09:00:00
	"timestamp_end": 1735117200000
	"recurrence_rules": [
		{
			"frequency": {
				"Daily": {
					"hours": [
						[
							{ "hour": 8, "minute": 0, "sec": 0 }.
							{ "hour": 23, "minute": 59, "sec": 59 }
						]
					]
				}
			},
			"interval": 1,
		}
	]
}

As can be seen in the example, the timestamp_start and timestamp_end have been set to the period of the Festive Season (December 1st, 2024 to December 25th 2024 respectively) and the hours of availability are set from 08:00:00 UTC to 23:59:59 UTC.

Since the jackpot is available on all days through the period, there is no need to define the Weekly ruleset.

In addition to the schedule, the raffle will also need to be configured to run for the duration of the schedule. In this case, the duration will be 24 days and 9 hours.

NOTE In general, you as an operator do not need to worry about the duration configuration as this is configured as part of the Jackpot template by the ThrillTech Jackpot Model design team and not something you as an operator need to worry about.

Daily Raffles

In this example, we will be configuring a Raffle jackpot that is available on all days of the week and will resolve (pay prizes to players) at 10pm UTC (22:00:00 UTC) each day. The raffle will start at 00:00:00 of each day and end when it resolves daily.

Example:

In this example, the raffle started on August 1st, 2024 at 00:00:00 UTC:

{
	// Thursday, 1 August 2024 00:00:00
	"timestamp_start": 1722470400000,
	"recurrence_rules": [
		{
			"frequency": {
				"Daily": {
					"hours": [
						[
							{ "hour": 0, "minute": 0, "sec": 0 }.
							{ "hour": 22, "minute": 0, "sec": 0 }
						]
					]
				}
			},
			"interval": 1,
		}
	]
}

In addition to the schedule, the raffle's duration will be defined to last 22 hours.

General Services

ThrillConnect Service

The ThrillConnect Service is designed to be an "edge" service, meaning that it can be deployed to the edge of your hosting environment and service requests from your frontend(s) as well as other services (both internal or 3rd party).

ThrillConnect provides the following API interfaces for your frontend to use:

ThrillConnect: ThrillPots REST API

ThrillConnect provides a REST API for your applications (frontend or otherwise) to safely retrieve information about jackpots that are running in the environment.

Retrieving a Jackpot for a particular Source

If you want to retrieve a jackpot for a specific source_id, you can call the following endpoint:

GET /v1/thrillpots/instances/source/:source_id/brand/:brand_id

ParameterTypeRequiredDescription
source_idPathYesThe source ID for the request
brand_idPathYesThe brand ID for the request
player_idQueryNoThe player ID that the request should be specific for
country_codeQueryNoThe country code for the request

This request will use the provided parameters to retrieve the most appropriate jackpot for the source_id, brand_id, player_id and country_code combination.

If you specific the player_id, you will also receive the opt-in status for that player in the response.

HINT: Once you have retrieved the Jackpot for a source, you can use the id of the Jackpot instance for when you need to opt a player in or out

Retrieving Currency Exchange Rates

If you need to retrieve the active exchange rates in use by the ThrillPots system, you can call the currencies endpoint:

GET /v1/currencies

This will retrieve the current exchange rates from the base currency of the system, for example:

{
    "last_updated": 1715126401000,
    "base_currency": "EUR",
    "multipliers": {
        "EUR": 1.0,
        "USD": 1.0762,
        "GBP": 0.8592,
        "CAD": 1.4753,
        "PLN": 4.311,
        ...
        "NZD": 1.7921,
        "AUD": 1.6303,
        "RON": 4.9753,
        "SGD": 1.4567,
        "SEK": 11.6761,
    }
}

Retrieving ThrillPots Sources

You can retrieve all configured sources for a specific brand by using:

GET /v1/thrillpots/sources?owner_id=XXX

The response to this query, if any sources have been configured for the owner_id will look something like this:

[
    {
        "owner_id": "thrilltech:brand1",
        "source_name": "site-wide",
        "source_id": "site-wide-source",
        "jackpots": [
            {
                "priority": 0,
                "owner_id": "thrilltech",
                "instance_id": "209cc142-ccb2-4e28-a763-0a031b560d74"
            }
        ]
    },
    {
        "owner_id": "thrilltech:brand1",
        "source_name": "Deposit jackpot",
        "source_id": "deposit-source",
        "jackpots": [
            {
                "priority": 0,
                "owner_id": "thrilltech",
                "instance_id": "0a031b56-4e28-a763-ccb2-2090d74cc142"
            }
        ]
    }
]

ThrillConnect: WebSocket API

ThrillConnect exposes an authenticated WebSocket API for use by your frontend or service applications.

Connecting to the WebSocket endpoint

In order to connect to the ThrillConnect WebSocket endpoint, create a WebSocket client and connect to:

ws://thrillconnect_service_host/v1/events/:operator_id/:brand_id

ParameterTypeRequiredDescription
operator_idPathYesThe operator ID of the casino
brand_idPathYesThe brand ID of the casino
tokenQueryYesThe session token for the player that is connecting
currencyQueryYesThe currency of the player that connecting

Example

ws://thrillconnect_service_host/v1/events/casino-group/awesome-brand?token=session_token_00001&currency=USD

Once a connection is established, ThrillConnect will attempt to authenticate the player using the token provided with your wallet/account system. This authentication will take place using the Authentication endpoint via ThrillGate.

If authentication is successful, the connection will remain open. If authentication fails, the connection will be closed with a 401 error.

WS Message Structure

All messages that you receive from the ThrillConnect WebSocket connection have the following structure:

{
    "msg_type": String, ("Event" | "Message" | "Error"),
    "source": String,
    "msg_name": String,
    "operator_id": String,
    "brand_id": String,
    "player_id": String,
    "data": Object,
    "timestamp: Number
}
FieldDescription
msg_typeThis can contain one of the following values:

- Event
- Message
- Error
sourceThis indicates the source system that sent the message. In the case of ThrillPots, the value will be thrillpots
msg_nameThe name of the message. Refer to the events and requests sections for more information
operator_idThe operator ID that this message is targetted for
brand_idThe brand ID that this message is targetted for
player_idIf not null, the player_id that the message is targetted for
dataThe message payload (structure is dependent on the msg_type)
timestampThe timestamp (UNIX epoch) that the message was sent at

ThrillConnect: Event Subscription

Subscribing for events

Once you have a connection established, you will usually want to subscribe for events. The ThrillTech event system allows you to specify which systems, and which events from those systems, you wish to subscribe to.

To subscribe for events from the ThrillPots system, you must send a SubscribeRequest message via the websocket connection. For example, to subscribe to all events from the thrillpots system, you can send the following message:

{
    "SubscribeRequest": {
        "events": [{
            "source": "thrillpots",
            "event_type": "*"
        }]
    }
}

If you want to subscribe to specific events only, for example if you only want to subscribe to JackpotUpdateEvents, you could send the following request:

{
    "SubscribeRequest": {
        "events": [{
            "source": "thrillpots",
            "event_type": "JackpotUpdate"
        }]
    }
}

Event Types

The following events are available to be subscribe to for ThrillPots:

EventDescription
JackpotUpdateThese events provide periodic updates for all active jackpots
OptInEventThese events provide updates on the connected player's opt-in status
WinEventThese events provide win notifications (not specifically for the connected player)
RaffleWinEventThese events provide win notifications for raffle jackpot wins

JackpotUpdate

JackpotUpdate events are sent periodically to keep your application informed of the latest jackpot values.

An example JackpotUpdate event could look like this:

{
    "msg_type": "Event",
    "source": "thrillpots",
    "msg_name": "JackpotUpdate",
    "operator_id": "thrilltech",
    "brand_id": "brand1",
    "player_id": null,
    "data": {
        "id": "f689317d-81c8-4395-b689-10ce6f88089e",
        "currency": "EUR",
        "pots": [
            {
                "id": "minor",
                "is_progressive": true,
                "current_value": 10.0
            },
            {
                "id": "major",
                "is_progressive": true,
                "current_value": 100.21749999999994
            },
            {
                "id": "mega",
                "is_progressive": true,
                "current_value": 1000.045
            }
        ],
        "allowed_brands": [
            "thrilltech:brand1",
            "thrilltech:brand2",
        ],
        "allowed_sources": [],
        "status": "Active",
        "last_updated": 1715154276442
    },
    "timestamp": 1715191298453
}

OptInEvent

When a player opts-in or opts-out of a jackpot, an event will be sent to that player's WebSocket connection. An structure of the data for an OptInEvent looks like this:

{
    "instance_id": String,
    "player_id": String,
    "player_brand_id": String,
    "preferred_contribution_value": Number,
    "opted_in": Boolean,
    "last_updated": Number,
}

WinEvent

When a Jackpot is won, the ThrillPots system publishes a WinEvent which contains the details of the win. This message is sent to all connections that are subscribed to the receive the event. The structure of the data portion of the Event message looks like this:

{
    "brand_id": String,
    "player_id": String,
    "source_id": Option<String>,
    "instance_id": String,
    "jackpot_name": String,
    "jackpot_currency": String,
    "timestamp": u64,
    "win_pot_id": String,
    "win_amount": Number,
    "currency_multipliers": {
        "brand_id": String,
        "base_currency": String,
        "multipliers": {
            "EUR": Number,
            "GBP": Number,
            "ZAR": Number,
            ...
            "NZD": Number,
            "SEK": Number
        }
    }
    "win_withheld": bool,
    "community_winners": null | [
        {
            "player_id": String,
            "brand_id": String,
            "currency": String,
            "win_amount": Number
        }
    ],
    "games_in_jackpot": Vec<String>,
    "seed": Decimal
}

RaffleWinEvent

When a Raffle Jackpot resolves and winners are determines, a RaffleWinEvent which contains the details of the wins will be sent. The message is sent to all connections that are subscribed to receive the event. The structure of the data portion of the Event message looks like this:

{
    "brand_id": String,
    "instance_id": String,
    "jackpot_name": String,
    "jackpot_currency": String,
    "currency_multipliers": {
        "brand_id": String,
        "base_currency": String,
        "multipliers": {
            "EUR": Number,
            "GBP": Number,
            "ZAR": Number,
            ...
            "NZD": Number,
            "SEK": Number
        }
    }
    "timestamp": Number,
    "winners": [
        {
            "player_id": String,
            "brand_id": String,
            "currency": String,
            "win_amount": Number
        }
    ],
    "win_withheld": bool
}

ThrillConnect: ThrillPots Requests

You can use the authenticated WebSocket connection to send requests that are relevant to the authenticated player.

Opt-In/Out Request

In order to opt a player into or out of a jackpot, you use the PlayerOptInRequest message. This allows you to send not only standard opt-in / opt-out requests, but also to specify the contribution value that the player wishes to opt-in with.

Example: Opting a player in with the default contribution value

{
    "PlayerOptInRequest": {
        "instance_id": "209cc142-ccb2-4e28-a763-0a031b560d74",
        "player_id": "player_id_token_00001",
        "brand_id": "thrilltech:brand1",
        "player_country": "MT",
        "opt_in": true
    }
}

Example: Opting a player in with a specific contribution value (0.30)

{
    "PlayerOptInRequest": {
        "instance_id": "209cc142-ccb2-4e28-a763-0a031b560d74",
        "player_id": "player_id_token_00001",
        "brand_id": "thrilltech:brand1",
        "player_country": "MT",
        "opt_in": true,
        "contribution_value": 0.3
    }
}

Example: Opting a player out of a jackpot

{
    "PlayerOptInRequest": {
        "instance_id": "209cc142-ccb2-4e28-a763-0a031b560d74",
        "player_id": "player_id_token_00001",
        "brand_id": "thrilltech:brand1",
        "player_country": "MT",
        "opt_in": false
    }
}

If the opt-in or opt-out request was successful, you will receive an OptInEvent

Retrieving a player's raffle tickets for a specific instance

To retrieve a player's raffle ticket count for a specific Raffle Jackpot, send the PlayerRaffleTicketsRequest message:

{
    "PlayerRaffleTicketsRequest": {
        "player_id": "player_00001",
        "instance_id": "f0dee1ae-6231-458a-ad6d-4dc0c941e5c3",
        "brand_id": "thrilltech:brand1"
    }
}

If the request was valid, you will receive a PlayerRaffleTicketResponse message:

{
    "msg_type": "Message",
    "source": "thrillpots",
    "msg_name": "PlayerRaffleTicketResponse",
    "operator_id": "thrilltech",
    "brand_id": "brand1",
    "player_id": "player_00001",
    "data": {
        "instance_id": "f0dee1ae-6231-458a-ad6d-4dc0c941e5c3",
        "ticket_count": 8
        "timestamp_start": 134857982371,
        "timestamp_end": 14384723487,
    },
    "timestamp": 1715191298453
}

Retrieving all of a player's raffle tickets for active raffles

To retrieve all the raffle tickets for all active raffles for a player (in other words, not specific to a particular raffle), you can use a modified version of the above PlayerRaffleTicketsRequest request (omitting the instance_id on the request):

{
    "PlayerRaffleTicketsRequest": {
        "player_id": "player_00001",
        "brand_id": "thrilltech:brand1"
    }
}

If the player has earned any raffle tickets on any active raffles, the response will be a PlayerRaffleTicketListResponse and will look something like this:

{
    "msg_type": "Message",
    "source": "thrillpots",
    "msg_name": "PlayerRaffleTicketListResponse",
    "operator_id": "thrilltech",
    "brand_id": "brand1",
    "player_id": "player_00001",
    "data": {
        "instance_tickets": [
            {
                "instance_id": "raffle_instance_a_id",
                "ticket_count": 8
                "timestamp_start": 134857982371,
                "timestamp_end": 14384723487,
            },
            {
                "instance_id": "raffle_instance_b_id",
                "ticket_count": 3
                "timestamp_start": 134857982371,
                "timestamp_end": 14384723487,
            },

        ]
    },
    "timestamp": 1715191298453
}

In the case that a player has not earned any raffle tickets for active raffles, the list will be empty. For example:

{
    "msg_type": "Message",
    "source": "thrillpots",
    "msg_name": "PlayerRaffleTicketListResponse",
    "operator_id": "thrilltech",
    "brand_id": "brand1",
    "player_id": "player_01010",
    "data": {
        "instance_tickets": []
    },
    "timestamp": 1715191298453
}

ThrillGate Service

ThrillGate is the service used to integrate with an operator's wallet and bonus APIs. It supports both Provider-to-Operator and Operator-to-Provider integration models, meaning that either ThrillTech can integrate to an operator's APIs or the operator can integrate to ThrillTech's "Standard" integration API.

At its core, ThrillGate provides a standard approach to authenticating player session tokens, performing transactions (both single and batches of transaction) as well as transaction cancellation mechanics.

Standard Wallet API

When doing an Operator-to-Provider integration, ThrillGate provides a definition of an API that should be exposed by the operator wallet. This definition is called the "Standard Wallet API" and supports all the functionality that ThrillTech services require from an integration with the operator platform.

Security

The Standard Wallet API uses HMAC to secure its payloads and allow the operator system to verify that the request has been sent from the expected ThrillGate source service.

Integrating

Refer to the product specific section(s) on integrating ThrillGate's Standard Wallet API with your platform.

ThrillPots Wallet Integration

Configuring Wallet Error Behaviour

NOTE: Self-Hosted customers have the ability to define these conditions themselves within ThrillGate. If you are a SaaS customer, you will need to request any specific rules that you wish you to have via your Account Manager

It is possible to configure the way ThrillGate reacts to specific wallet errors.

The standard wallet error structure is defined as:

{
    "code": String,
    "message": String
}

Therefore, if your wallet need to respond with a 403 error (for example), the response would be:

HTTP Error Code: 403 Body:

{
    "code": "FORBIDDEN",
    "message": "",
}

Now, if you wanted to configure ThrillGate to never retry when your wallet returns a 403 error, you could add the following sub-document to your wallet's config field:

{
    ...
    "config": {
        "error_response_rules": {
            "403:FORBIDDEN": {
                "must_retry": false
            }
        }
    }
}

From this example, you can see that you can also specialise specific errors based on their code value in the error response.

In other words, you could create different rules for handling a 400 error with code set to INVALID_STRUCTURE and separate rules for 400 with code set to INVALID_PROPERTY_VALUE.

This type of control can be useful if your wallet has specific requirements for retry or cancellation handling from ThrillGate.

The error_response_rules object structure is defined as:

{
    "HTTP_ERROR_CODE:ERROR_CODE_VALUE": {
        "must_retry": Boolean,
        "must_cancel": Boolean,
    }
}

Both must_retry and must_cancel are optional values and default to true if not set.

ThrillOffice Overview

The highlight of our September release is the new ThrillOffice service. A complementary update of Thrill-ID brings the required system definition and default service credentials for ThrillOffice.

Release Notes - September 2024

ThrillOffice

September brings big updates for our BackOffice! Along with lots of new frontend features, it comes with its own service. This service will take responsibility of all the reporting functionallity, currently exposed on ThrillPots. This way new BackOffice features will not be tied with upgrades on the core service and will come more frequently and easier to digest. ThrillOffice service will also provide historical data over instances, various stats and much more data to analyze and give insight on Jackpots performance.

New Features

Dashboard view

Dashboard provides a quick overview over brands performance. It introduces several widgets ( with more coming up soon):

  • Total Contributions
  • Total Winners
  • Total opted in players
  • Total GGR
  • Bets distribution
  • Top Contributors
  • Top Wins
  • Top Net Contributors

All widgets use derived timeseries data which initially will only show all-time totals and in a month time will enable more precise time frame selection.

Raffles

Raffles view is specialized instances view that targets raffles. It provides all relevant details for a Raffle Jackpot. Allows for precise filtering on brand and/or status. Expanding a Raffle instance row will display details on prizes and schedule.

Raffle Winners

Raffle Winners view is a specialized winners view for Raffles. It can be accessed by selecting Winners in Raffle instance's context menu.

Liability Report

Liability report view provides an overview of each Jackpot instances month-to-month liability. Like other reporting views it allows for targeting a brand, single instance or precise time frame.

Improved Filtering

Filters slider now includes an improved time selector that provides shortcuts for frequently used time frames.

Cross brand reporting

All reporting views now allow viewing entries across all available brands.

ThrillPots Overview

Welcome to the ThrillPots Integration Guide.

ThrillPots is an advanced standalone Jackpot Platform that allows casinos to offer their players jackpots over "everything". Be it offering a sitewide jackpot across games from various providers, to a seasonal Raffle jackpot for the 12 days of Christmas or even a Bad Beat jackpot for your poker players, ThrillPots can do it all (and more).

The goal of this guide is to make integrating with ThrillPots as painless as possible by providing you, the technical reader, with all the information you need and taking you step by step through a standard integration process.

Release Notes - August 2024

General

  • Improvements to the OpenAPI Documentation continue to be made and this release has focused on documentation accuracy on the Standard Wallet API protocol, ThrillConnect and ThrillPots Gateway. This is an ongoing effort.

New Features

ThrillPots

  • Recurring Raffles

    • In previous releases, raffles were limited to being once-off scheduled jackpots. In this release, we have extended the scheduling capabilities of the system to allow granular control of jackpot and raffle schedules.
      • More information about scheduling can be found here
  • Raffle Ticket Enhancements

    • As of this release, raffle tickets can be configured based on a player's base_wager or contribution. Previous releases only supported ticket costs based on contribution.
    • It is now possible to retrieve all of a player's raffle tickets for all active raffles (instead of retrieving them one raffle instance at a time).
      • ThrillPots Gateway:
        • GET /jackpots/instances/raffle/tickets/brand/:brand_id/:player_id
  • Advanced Scheduling

    • As mentioned in the Recurring Raffles feature above, we have introduced a more advanced scheduling subsystem to the platform.
    • In ThrillPots, schedules are bound to a Jackpot Instance and a brand
  • Seed Boosts

    • The seed boosts feature allows operators to add additional funds to a Jackpot which will act as additional seed buffers when a jackpot is won.
    • Seed Boosts can be applied to specific pots within a Jackpot. For example, if you wished to add a Seed Boost to your top tier only, you could do so.

Changes/Improvements

ThrillPots

  • Async Contribution Errors now carry metadata

    • For integrations that make use of asynchronous contributions, you may have noticed that the metadata supplied on the contribution call was not propogated on errors reported to the webhook.
    • This issue has now been addressed and the webhook will receive the original metadata on all errors under the metadata field.
  • JackpotEventUpdate event changes

    • Added the following new fields to the event:
      • jackpot_type - Indicates where the instance is a Jackpot or a Raffle (these are the two valid values for this field)
      • timestamp_start - If the instance has a schedule, this field will contain the UTC timestamp for the starting time of the active jackpot instance
      • timestamp_end - If the instance has a schedule and an end time for the instance, this field will contain the UTC timestamp for the end
    • An example of the new structure looks like this:
    {
    	"event_type": "JackpotUpdateEvent",
    	"data": {
    		"id": "ab775921-0743-47d4-8ad2-cd60aae27b39",
    		"jackpot_type": "Raffle",
    		"currency": "EUR",
    		"pots": [
    			{
    				"id": "main",
    				"is_progressive": false,
    				"current_value": 100.0
    			}
    		],
    		"allowed_brands": [
    			"thrilltech:brand1",
    			"thrilltech:brand2",
    			"thrilltech:my-new-brand"
    		],
    		"allowed_sources": [
    			"raffle-test"
    		],
    		"status": "Active",
    		"timestamp_start": 1728604800000,
    		"timestamp_end": 1728691199000,
    		"last_updated": 1728604800000
    	}
    }
    
    • Resolve Raffles not actively updating to Active state based on scheduling
  • Zero value contributions are allowed

    • Up until now, Jackpot Templates did not allow contribution values to be specified as ZERO.
    • As of this release, this restriction as been lifted (with certain caveats - explained below)
    • Reasons to allow zero-value contributions:
      • Promotional Jackpots: Promotional jackpots should allow zero value contributions if they are non-progressive and/or do not have value based tipping points
    • Caveats:
      • Zero value contributions can only be made to jackpots that are fully operator funded AND have all their pots defined as probability or time based tipping points.
      • For zero value contributions, there is no RTP to be calculated for wins
  • WinEvent changes

    • In previous versions, the WinEvent was only broadcast to players of the brand on which the win occurred. In this release, the WinEvent is also broadcast to all brands that are participating in the jackpot.
  • Improved Handling for Limited Jackpot Tiers

    • We have improved the handling of limited jackpot tiers. Limited Jackpot Tiers are tiers that are configured to only drop a certain amount of times. With this release, if the last available tier of a jackpot is a limited tier and the drop limit has been reached, the jackpot itself will automatically end (status == Ended) and the frontend will stop receiving JackpotUpdateEvents for the jackpot.

ThrillConnect

  • Updated payload for Get Instance By Source endpoint
    • Affected endpoint:
      • GET /v1/thrillpots/instances/source/:source_id/brand/:brand_id
    • The response now contains three additional fields:
      • status - The status of the instance
      • timestamp_start - The UTC timestamp containing when the jackpot starts/started
      • timestamp_end - The UTC timestamp containing when the jackpot will end
    • These additions allow frontends to:
      • determine whether a jackpot is active for contributions
        • if status == Active, the jackpot is active within the schedule
        • if status == Pending, the jackpot is scheduled to start at a future time
      • determine if a raffle is currently active or not
        • if status == Active, the raffle is active and accepting contributions
        • if status == Pending, the raffle is scheduled to start at a future time (timestamp_start).