The Eva platform, or simply Eva, is a platform that aggregates the content of various game suppliers and provides a single API for external operators.
With it, you can access a broad catalog of products.
This document contains a description and examples of the API provided by Eva as a content aggregator to make the integration process easier
To integrate own platform via Eva operator should:
|
1. Non-functional requirements
Here are described non-functional requirements that the operator’s wallet must follow:
-
Compatibility
Only HTTPS communication is supported.
The wallet must be forward-compatible with the all possible API changes and extensions.
This includes additional JSON fields, additional headers.
Eva does not guarantee any data that is not specified in this API and the wallet’s behavior must not depend on any other parameters (Eg: X-Forwarded-Host
, X-Forwarded-Proto
headers).
* The only exception is the HTTP Protocol requirements, eg: Host
header
-
Security
The wallet must implement these rules:
-
Authentication
Eva uses basic authentication.
Credentials must be encoded at the wallet side.
Technical team must use 1-time sharing tools (Intuitive Password, Privnote, OneTimeNote).
-
IPs whitelisting
Wallet must be protected with the IP whitelist
In case of failure against these rules, the corresponding error must be returned.
It is also highly recommended not to expose API implementation details, the HTTP status code will be enough
-
Performance
The wallet must be highly performant and maintain low latency to ensure real-time responsiveness critical to the player experience.
Any delay in loading balances or processing transactions, must be minimized to prevent a negative impact on user engagement.
Satisfactory values:
P95 percentile
Requests per second | Response Time |
---|---|
< 1000 |
< 40 ms |
1k - 2k |
< 80 ms |
> 2k |
< 350 ms |
P99 percentile
Requests per second | Response Time |
---|---|
< 1000 |
< 60 ms |
1k - 2k |
< 200 ms |
> 2k |
< 450 ms |
2. General API sequence
The following diagram illustrates the flow of information between the player’s browser, operator, and Eva
3. Game Launch
3.1. Overview
The Eva Platform provides a unified launcher URL for operators that works for all games across all providers.
The operator navigates a window to our launcher, and then Eva redirects the window to game server of the provider.
Handling this redirection flow and ensuring proper content delivery to the player is the responsibility of the operator.
The structure for the final launch URL is as follows:
https://<eva_launcher_url>?<query_parameters>
where:
-
eva_launcher_url is the base URL for the Eva launcher, which will be provided to you during the integration phase.
-
query_parameters are the query parameters required to launch a specific game.
The parameters are detailed below.
Query Parameter | Description | Type | Notes |
---|---|---|---|
channel |
Launch channel |
Enum |
Available values: |
gameId |
Game identifier |
String |
Game lobbyId provided by the Eva Platform |
language |
Optional |
String(2) |
The absence of this parameter will trigger the game launch using the default language |
lobbyUrl |
URL where the player should be redirected upon clicking the Home button inside the game UI |
String |
Must be URL encoded |
partnerKey |
Partner key |
String |
A unique key for the partner business unit, generated by the Eva Platform. |
sessionToken |
Optional |
String (max 124 characters) |
It will be sent as json field in some wallet callbacks. |
3.2. Examples
Real mode:
https://some-eva-host.com/v0/casino/games/launch?
gameId=cool-virtual-product
&channel=mobile
&partnerKey=example
&sessionToken=J7Qjpo4_vkzv8FEwC-Tw7J2YB1w5dZzpu1p6M1ij6nPc_YCQpyNOcwuregUGT6Svm16lWnmyZ
&language=it
&lobbyUrl=https%3A%2F%2Fsome-operator-lobby.com%2Fredirect%2Fhome%3Fid%3DOTV6pW%2BjErGq
Demo mode:
https://some-eva-host.com/v0/casino/games/launch?
gameId=another-virtual-product
&channel=desktop
&partnerKey=example
&lobbyUrl=https%3A%2F%2Fsome-operator-lobby.com%2Fredirect%2Fhome%3Fid%3DOTV6pW%2BjErGq
4. Wallet Integration
4.1. Key Concepts
4.1.1. Round
The casino logic is primarily centered around the concept of rounds.
-
A casino transaction is always initiated by the provider.
-
As the initiator, the provider is responsible for both finalizing the processing and confirming the success of the transaction.
A round can exist in one of two states:
Scenarios in which the above rules may be violated are described in sections Wallet-Controlled Transaction Scenarios and Special Cases Based on Provider-Specific Logic. |
4.1.2. Types of Transactions Within a Round
-
Bet: A financial transaction where funds are deducted from the player’s account. This occurs when the player places a bet.
-
Win: A financial transaction where funds are credited to the player’s account. This takes place when the player wins a game or event, resulting in a payout.
-
Refund: A financial transaction where funds are credited to the player’s account, typically under specific conditions such as canceled bets, errors, or other predefined circumstances that require reimbursement.
Providers have mechanism for sending retries for failed transaction requests:
|
4.2. Wallet Responsibility Definition
The primary responsibility of casino platform, and by extension, each wallet operating at the casino platform level, is to validate casino transactions.
This validation must align with the entire product logic, account for corner cases, and address potential fraud risks.
The wallet is responsible for determining whether a transaction should be processed based on the casino domain logic. |
4.2.1. Wallet-Controlled Transaction Scenarios
The wallet is the only system fully responsible for financial losses in the event of transaction failures. Providers do not guarantee that failures will not occur on their side; therefore, the wallet must be protected against such risks.
Based on prior experience, the following common cases occur frequently. The responsibility for handling these cases rests entirely with the wallet:
-
Refund before bet (inverted refund).
-
Refund after a failed bet (depending on the error, the wallet decides whether to process the refund or not).
-
Bet to a closed round.
-
Win to a closed round.
-
Canceling a bet after a win.
-
Bet to a refunded round.
-
Win to a refunded round.
-
Win without a bet.
4.2.2. Special Cases Based on Provider-Specific Logic
There are also edge cases that are technically invalid but are considered a normal flow for some providers due to their specific business logic. These providers request that such scenarios be allowed. This logic should also be embedded in the wallet, which determines what is valid and what is not.
Therefore, as a separate recommendation, these strategies should only be allowed or denied on a per-provider basis:
-
AllowMultipleBets – More than one bet can occur in a round.
-
AllowMultipleWins – More than one win can occur in a round.
-
AllowMultipleRefunds – More than one refund occur in a round.
-
IsWinWithoutBetAllowed – A win without a bet is allowed in a round.
-
AllowPostCloseWin – Allow or deny processing a win that is sent after the round has been closed.
-
AllowPostCloseBet – Allow or deny processing a bet that is sent after the round has been closed.
4.3. API Reference
|
Each request from the Eva Platform is sent to the mapping of the URI provided.
For example, if the URI is https://operator-uri.com/api/v1
, then the following set of mappings is used:
https://operator-uri.com/api/v1/players/accounts/:playerId?providerId=:provider https://operator-uri.com/api/v1/players/sessions/:sessionToken?providerId=:provider https://operator-uri.com/api/v1/transactions/bet https://operator-uri.com/api/v1/transactions/win https://operator-uri.com/api/v1/transactions/refund https://operator-uri.com/api/v1/transactions/promoWin https://operator-uri.com/api/v1/transactions/tournamentWin
Each request from the Eva Platform contains such mandatory headers:
Header | Value | Description |
---|---|---|
Accept |
|
Specifies the content type of the response body |
Authorization |
|
Base64-encoded |
Content-Type |
|
Indicates the content type of the request body |
X-Partner-Key |
|
A unique key for the partner business unit, generated by the Eva Platform |
4.3.1. Player Info by ID
This method retrieves information about a player (excluding balance) using the player’s identifier.
Request Example
GET /players/accounts/:playerId?providerId=:example-provider HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcm5hbWUtYWJjOnBhc3N3b3JkLWFiYw==
Content-Type: application/json
X-Partner-Key: example-key
Parameter | Type | Description |
---|---|---|
playerId |
Path parameter |
Player’s identifier |
providerId |
Query parameter |
The game provider for which the request is being made |
Response Example
HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Content-Length: 122
{
"country" : "UA",
"currency" : "USD",
"displayName" : "example-display-name",
"playerId" : "example-player-id"
}
Field | Type | Description |
---|---|---|
country |
String |
Player’s country in |
currency |
String |
Player’s currency in |
displayName |
String |
Player’s display name |
playerId |
String |
Unique player identifier |
4.3.2. Player Info by session token
This method is used to get the player’s information by session token.
Request Example
GET /players/sessions/:sessionToken?providerId=:example-provider HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcm5hbWUtYWJjOnBhc3N3b3JkLWFiYw==
Content-Type: application/json
X-Partner-Key: example-key
Parameter | Type | Description |
---|---|---|
sessionToken |
Path parameter |
Player’s session token |
providerId |
Query parameter |
Game provider for which the request is performed |
Response Example
HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Content-Length: 200
{
"balance" : {
"bonus" : 500,
"locked" : 200,
"main" : 1000
},
"country" : "UA",
"currency" : "USD",
"displayName" : "example-display-name",
"playerId" : "example-player-id"
}
Field | Type | Description |
---|---|---|
balance |
Object |
Nested object carrying player’s balance details |
balance.bonus |
Long |
Amount of money that the player received from bonus campaigns |
balance.locked |
Long |
Amount of money that the player deposited to participate in deposit campaigns |
balance.main |
Long |
Player’s main balance |
country |
String |
Player’s country in |
currency |
String |
Player’s currency in |
displayName |
String |
Player’s display name |
playerId |
String (max 28 characters) |
Unique player identifier - supported characters from The "URL and Filename safe" Base 64 Alphabet |
4.3.3. Player Session Token by player details
This method is used to initiate player’s session on partner’s platfrom by the details passed in request.
|
Request Example
POST /players/sessions?providerId=:example-provider HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcm5hbWUtYWJjOnBhc3N3b3JkLWFiYw==
Content-Type: application/json
X-Partner-Key: example-key
Content-Length: 92
{
"currency" : "USD",
"gameId" : "example-game-id",
"playerId" : "example-player-id"
}
Parameter | Type | Description |
---|---|---|
providerId |
Query parameter |
Game provider for which the request is performed |
currency |
String |
Currency to initiate the session |
gameId |
String |
Game identifier to initiate the session |
playerId |
String (max 28 characters) |
Unique player identifier - supported characters from The "URL and Filename safe" Base 64 Alphabet |
Response Example
HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Content-Length: 63
{
"sessionToken" : "QIy9BrNamCthaTuyXJeKC-zv6lwtLyqNVMEsBq"
}
Field | Type | Description |
---|---|---|
sessionToken |
String |
Player’s session token |
4.3.4. Bet Transaction
The bet (debit) method is called when funds should be deducted from the player’s balance.
|
Request Example
POST /transactions/bet HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcm5hbWUtYWJjOnBhc3N3b3JkLWFiYw==
Content-Type: application/json
X-Partner-Key: example-key
Content-Length: 370
{
"amount" : 123,
"currency" : "USD",
"gameId" : "example-game-id",
"playerId" : "example-player-id",
"provider" : "example-provider",
"reason" : "bet",
"roundClosed" : false,
"roundId" : "example-round-id",
"sessionToken" : "QIy9BrNamCthaTuyXJeKC-zv6lwtLyqNVMEsBq",
"sideSplit" : {
"base" : 100,
"side" : 23
},
"txId" : "example-tx-id"
}
Field | Type | Description |
---|---|---|
amount |
Long |
Amount of the transaction in the currency’s minor units |
currency |
String |
Currency of this transaction |
gameId |
String |
Game identifier where the bet was placed |
playerId |
String |
Player to whom the transaction is related |
provider |
String |
Game provider for which the request is performed |
reason |
String |
Reason for this transaction. Possible values: |
roundClosed |
Boolean |
Identifies whether the game round is finished |
roundId |
String |
Game round identifier |
sessionToken |
String |
Player’s session token |
txId |
String |
Unique transaction identifier |
Optional sideSplit |
Object |
Contains base and side amounts for live casino side bets |
sideSplit.base |
Long |
Amount of the main bet |
sideSplit.side |
Long |
Amount of the side bet |
Response Example
HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Content-Length: 393
{
"at" : "2023-04-06T11:47:52.859062Z",
"balance" : {
"bonus" : 500,
"locked" : 200,
"main" : 1000
},
"currency" : "USD",
"tx" : {
"at" : "2023-04-06T11:47:52.859062Z",
"id" : "example-tx-id",
"processed" : false,
"processedTxId" : "example-processed-tx-id",
"txAmountDetails" : {
"bonus" : 20,
"locked" : 10,
"main" : 30
}
}
}
Field | Type | Description |
---|---|---|
at |
String |
Timestamp indicating when the transaction was processed ( |
balance |
Object |
Nested object carrying player’s balance details |
balance.bonus |
Long |
Player’s relevant bonus balance |
balance.locked |
Long |
Player’s relevant locked balance |
balance.main |
Long |
Player’s relevant main balance |
currency |
String |
Player’s currency in |
tx |
Object |
Nested object carrying transaction details |
tx.at |
String |
Timestamp indicating when the transaction was processed ( |
tx.id |
String |
Transaction identifier from the request |
tx.processed |
Boolean |
Identifies whether the transaction was already processed before this request |
tx.processedTxId |
String |
Transaction identifier on the operator’s side |
tx.txAmountDetails |
Object |
Nested object carrying details about balance changes by this transaction |
tx.txAmountDetails.bonus |
Long |
Amount of money deducted from the bonus balance |
tx.txAmountDetails.locked |
Long |
Amount of money deducted from the locked balance |
tx.txAmountDetails.main |
Long |
Amount of money deducted from the main balance |
4.3.5. Win Transaction
The win (credit) method is called when funds should be added to the player’s balance.
Request Example
POST /transactions/win HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcm5hbWUtYWJjOnBhc3N3b3JkLWFiYw==
Content-Type: application/json
X-Partner-Key: example-key
Content-Length: 357
{
"amount" : 123,
"currency" : "USD",
"freeSpinData" : {
"freeSpin" : "no"
},
"gameId" : "example-game-id",
"playerId" : "example-player-id",
"provider" : "example-provider",
"reason" : "win",
"roundClosed" : false,
"roundId" : "example-round-id",
"sideSplit" : {
"base" : 100,
"side" : 23
},
"txId" : "example-tx-id"
}
Field | Type | Description |
---|---|---|
amount |
Long |
Amount of the transaction in the currency’s minor units |
currency |
String |
Currency of this transaction |
freeSpinData |
Object |
Nested object carrying free spin details |
freeSpinData.freeSpin |
String |
Identifies whether this transaction is related to a free spin campaign. |
gameId |
String |
Game identifier where the bet was placed |
playerId |
String |
Player to whom the transaction relates |
provider |
String |
Game provider for which the request is performed |
reason |
String |
Reason this transaction was committed. |
roundClosed |
Boolean |
Identifies whether the game round has finished |
roundId |
String |
Game round identifier |
txId |
String |
Unique transaction identifier |
Optional sideSplit |
Object |
Contains base and side winnings for live casino side bets |
sideSplit.base |
Long |
Amount of the main win |
sideSplit.side |
Long |
Amount of the side win |
Response Example
HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Content-Length: 393
{
"at" : "2023-04-06T11:47:52.859062Z",
"balance" : {
"bonus" : 500,
"locked" : 200,
"main" : 1000
},
"currency" : "USD",
"tx" : {
"at" : "2023-04-06T11:47:52.859062Z",
"id" : "example-tx-id",
"processed" : false,
"processedTxId" : "example-processed-tx-id",
"txAmountDetails" : {
"bonus" : 20,
"locked" : 10,
"main" : 30
}
}
}
Field | Type | Description |
---|---|---|
at |
String |
Timestamp indicating when the transaction was processed ( |
balance |
Object |
Nested object carrying the player’s balance details |
balance.bonus |
Long |
Player’s relevant bonus balance |
balance.locked |
Long |
Player’s relevant locked balance |
balance.main |
Long |
Player’s relevant main balance |
currency |
String |
Player’s currency in |
tx |
Object |
Nested object carrying transaction details |
tx.at |
String |
Timestamp indicating when the transaction was processed ( |
tx.id |
String |
Transaction identifier from the request |
tx.processed |
Boolean |
Identifies whether the transaction had already been processed before this request |
tx.processedTxId |
String |
Transaction identifier on the operator’s side |
tx.txAmountDetails |
Object |
Nested object carrying details about balance changes by this transaction |
tx.txAmountDetails.bonus |
Long |
Amount of money deducted from the bonus balance |
tx.txAmountDetails.locked |
Long |
Amount of money deducted from the locked balance |
tx.txAmountDetails.main |
Long |
Amount of money deducted from the main balance |
4.3.6. Refund Transaction
When the previous bet transaction needs to be rejected, the refund method is called, returning the processed bet amount to the player’s balance.
Each refund request must include the transaction ID of the bet for which the refund is intended. This ensures that every refund request is linked to the specific bet it corresponds to, enabling proper tracking and processing.
In certain cases, the refund amount may not be specified in the refund request. When this occurs, the provider expects the wallet to calculate the refund amount based on the bet details.
|
Request Example
POST /transactions/refund HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcm5hbWUtYWJjOnBhc3N3b3JkLWFiYw==
Content-Type: application/json
X-Partner-Key: example-key
Content-Length: 363
{
"amount" : 123,
"betTxId" : "example-tx-id",
"currency" : "USD",
"gameId" : "example-game-id",
"playerId" : "example-player-id",
"provider" : "example-provider",
"reason" : "refund_of_bet",
"refundTxId" : "example-tx-id_refund",
"roundClosed" : false,
"roundId" : "example-round-id",
"sideSplit" : {
"base" : 100,
"side" : 23
}
}
Field | Type | Description |
---|---|---|
amount |
Long |
Amount of the transaction in the currency’s minor units |
currency |
String |
Currency of this transaction |
gameId |
String |
Game identifier where the bet was placed |
playerId |
String |
Player to whom the transaction relates |
provider |
String |
Game provider for which the request is performed |
reason |
String |
Reason this transaction was committed. Possible values: |
roundClosed |
Boolean |
Identifies whether the game round has finished |
roundId |
String |
Game round identifier |
betTxId |
String |
TxId of the bet transaction to be refunded |
refundTxId |
String |
Unique refund transaction identifier |
Optional sideSplit |
Object |
Contains base and side amounts for live casino side bets cancel |
sideSplit.base |
Long |
Amount of the main cancel |
sideSplit.side |
Long |
Amount of the side cancel |
Response Example
HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Content-Length: 393
{
"at" : "2023-04-06T11:47:52.859062Z",
"balance" : {
"bonus" : 500,
"locked" : 200,
"main" : 1000
},
"currency" : "USD",
"tx" : {
"at" : "2023-04-06T11:47:52.859062Z",
"id" : "example-tx-id",
"processed" : false,
"processedTxId" : "example-processed-tx-id",
"txAmountDetails" : {
"bonus" : 20,
"locked" : 10,
"main" : 30
}
}
}
Field | Type | Description |
---|---|---|
at |
String |
Timestamp indicating when the transaction was processed ( |
balance |
Object |
Nested object carrying the player’s balance details |
balance.bonus |
Long |
Player’s relevant bonus balance |
balance.locked |
Long |
Player’s relevant locked balance |
balance.main |
Long |
Player’s relevant main balance |
currency |
String |
Player’s currency in |
tx |
Object |
Nested object carrying transaction details |
tx.at |
String |
Timestamp indicating when the transaction was processed ( |
tx.id |
String |
Transaction identifier from the request |
tx.processed |
Boolean |
Identifies whether the transaction had already been processed before this request |
tx.processedTxId |
String |
Transaction identifier on the operator’s side |
tx.txAmountDetails |
Object |
Nested object carrying details about balance changes by this transaction |
tx.txAmountDetails.bonus |
Long |
Amount of money deducted from the bonus balance |
tx.txAmountDetails.locked |
Long |
Amount of money deducted from the locked balance |
tx.txAmountDetails.main |
Long |
Amount of money deducted from the main balance |
4.3.7. Promo Win Transaction
When a player receives some promo offers, the promoWin method is called to add funds to the player’s balance.
Request Example
POST /transactions/promoWin HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcm5hbWUtYWJjOnBhc3N3b3JkLWFiYw==
Content-Type: application/json
X-Partner-Key: example-key
Content-Length: 167
{
"amount" : 123,
"currency" : "USD",
"playerId" : "example-player-id",
"provider" : "example-provider",
"reason" : "promo_win",
"txId" : "example-tx-id"
}
Field | Type | Description |
---|---|---|
playerId |
String |
Player to whom the transaction relates |
provider |
String |
Game provider for which the request is performed |
reason |
String |
Reason this transaction was committed. Possible values: |
txId |
String |
Unique transaction identifier |
amount |
Long |
Amount of the transaction in the currency’s minor units |
currency |
String |
Currency of this transaction |
Response Example
HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Content-Length: 393
{
"at" : "2023-04-06T11:47:52.859062Z",
"balance" : {
"bonus" : 500,
"locked" : 200,
"main" : 1000
},
"currency" : "USD",
"tx" : {
"at" : "2023-04-06T11:47:52.859062Z",
"id" : "example-tx-id",
"processed" : false,
"processedTxId" : "example-processed-tx-id",
"txAmountDetails" : {
"bonus" : 20,
"locked" : 10,
"main" : 30
}
}
}
Field | Type | Description |
---|---|---|
at |
String |
Timestamp indicating when the transaction was processed ( |
balance |
Object |
Nested object carrying the player’s balance details |
balance.bonus |
Long |
Player’s relevant bonus balance |
balance.locked |
Long |
Player’s relevant locked balance |
balance.main |
Long |
Player’s relevant main balance |
currency |
String |
Player’s currency in |
tx |
Object |
Nested object carrying transaction details |
tx.at |
String |
Timestamp indicating when the transaction was processed ( |
tx.id |
String |
Transaction identifier from the request |
tx.processed |
Boolean |
Identifies whether the transaction had already been processed before this request |
tx.processedTxId |
String |
Transaction identifier on the operator’s side |
tx.txAmountDetails |
Object |
Nested object carrying details about balance changes by this transaction |
tx.txAmountDetails.bonus |
Long |
Amount of money deducted from the bonus balance |
tx.txAmountDetails.locked |
Long |
Amount of money deducted from the locked balance |
tx.txAmountDetails.main |
Long |
Amount of money deducted from the main balance |
4.3.8. Tournament Win Transaction
When a player succeeds in tournaments, the tournamentWin method is called to add funds to the player’s balance.
Request Example
POST /transactions/tournamentWin HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcm5hbWUtYWJjOnBhc3N3b3JkLWFiYw==
Content-Type: application/json
X-Partner-Key: example-key
Content-Length: 212
{
"amount" : 123,
"currency" : "USD",
"playerId" : "example-player-id",
"provider" : "example-provider",
"reason" : "tournament",
"tournamentId" : "example-tournament-id",
"txId" : "example-tx-id"
}
Field | Type | Description |
---|---|---|
playerId |
String |
Player to whom the transaction relates |
provider |
String |
Game provider for which the request is performed |
reason |
String |
Reason this transaction was committed. Possible values: |
tournamentId |
String |
Unique tournament identifier |
txId |
String |
Unique transaction identifier |
amount |
Long |
Amount of the transaction in the currency’s minor units |
currency |
String |
Currency of this transaction |
Response Example
HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Content-Length: 393
{
"at" : "2023-04-06T11:47:52.859062Z",
"balance" : {
"bonus" : 500,
"locked" : 200,
"main" : 1000
},
"currency" : "USD",
"tx" : {
"at" : "2023-04-06T11:47:52.859062Z",
"id" : "example-tx-id",
"processed" : false,
"processedTxId" : "example-processed-tx-id",
"txAmountDetails" : {
"bonus" : 20,
"locked" : 10,
"main" : 30
}
}
}
Field | Type | Description |
---|---|---|
at |
String |
Timestamp indicating when the transaction was processed ( |
balance |
Object |
Nested object carrying the player’s balance details |
balance.bonus |
Long |
Player’s relevant bonus balance |
balance.locked |
Long |
Player’s relevant locked balance |
balance.main |
Long |
Player’s relevant main balance |
currency |
String |
Player’s currency in |
tx |
Object |
Nested object carrying transaction details |
tx.at |
String |
Timestamp indicating when the transaction was processed ( |
tx.id |
String |
Transaction identifier from the request |
tx.processed |
Boolean |
Identifies whether the transaction had already been processed before this request |
tx.processedTxId |
String |
Transaction identifier on the operator’s side |
tx.txAmountDetails |
Object |
Nested object carrying details about balance changes by this transaction |
tx.txAmountDetails.bonus |
Long |
Amount of money deducted from the bonus balance |
tx.txAmountDetails.locked |
Long |
Amount of money deducted from the locked balance |
tx.txAmountDetails.main |
Long |
Amount of money deducted from the main balance |
5. Error Handling
In case any error occurs on the Operator’s side while handling the corresponding request, Eva Platform expects a response indicating the error with such a structure and an appropriate HTTP status:
HTTP/1.1 400 Bad Request
Content-type: application/json; charset=UTF-8
Content-Length: 132
{
"at" : "2023-04-06T11:47:52.859062Z",
"errorCode" : "error.player.session-expired",
"message" : "Session token is expired"
}
Field | Type | Description |
---|---|---|
errorCode |
String |
Error code identifier. A list of error codes is provided in the section below |
message |
String |
Human-readable error message |
at |
String |
Time when the error occurred ( |
5.1. Error Codes
Code | Status code | Description |
---|---|---|
error.player.incorrect-currency |
422 |
Returned when the player’s currency is invalid |
error.player.insufficient-balance |
422 |
Returned when there is not enough balance to perform an action. Applicable for bet call |
error.player.locked |
422 |
Returned when the player has restrictions on the operator’s platform |
error.player.not-found |
422 |
Returned when the player is not found on the operator’s platform |
error.player.session-expired |
422 |
Returned when the session token passed in the request is expired or incorrect. Applicable for playerInfo & bet calls |
error.request.validation-failed |
400 |
Returned when validation of the request body data fails |
error.system.unexpected |
500 |
Returned when an unexpected internal error occurs on the operator’s platform |
error.transaction.casino-logic-validation-failed |
422 |
Returned for unexpected casino game flow (e.g., win without bet, refund for a round with win) |
error.transaction.target-tx-not-found |
422 |
Returned for an unknown transaction. Applicable for refund call |
6. Data API
6.1. Authentication
6.1.1. Overview
To ensure security and control access to the Data API, authorization is performed via the OAuth 2.0 protocol using the "Client Credentials" scheme.
6.1.2. Retrieving token
This method allows client applications to obtain an access token using their credentials (
and client_id
).client_secret
POST /v0/management/token HTTP/1.1
Accept: application/json
Content-Type: application/x-www-form-urlencoded
X-Partner-Key: example-key
grant_type=client_credentials&client_id=client&client_secret=secret
Body Parameter | Description | Type |
---|---|---|
grant_type |
Should be |
String |
client_id |
Credentials provided during integration phase for each partner unit |
String |
client_secret |
Credentials provided during integration phase for each partner unit |
String |
HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Content-Length: 95
{
"access_token": "2YotnFZFEjr1zCsicMWpAA",
"token_type": "Bearer",
"expires_in": 3600
}
After successful authentication you must use the provided token to authorize on the Data API using the following format:
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
6.1.3. Error handling
If an error occurs while attempting to retrieve a new access token, the operator can expect a response indicating the error with such structure:
HTTP/1.1 401 Unauthorized
Content-type: application/json; charset=UTF-8
Content-Length: 86
{
"error" : "unauthorized_client",
"error_description" : "Invalid client secret"
}
If authorization fails when trying to access a secured resource, the operator can expect a response indicating the authorization error with structure described in the OAuth 2.0 protocol
HTTP/1.1 401 Unauthorized
Content-Length: 0
WWW-Authenticate: Bearer error="invalid_token", error_description="Principal isn't resolved.", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"
or
HTTP/1.1 403 Forbidden
Content-Length: 0
WWW-Authenticate: Bearer error="insufficient_scope", error_description="Partner key isn't allowed.", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1", scope="partner_data"
6.2. Game details
6.2.1. Overview
The Data API provides access to game-related data for external operators.
It allows retrieval of game information, filtering by various criteria passed as query parameters
The structure for the final URL is as follows:
https://<eva_target_data_api_url>?page={page}&size={size}&<query_parameters>
where:
-
eva_target_data_api_url is the base URL for the Eva Data API handler.
This will be provided during the integration phase. -
query_parameters are the query parameters for additional filtering.
-
The
page
andsize
query parameters control pagination:-
page
specifies the page number. -
size
determines the number of items per page.
-
The following table describes the query parameters accepted by the API:
Query Parameter | Description | Type | Notes |
---|---|---|---|
size |
Number of records per page |
Integer |
Limited by value configured on Eva Platform side |
page |
Optional |
Integer |
Defaults to |
gameId |
Optional |
String |
Unique game identifier at lobby |
walletId |
Optional |
String |
Game identifier at wallet |
productType |
Optional |
Enum |
Available values: |
translationKey |
Optional |
String |
Game title translation key |
gameProvider |
Optional |
String |
Identifier of the game’s provider |
channel |
Optional |
Enum |
Distribution channel for the game. Available values include |
isFreeSpinsAvailable |
Optional |
Boolean |
Filters games based on the availability of free spins. |
The response includes pagination details and the resulting items, allowing operators to navigate through the data efficiently.
The following table describes the response fields:
Field | Description | Type |
---|---|---|
currentPage |
Integer |
Current page |
totalItems |
Integer |
Total number of items |
totalPages |
Integer |
Total number of pages |
items |
Array of objects |
Carrying game items filtered by query parameters passed |
items[i].gameId |
String |
Unique game identifier at lobby |
items[i].walletId |
String |
Game identifier at wallet |
items[i].productType |
Enum |
Possible values: |
items[i].translationKey |
String |
Game title translation |
items[i].gameProvider |
String |
Game provider identifier |
items[i].channel |
Enum |
Distribution channel for the game. Possible values include |
items[i].dealerLanguage |
Nullable String |
Dealer language |
items[i].imageUrl |
Nullable String |
URL pointing to image file of the game |
items[i].isDemoModeAvailable |
Boolean |
Indicates if demo mode (not using real balance) is available on game launch |
items[i].isFreeSpinsAvailable |
Boolean |
Indicates if free spins are available |
items[i].isActive |
Boolean |
Indicates if the game is active |
6.2.2. Examples
GET /v0/management/games?size=5&page=0&gameId=game-identifier&walletId=wallet-identifier&translationKey=GameName&gameProvider=game-provider&channel=desktop&isFreeSpinsAvailable=false HTTP/1.1
Accept: application/json
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
X-Partner-Key: example
{
"currentPage": 0,
"totalItems": 1,
"totalPages": 1,
"items": [
{
"gameId": "game-identifier",
"walletId": "wallet-identifier",
"productType": "slots",
"translationKey": "GameName",
"gameProvider": "game-provider",
"channel": "desktop",
"dealerLanguage": "UK",
"imageUrl": "https://image-url.com/some/path/image.png",
"isDemoModeAvailable": true,
"isFreeSpinsAvailable": false,
"isActive": true
}
]
}
6.3. Game Images Management
6.3.1. Overview
Default images may not always satisfy all the needs, so the operator can use the methods described below to manage custom images.
6.3.2. Upload Custom Game Image
This method allows you to upload a custom image for a specific game by its ID.
The image will become available globally through its unique URL returned in the response.
The response from the Game details method will also include the new URL for the custom image.
This method overwrites the image only for the specific partner unit. |
PUT /v0/management/games/{gameId}/images HTTP/1.1
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
Content-Type: multipart/form-data; boundary=1234567
X-Partner-Key: example
--1234567
Content-Disposition: form-data; name="image"; filename="image.png"
<image content>
--1234567
Content-Disposition: form-data; name="fileName"
image.png
--1234567--
Where:
-
image is the required part containing the image content itself
-
fileName is the required part containing the image file name, since the
filename
attribute in theContent-Disposition
is optional
HTTP/1.1 200 OK
Content-Length: 45
https://testhost.tech/games/image123.png
6.3.3. Delete Custom Image
This method allows you to delete a custom image for a specific game by its ID.
The response from the Game details method will now revert to the URL for the default image, if available.
The image will no longer be accessible via the previously generated URL. |
DELETE /v0/management/games/{gameId}/images HTTP/1.1
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
X-Partner-Key: example
HTTP/1.1 200 OK
Content-Length: 0
6.4. Free spins
6.4.1. Overview
This section of the API is designed for managing free spin campaigns and bonuses.
It includes endpoints to create campaign, grant bonus to player and cancel bonus.
These operations are crucial for promotional activities in gaming platforms.
All requests to the related free-spin endpoints require authentication.
Consumers must include the following mandatory headers in each request:
-
X-Partner-Key - A unique identifier for the partner.
-
X-Provider-Id - Identifies the game provider.
This ensures that the appropriate provider’s contract is associated with the partner key provided.
Free spin endpoints are idempotent. When a request is made to the free spin endpoint with same parameters (ones acting as idempotent markers), subsequent requests with the exact same parameters are not executed within underlying services. |
6.4.2. Creating campaign
This endpoint is used to create a new free spin campaign.
The campaign details must be specified in the request body.
POST /v0/management/bonuses/free-spins/campaigns HTTP/1.1
Accept: application/json
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
Content-Type: application/json
X-Partner-Key: example
X-Provider-Id: provider
{
"gameId": "provider-game-id",
"campaignId": "campaign-id",
"spins": 10,
"campaignStartDate": "2020-12-03T10:15:30.675220736Z",
"campaignEndDate": "2020-12-04T10:15:30Z",
"spinsExpirationDuration": 68004,
"betAmounts": {
"EUR": 9000,
"USD": 10000
}
}
Property Name | Description | Type | Notes |
---|---|---|---|
gameId |
Game identifier on provider’s side |
String |
Id of the game which the free spin campaign is available for |
campaignId |
Unique identifier of the free spin campaign on the operator’s side |
String |
Unique identifier for the free spin campaign, acting as an idempotent marker |
spins |
Amount of free spins |
Integer |
Number of free spins offered in the campaign for a player |
campaignStartDate |
The timestamp of campaign start date (ISO 8601) |
String |
Timestamp marking the start of the free spin campaign |
campaignEndDate |
The timestamp of campaign end date (ISO 8601) |
String |
Timestamp marking the end of the free spin campaign |
spinsExpirationDuration |
Time in millisecond for free spins |
Long |
Time in milliseconds during which the player can use the free spins from the campaign. |
betAmounts |
Map of currency and amount of bet |
Map<String, Long> |
Specifies the currencies available in the free spin campaign and their corresponding bet amounts in minor units |
{
"campaignId": "campaign-id",
"externalCampaignId": "campaign-id-on-providers-side"
}
Property Name | Description | Type | Notes |
---|---|---|---|
campaignId |
Unique identifier of the free spin campaign on the operator’s side |
String |
The same id as the one provided in the request, serving as confirmation that the campaign has been successfully created |
externalCampaignId |
Unique identifier of the free spin campaign on the provider’s side |
String |
Actual identifier that was used (or was assigned by provider) to create campaign |
6.4.3. Awarding bonus
This endpoint is used to award a free spin bonus to a player.
The details associated with the bonus, related campaign and player identifier must be included in the request body.
POST /v0/management/bonuses/free-spins/grant HTTP/1.1
Accept: application/json
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
Content-Type: application/json
X-Partner-Key: example
X-Provider-Id: provider
{
"campaignId": "campaign-id",
"bonusId": "bonus-id",
"playerId": "player-id",
"spinsExpirationDuration": 68004,
"currency": "USD"
}
Property Name | Description | Type | Notes |
---|---|---|---|
campaignId |
Unique identifier of the free spin campaign on the operator’s side |
String |
Unique identifier of free spin campaign where the game is available for bonuses (part of the idempotent marker) |
bonusId |
Unique identifier of the bonus |
String |
Unique identifier for a player’s bonus within the free spin campaign (part of the idempotent marker) |
playerId |
Player’s identifier |
String |
Unique player’s identifier (part of the idempotent marker) |
spinsExpirationDuration |
Time in millisecond for free spins |
Long |
Time in milliseconds during which the player can use the free spins from the campaign. |
currency |
Free spin’s currency |
String |
The currency available to the player in the free spin campaign |
{
"playerId": "player-id",
"bonusId": "bonus-id",
"externalBonusId": "bonus-id-on-providers-side"
}
Property Name | Description | Type | Notes |
---|---|---|---|
playerId |
Player’s identifier |
String |
This should be the same id as the one provided in the request |
bonusId |
Unique identifier of the bonus |
String |
This should be the same id as the one provided in the request, serving as confirmation that the bonus has been successfully created |
externalBonusId |
Unique identifier of the bonus |
String |
Actual identifier that was used (or was assigned by provider) to award bonus to player |
6.4.4. Cancelling bonus
This endpoint is used to cancel a previously awarded free spin bonus.
The player identifier and bonus details must be specified.
If an attempt is made to cancel not existing bonus, or cancel already cancelled one (idempotent request) - successful response is returned to indicate that player does not have bonus with the id provided |
POST /v0/management/bonuses/free-spins/cancel HTTP/1.1
Accept: application/json
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
Content-Type: application/json
X-Partner-Key: example
X-Provider-Id: provider
{
"campaignId": "campaign-id",
"bonusId": "bonus-id",
"externalBonusId": "bonus-id-on-providers-side",
"playerId": "player-id",
"currency": "USD"
}
Property Name | Description | Type | Notes |
---|---|---|---|
campaignId |
Unique identifier of the free spin campaign on the operator’s side |
String |
Unique identifier of the created free spin campaign (part of the idempotent marker) |
bonusId |
Unique identifier of the bonus |
String |
Unique identifier for a player’s awarded bonus within the free spin campaign (part of the idempotent marker) |
externalBonusId |
Unique identifier of the bonus |
String |
Actual identifier that was used (or was assigned by provider) to award bonus to player |
playerId |
Player’s identifier |
String |
Unique player’s identifier (part of the idempotent marker) |
currency |
Free spin’s currency |
String |
The currency available to the player in the free spin campaign |
{
"playerId": "player-id",
"bonusId": "bonus-id"
}
Property Name | Description | Type | Notes |
---|---|---|---|
playerId |
Player’s identifier |
String |
This should be the same id as the one provided in the request |
bonusId |
Unique identifier of the bonus |
String |
This should be the same id as the one provided in the request, serving as confirmation that the bonus has been successfully cancelled |
6.4.5. Error handling
If any error occurs during request processing - a JSON response describing the nature of the error is sent.
This response includes:
Property Name | Type | Description |
---|---|---|
code |
String |
Error code identifier. |
message |
Text |
A human-readable error message explaining the error |
Below is a list of error codes that can be present in the response:
Code | Message | Description | Status code |
---|---|---|---|
error.app.invalid-request-data |
Additional information about the validation error |
Any validation error encountered during the request processing |
400 |
error.system.cancel-not-supported |
Additional information about the system error |
Error indicating that cancelling is not supported for provider |
422 |
error.system.external-system-error |
Additional information about the system error |
Any error encountered during the request processing on provider’s side |
422 |
error.system.unexpected-error |
Additional information about the system error |
An unexpected error within the system |
500 |
{
"code": "error.app.invalid-request-data",
"message": "gameId: must not be blank"
}
7. FAQ
Why do some methods not provide sessionToken
?
These methods are considered as "offline", because they can be called outside the active game session.
Eg: round reconciliation, delayed payouts
The wallet must be able to process all these transactions if player exists in the 2-nd level cache (at least 7 days after the game session)
What is the purpose of tournamentWin
and promoWin
?
As you may guess, these methods distribute rewards in different tournaments and promo activities.
They are not tied to the concrete game and may be paid with a huge delay after the player’s game session.
This may include: Tournaments, Jackpots, Free Spins, and Free Money on Live casino.
Some features can not be disabled and are supplied as a part of the regular provider’s portfolio, so these methods are mandatory to implement |
What is the purpose of bonus
and locked
balances?
Without regard your wallet supports separate balances or not, the sum of main
+ bonus
+ locked
is displayed inside the game.
Despite that fact, these details are shared with the providers and are used for the statistics.
In this case some providers offer a discount for the bets paid by the bonus money
Why does gameId
in wallet requests and Free Spins API differ from that passed in launch URL ?
During the game launch process is used the unique title identifier.
This allows us to provide you a human-readable, URL-safe identifier without dependency on the provider’s internal logic to be used in your public lobby.
-
Some providers have an internal games lobby, where player can open any title even if it is not configured
-
Some providers have different IDs for the game launch and wallet transactions
-
Some providers have callused IDs, where the gameId is equal between different providers
In case of reverse mapping is required the key is:
providerId
+ walletGameId
= lobbyGameId
How should we implement the idempotency ?
Idempotency is crucial for the proper system functioning.
It helps to avoid any inconsistency during the regular gameplay and in case of system malfunction.
The basic idempotency key includes: playerId
, provider
, gameId
, roundId
, txId
.
It is essential for you to check whether other fields are valid and equal to the ones in the existing transaction.
The wallet must reply with the tx.processed: true
otherwise amount may be added to the invoice twice.
8. Changelog
Version | Date | Change |
---|---|---|
v1.0.0 |
10.04.2023 |
Added documentation for the operator |
v1.0.1 |
24.04.2023 |
Updated error handling description |
v1.0.2 |
05.04.2024 |
Added game launch section |
v1.0.3 |
09.04.2024 |
Added Data API section |
v1.0.4 |
16.04.2024 |
Added Authentication section |
v1.0.5 |
18.04.2024 |
Added Free spins section |
v1.0.6 |
21.04.2024 |
Added Game Images Management section |
v1.0.7 |
22.07.2024 |
Added 'sideSplit' transactions field |
v1.0.8 |
23.07.2024 |
Added 'productType' field to the Data API section |
v1.0.9 |
30.08.2024 |
Added 'Player Session Token by player details' to the Wallet API section |
v1.1.0 |
19.11.2024 |
Added NFR & FAQ sections |
v1.1.1 |
27.03.2025 |
Added Key Concepts & Wallet Responsibility Definition sections |