Game Launch API
Overview
When a player wants to play your game from a casino operator, Groove sends a game launch request to your platform. Your
system must process this request, create a game session, and return a URL where the player will be redirected to play
your game.
Start Game Process Flow
The game launch process follows these steps:
sequenceDiagram
participant Player
participant Casino
participant Groove
participant YourAPI as Your Game Provider API
participant YourGame as Your Game Server
Player->>Casino: Select game to play
Casino->>Groove: Request game launch
Groove->>YourAPI: Forward launch request with player data
YourAPI->>YourAPI: Create game session
YourAPI-->>Groove: Return game URL
Groove-->>Casino: Return redirect URL
Casino->>Player: Redirect to game
Player->>YourGame: Start playing
Process Steps:
- Player selects your game in the casino lobby
- Casino sends game launch request to Groove
- Groove forwards the request to your Game Launch API endpoint
- Your system creates a session and returns the game URL
- Player is redirected to your game server
Start Game Request
Groove will send a game launch request to your platform with player and session information. Your system must process
this request and return a URL where the player can access the game.
- Endpoint:
https://{your_domain}/game/ (or your specified endpoint)
- Method:
GET
- Content-Type: URL encoded parameters
Warning
All parameters sent by Groove will be URL encoded. Your system must decode them properly.
Request Parameters
Required Parameters
| Parameter |
Data Type |
Description |
Example |
accountid |
String(60) [0-9a-zA-Z] |
Account ID |
5179068 |
device_type |
String |
Device currently used by the player |
desktop, mobile |
country |
String |
Country code (ISO 3166-1 alpha-2) |
IL, UK, US |
homeurl |
String(50) |
Page URL that the player is redirected to after exiting the game Note: If empty, the home button should not be displayed in your game (prevents iframe-in-iframe issues) |
http://www.somecasino.com |
is_test_account |
Boolean |
Indicates if the player is a test player (excluded from reports) |
false (regular), true (test) |
license |
String |
Country that has gaming jurisdiction |
Curacao, Malta, UK |
nogscurrency |
String |
Currency code |
EUR, USD, GBP |
nogsgameid |
String |
Groove game ID Note: Can contain letters and special characters |
80102, game_123, slot-abc |
nogslang |
String |
Language code |
en_US |
nogsmode |
String |
Game mode |
demo, real |
nogsoperatorid |
String |
Groove ID for the casino |
11 |
sessionid |
String(64) |
Session ID |
${nogsoperatorid}_99d71938-d598c2es |
Optional Parameters (Reality Check)
| Parameter |
Data Type |
Description |
Example |
exitUrl |
String |
Exit URL |
http://myhomepage.com |
historyUrl |
String(50) |
URL for viewing player’s gaming history (regulatory requirement) |
http://casino.com/history |
rc_url |
String |
Reality check URL |
https://realitycheckapp.groovegaming.com |
realityCheckElapsed |
Integer |
Reality Check Elapsed time in minutes |
10 |
realityCheckInterval |
Integer |
Reality Check Interval in minutes |
15 |
Info
**Note**: Some games are not available on mobile devices. Always specify the `device_type` parameter when known.
Request Example (What You’ll Receive)
GET /game/?accountid=5179068&country=UK&historyUrl=http%3A%2F%2Fcasino.com%2Fhistory&homeurl=http%3A%2F%2Fwww.somecasino.com&is_test_account=false&license=UK&nogscurrency=EUR&nogsgameid=80102&nogslang=en_US&nogsmode=real&nogsoperatorid=11&sessionid=11_99d71938-d598c2es HTTP/1.1
Host: {your_domain}
Processing the Request (Your Implementation)
Your platform must:
- Process the incoming parameters from Groove
- Create a game session in your system
- Store the session information for use in transaction callbacks
- Return a redirect to your game URL (HTTP 302)
**Critical for Transactions**: When making transaction callbacks to Groove, you must use the latest game session for the
combination of:
- `nogsoperatorid` (operator ID)
- `accountid` (player account ID)
- `nogscurrency` (currency)
This ensures Groove can properly identify and process the transaction.
Response (What You Must Return)
Success Response
- Status Code:
302 Found
- Behavior: Your system must redirect to the actual game URL where the player can start playing
- Location Header: Must contain the full URL to your game
Error Response
If you cannot launch the game, return an error response:
{
"errMsg": "general_error"
}
Error Handling
Common error scenarios:
| Error |
Description |
Solution |
general_error |
Generic error occurred |
Check all required parameters are present and valid |
| Missing parameters |
Required parameter not provided |
Ensure all required parameters are included |
| Invalid game ID |
Game ID doesn’t exist |
Verify the nogsgameid is correct |
| Invalid session |
Session has expired or is invalid |
Generate a new session |
Reality Check Feature
For jurisdictions requiring reality check functionality:
- Include
realityCheckInterval - the interval in minutes for reality checks
- Include
realityCheckElapsed - time already elapsed in the current session
- Provide
rc_url - URL for the reality check application
The game will automatically prompt players at the specified intervals.
Implementation Best Practices
- Validate all incoming parameters from Groove before processing
- Store session information securely for later transaction validation
- Implement proper error handling for invalid or expired sessions
- Support both demo and real modes in your game (Account ID / Session ID can be empty for demo mode)
- Handle device detection to serve appropriate game versions
- Maintain session mapping between Groove session IDs and your internal sessions
- Use HTTPS for all endpoints
- Handle empty homeurl - If homeurl is empty, hide the home button in your game UI to prevent iframe-in-iframe
issues
Next Steps
After successfully launching a game, your game will need to communicate with Groove through
the Transaction API for:
- Validating player sessions (GetAccount)
- Retrieving player balances (GetBalance)
- Processing bets (Wager)
- Reporting results (Result)
Continue to Transaction APIs →
Transaction API
Overview
The Transaction API enables your games to communicate with Groove for all wallet and gaming operations. Your game sends
transaction requests to Groove, which then handles the actual wallet operations with the casino operators.
This standardized API allows your games to work with any casino operator connected to Groove without needing individual
integrations.
Transaction Flow
When a player starts your game:
- Your game calls Groove’s GetAccount endpoint to validate the session
- Your game calls Groove’s GetBalance to retrieve the player’s current balance
- During gameplay, your game sends Wager requests to Groove when players bet
- Your game sends Result requests to report wins or losses
- If needed, your game can send Rollback requests to correct transactions
API Configuration
- Groove Transaction Endpoint:
{GrooveEndpoint}/groove (Groove will provide this)
- Request Method:
GET
- Response Format: JSON
- Authentication: HMAC-SHA256 signature in Authorization header (
see Signature Validation)
Transaction Sequence Diagram
sequenceDiagram
participant YourGame as Your Game
participant Groove
participant Casino
participant Wallet as Casino Wallet
Note over YourGame,Wallet: Session Validation
YourGame->>Groove: GetAccount Request
Groove->>Casino: Validate Session
Casino-->>Groove: Player Details
Groove-->>YourGame: Account Validated
Note over YourGame,Wallet: Balance Check
YourGame->>Groove: GetBalance Request
Groove->>Wallet: Get Balance
Wallet-->>Groove: Current Balance
Groove-->>YourGame: Balance Response
Note over YourGame,Wallet: Bet Processing
YourGame->>Groove: Wager Request
Groove->>Wallet: Deduct Bet
Wallet-->>Groove: Updated Balance
Groove-->>YourGame: Wager Confirmed
Note over YourGame,Wallet: Win Processing
YourGame->>Groove: Result Request
Groove->>Wallet: Credit Win
Wallet-->>Groove: Updated Balance
Groove-->>YourGame: Result Confirmed
Transaction Types
Authentication & Session Management (Your Game → Groove)
- GetAccount - Validate player session and get player details
- GetBalance - Retrieve current player balance
Core Gaming Transactions (Your Game → Groove)
- Wager - Process a bet when player places a wager
- Result - Report the outcome of a game round
- Wager and Result - Process bet and result in a single transaction
Correction & Special Transactions (Your Game → Groove)
- Rollback - Cancel or reverse a previous transaction
- Jackpot - Report a jackpot win to Groove
Security (Groove → Your Game)
Implementation Requirements for Your Game
Making Requests to Groove
- All requests from your game to Groove use GET method with URL parameters
- Session ID from game launch must be included in all transactions
- Transaction IDs must be unique for each transaction
- Handle timeouts appropriately (recommended 30 second timeout)
Handling Groove Responses
- Check response codes - 200 means success, others indicate errors
- Store transaction IDs for potential rollback scenarios
- Retry logic should respect idempotency (use same transaction ID)
- Balance updates should be reflected in your game UI immediately
Balance Management
For CMA-compliant games, additional fields are required:
game_mode: Combined real and bonus modes (1 = Real, 2 = Bonus)
order: Type of order (cash_money, bonus_money)
- Separate tracking of
real_balance and bonus_balance
Error Handling
Standard Response Structure
{
"code": 200,
"status": "Success",
"apiversion": "1.2",
// Additional fields based on transaction type
}
Error Response Structure
{
"code": 1,
"status": "Technical error",
"message": "Technical error",
"apiversion": "1.2"
}
Common Error Codes
| Code |
Status |
Description |
| 200 |
Success |
Transaction processed successfully |
| 1 |
Technical error |
Generic technical error |
| 102 |
Wager not found |
Wager transaction not found |
| 110 |
Operation not allowed |
Operation cannot be performed |
| 400 |
Transaction parameter mismatch |
Essential fields mismatch |
| 409 |
Round closed or transaction ID exists |
Round already closed |
| 1000 |
Not logged on |
Session invalid (not for result/rollback) |
| 1006 |
Out of money |
Insufficient funds |
| 1019 |
Gaming limit |
Loss or bet limit exceeded |
| 1035 |
Account blocked |
Player account is blocked |
Best Practices for Game Providers
- Session Management: Store the Groove session ID from game launch and use it for all transactions
- Unique Transaction IDs: Generate unique IDs for each wager and result to enable proper tracking
- Error Handling: Implement comprehensive error handling for all Groove responses
- Balance Synchronization: Always update your game UI based on balance returned by Groove
- Logging: Maintain detailed logs of all transactions for debugging and reconciliation
- Timeout Handling: Implement appropriate timeouts and retry logic
- Currency Precision: Always use decimal format with maximum of two decimal places
Security Considerations
- Implement HMAC-SHA256 signature validation for all incoming requests (
see Signature Validation)
- Use HTTPS for all communications
- Validate session tokens properly
- Implement rate limiting to prevent abuse
- Log all transactions for audit purposes
- Store Access Keys securely (never in code)
Integration Steps for Your Game
- Implement session validation - Call GetAccount when game loads
- Add balance retrieval - Call GetBalance to show player’s funds
- Process bets - Send Wager requests when players place bets
- Report results - Send Result requests after each game round
- Handle corrections - Implement Rollback for error scenarios
- Support jackpots - Send Jackpot requests for special wins
Continue to GetAccount API →
Subsections of Transaction API
GetAccount
GetAccount
Returns player details, such as unique ID, currency, and language.
The casino platform must confirm the validity of incoming game sessions and account IDs and return the user data
relevant for the session. If a retry or rollback request is sent regarding a request that the casino already responded
to, the account ID that is returned must be unique per player, and identical.
Request Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accountid |
String(60) [0-9a-zA-Z] |
Required |
Account ID Example: 5179068 |
apiversion |
String |
Required |
The API version that will be used Example: 1.2 |
device |
String |
Required |
The device currently used by the player Valid values: desktop or mobile |
gamesessionid |
String(64) |
Required |
The game session id from the start game Example: 11_99d71938-c2d9-4844-b950-d598c2es |
request |
String |
Required |
Request method name Example: getaccount |
Request Example
/groove?request=getaccount&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&apiversion=1.2
Response Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accountid |
String |
Required |
Account ID generated by the casino Example: 5179068 |
apiversion |
String |
Required |
The version of the API being used Example: 1.2 |
bonus_balance |
Decimal (32,10) |
Optional |
The player’s bonus balance Example: 50.0 |
city |
String(32) |
Required |
The city where the player logged in Examples: London, Tel Aviv |
code |
Integer |
Required |
Response code (See Appendix) Example: 200 |
country |
String |
Required |
Country code (ISO 3166-1 alpha-2) Examples: IL, UK, US |
currency |
String |
Required |
Currency code (ISO) Example: EUR |
game_mode |
Integer |
Optional* |
Combined real and bonus modes 1 = Real mode 2 = Bonus mode *Required for CMA-compliant games |
gamesessionid |
String(64) |
Required |
The ID for the game session Example: 11_99d71938-c2d9-4844-b950-d598c2es |
order |
String |
Optional* |
The type of order Valid values: cash_money, bonus_money *Required for CMA-compliant games |
real_balance |
Decimal (32,10) |
Required |
The player’s real balance Example: 100.0 |
status |
String |
Required |
The status of the response Example: Success |
Info
For Fugaso GP, the following cryptocurrencies are available: BTC, LTC, DOG, ETH, BCH
Response Example
Success Response
{
"code": 200,
"status": "Success",
"accountid": 8877,
"city": "aaa",
"country": "IL",
"currency": "EUR",
"gamesessionid": "aaaaa",
"real_balance": 100,
"bonus_balance": 50,
"game_mode": 1,
"order": "cash_money, bonus_money",
"apiversion": "1.2"
}
Error Codes
| Code |
Status |
Message |
| 1 |
Technical error |
Technical error |
| 1000 |
Not logged on |
Not logged on |
| 1003 |
Authentication failed |
Authentication failed |
GetBalance
GetBalance
Returns the current balance in the specific player account.
The casino platform must confirm the validity of the incoming game session ID and that it is connected to the given
account ID. The casino platform must also return the player’s current balance, both the bonus balance and the real
balance.
Request Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accountid |
String(60) [0-9a-zA-Z] |
Required |
Account ID Example: 5179068 |
apiversion |
String |
Required |
The API version that will be used Example: 1.2 |
device |
String |
Required |
The device currently used by the player Valid values: desktop or mobile |
gamesessionid |
String(64) |
Required |
The game session id from the start game Example: 11_99d71938-c2d9-4844-b950-d598c2es |
nogsgameid |
String |
Required |
Groove game ID Note: Can contain letters and special characters Example: 80102, game_123, slot-abc |
request |
String |
Required |
Request method name Example: getbalance |
Request Example
/groove?request=getbalance&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&nogsgameid=80102&apiversion=1.2
Response Parameters
| Parameter |
Data Type |
Mandatory |
Description |
apiversion |
String |
Required |
The version of the API being used Example: 1.2 |
balance |
Decimal (32,10) |
Required |
The total balance amount (real + bonus) Examples: 500, 140.25 |
bonus_balance |
Decimal (32,10) |
Optional |
The player’s bonus balance Example: 50.0 |
code |
Integer |
Required |
Response code Example: 200 |
game_mode |
Integer |
Optional* |
Combined real and bonus modes 1 = Real mode 2 = Bonus mode *Required for CMA-compliant games |
order |
String |
Optional* |
The type of order Valid values: cash_money, bonus_money *Required for CMA-compliant games |
real_balance |
Decimal (32,10) |
Required |
The player’s real balance Example: 100.0 |
status |
String |
Required |
The status of the response Example: Success |
Response Examples
Success Response
{
"code": 200,
"status": "Success",
"balance": 100,
"bonus_balance": 50,
"real_balance": 50,
"game_mode": 1,
"order": "cash_money, bonus_money",
"apiversion": "1.2"
}
Error Response
{
"code": 1,
"status": "Technical error",
"message": "Technical error",
"apiversion": "1.2"
}
Error Codes
| Code |
Status |
Message |
| 1 |
Technical error |
Technical error |
Wager
Wager
The Wager method wagers, or bets, for a player and updates the player’s wallet balance on the casino’s platform.
Idempotency must be provided.
The casino platform must:
- Confirm that the incoming game session ID is valid and is connected with the given account ID. If this validation
fails, refuse the wager.
- Check that the transaction can be approved. Checks should include:
- Sufficient funds are available
- The player is within responsible gaming limits
- Determine whether the transactions have already been processed or not
- Check if a request with the same transactionid has been performed before:
- If any of the essential fields transactionid, accountid, or betamount mismatch, the error Transaction parameter
mismatch is returned
- If there are no mismatches, the original response with the status 200 Success - duplicate request is returned.
The only values that may change are the balance related parameters, since the player’s balance may have changed
- In order to handle future Result and Rollback calls, you must store the following parameters:
gamesessionid,
accountid, roundid, transactionid and betamount
Request Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accountid |
String(60) [0-9a-zA-Z] |
Required |
Account ID Example: 5179068 |
apiversion |
String |
Required |
The API version that will be used Example: 1.2 |
betamount |
Decimal (32,10) |
Required |
The wager amount (total of real and bonus money) Note: Must be 0 for free round transactions when frbid is provided Examples: 2, 0.4, 0.01 (regular), 0 (free rounds) |
device |
String |
Required |
The device currently used by the player Valid values: desktop, mobile |
frbid |
String(255) |
Optional* |
Free Round Bonus ID - Must be the templateId from FRB assign response *Required for free round transactions Example: 123abc456 (the templateId from assign response) |
gameid |
String |
Required |
Groove game ID Note: Can contain letters and special characters Example: 80102, game_123, slot-abc |
gamesessionid |
String(64) |
Required |
The game session id from the start game Example: 11_99d71938-c2d9-4844-b950-d598c2es |
request |
String |
Required |
Request method name Example: wager |
roundid |
String(255) |
Required |
Round ID Example: 802d1812c32686748f2afbcacfcc82114cf |
transactionid |
String(255) |
Required |
Transaction ID Example: 7617edd0924c11e7abb2865556898ad0 |
Request Examples
Regular Wager (No Free Rounds)
/groove?request=wager&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&gameid=80102&apiversion=1.2&betamount=10.0&roundid=nc8n4nd87&transactionid=trx_id
Free Round Wager
/groove?request=wager&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&gameid=80102&apiversion=1.2&betamount=0&roundid=nc8n4nd87&transactionid=trx_id&frbid=123abc456
**Free Round Transactions:**
- `betamount` must be `0` when using free rounds
- `frbid` must be the `templateId` from the FRB assign response
- The same template can be assigned multiple times to the same player
Response Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accounttransactionid |
String(50) |
Required |
The casino’s internal transaction ID Example: 7617edd0924c11e7abb2865556898ad0 |
apiversion |
String |
Required |
The version of the API being used Example: 1.2 |
balance |
Decimal (32,10) |
Required |
The total balance amount after the wager Examples: 500, 140.25 |
bonus_balance |
Decimal (32,10) |
Optional |
The player’s bonus balance Example: 50.0 |
bonusmoneybet |
Decimal (32,10) |
Required |
The bonus amount used in the bet If casino doesn’t work with bonuses, value must be 0 |
code |
Integer |
Required |
Response code Example: 200 |
game_mode |
Integer |
Optional* |
Combined real and bonus modes 1 = Real mode 2 = Bonus mode *Required for CMA-compliant games |
order |
String |
Optional* |
The type of order Valid values: cash_money, bonus_money *Required for CMA-compliant games |
real_balance |
Decimal (32,10) |
Required |
The player’s real balance Example: 100.0 |
realmoneybet |
Decimal (32,10) |
Required |
The real money amount used in the bet |
status |
String |
Required |
The status of the response Example: Success |
Warning
The sum of `bonusmoneybet` and `realmoneybet` must equal the `betamount` sent by the provider.
Response Example
Success Response
{
"code": 200,
"status": "Success",
"accounttransactionid": "aaaaaaa",
"balance": 100,
"bonusmoneybet": 0,
"realmoneybet": 10,
"bonus_balance": 50,
"real_balance": 50,
"game_mode": 1,
"order": "cash_money, bonus_money",
"apiversion": "1.2"
}
Error Codes
| Code |
Status |
Message |
| 1 |
Technical error |
Technical error |
| 110 |
Operation not allowed |
Reasons include: • Wager amount is less than 0 • User with specified accountId not found • AccountId doesn’t match sessionId |
| 400 |
Transaction operator mismatch |
Transaction operator mismatch |
| 409 |
Round closed or transaction ID exists |
Round closed or transaction ID exists |
| 1000 |
Not logged on |
Not logged on |
| 1006 |
Out of money |
Out of money |
| 1019 |
Gaming limit |
Loss limit exceeded or Overall bet limit exceeded |
| 1035 |
Account blocked |
Account blocked |
Result
Result
The game server uses this method to inform that the wager round is complete. The result 0 indicates that the player
lost. Idempotency must be provided.
Info
**Note:**
- Result requests may be received after the player goes offline
- Result requests may be received without a prior wager request for FRB (free round bonus) and tournament auto-payout
- For FRB results without a prior wager, the result represents the win from the free round
The casino platform must:
- Confirm that the incoming game session ID is valid and is connected with the given account ID
- Check if a request with the same transactionid has been performed before:
- If any of the essential fields transactionid, accountid, or betamount mismatch, the error Transaction parameter
mismatch is returned
- If there are no mismatches, the original response with the status 200 Success - duplicate request is returned.
The only values that may change are the balance related parameters, since the player’s balance may have changed
- Confirm that the incoming accountid and roundid match up with a previously placed wager. If this confirmation fails,
refuse the result
- A result must be accepted even if the game session has expired, since a result can be reported by the game server
later. Groove provides the game session for you as information in this call
- The only expected return code for a valid result call is success. All other return codes are unexpected and will
result in the result attempt being resent. Return code 1000 Not logged on is never a valid response to a result
call. The casino platform must accept the result even if the session has expired
Request Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accountid |
String(60) [0-9a-zA-Z] |
Required |
Account ID Example: 5179068 |
apiversion |
String |
Required |
The API version that will be used Example: 1.2 |
device |
String |
Required |
The device currently used by the player Valid values: desktop, mobile |
frbid |
String(255) |
Optional* |
Free Round Bonus ID - Must be the templateId from FRB assign response *Required for free round result transactions Example: 123abc456 (the templateId from assign response) |
gameid |
String |
Required |
Groove game ID Note: Can contain letters and special characters Example: 80102, game_123, slot-abc |
gamesessionid |
String(64) |
Required |
The game session id from the start game Example: 11_99d71938-c2d9-4844-b950-d598c2es |
gamestatus |
String |
Required |
Game Status Valid values: completed, pending |
request |
String |
Required |
Request method name Example: result |
result |
Decimal (32,10) |
Required |
The amount of money won by the player If player did not win, value must be 0 Example: 2.25 |
roundid |
String(255) |
Required |
Round ID Example: 802d1812c32686748f2afbcacfcc82114cf |
transactionid |
String(255) |
Required |
Transaction ID Example: 7617edd0924c11e7abb2865556898ad0 |
Request Examples
Regular Result (After Wager)
/groove?request=result&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&gameid=80102&apiversion=1.2&result=10.0&roundid=nc8n4nd87&transactionid=trx_id&gamestatus=completed
Free Round Result (No Prior Wager)
/groove?request=result&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&gameid=80102&apiversion=1.2&result=10.0&roundid=nc8n4nd87&transactionid=trx_id&gamestatus=completed&frbid=123abc456
**Free Round Result without Wager:**
- Can be sent without a prior wager request
- Must include `frbid` (the templateId from assign response)
- The `result` amount represents the total win from the free round
Response Parameters
| Parameter |
Data Type |
Mandatory |
Description |
apiversion |
String |
Required |
The version of the API being used Example: 1.2 |
balance |
Decimal (32,10) |
Required |
The total balance amount after the result Examples: 500, 140.25 |
bonus_balance |
Decimal (32,10) |
Optional |
The player’s bonus balance Example: 50.0 |
bonusWin |
Decimal (32,10) |
Required |
The bonus amount won If casino doesn’t work with bonuses, value must be 0 |
code |
Integer |
Required |
Response code Example: 200 |
game_mode |
Integer |
Optional* |
Combined real and bonus modes 1 = Real mode 2 = Bonus mode *Required for CMA-compliant games |
order |
String |
Optional* |
The type of order Valid values: cash_money, bonus_money *Required for CMA-compliant games |
real_balance |
Decimal (32,10) |
Required |
The player’s real balance Example: 100.0 |
realMoneyWin |
Decimal (32,10) |
Required |
The real money amount won |
status |
String |
Required |
The status of the response Example: Success |
walletTx |
String(50) |
Required |
The wallet transaction ID Example: de73550e-0612-4a1b-8a0d-a5a3745b |
Warning
The sum of `bonusWin` and `realMoneyWin` must equal the `result` amount sent by the provider.
Response Example
Success Response
{
"code": 200,
"status": "Success",
"walletTx": "aaaaaaa",
"balance": 100,
"bonusWin": 0,
"realMoneyWin": 10,
"bonus_balance": 50,
"real_balance": 50,
"game_mode": 1,
"order": "cash_money, bonus_money",
"apiversion": "1.2"
}
Error Codes
| Code |
Status |
Message |
| 1 |
Technical error |
Technical error |
| 110 |
Operation not allowed |
Reasons include: • Result amount is less than 0 • User with specified accountId not found • AccountId doesn’t match sessionId • Game status is not pending or completed |
| 400 |
Transaction operator mismatch |
Transaction operator mismatch |
| 409 |
Round closed or transaction ID exists |
Round closed or transaction ID exists |
| 1000 |
Not logged on |
Not logged on |
Rollback
Rollback
This method either rolls back a wager or a wager that did not result in a result. For example, if a player places a
wager and the Result request fails, you can send a Rollback request to roll back the original wager.
The casino platform must confirm that the incoming accountid, roundid, and transactionid are identical to the latest
wager in the game round and not included in a result that has been issued for the relevant game round.
The casino platform may, but is not required to, verify that the bet amount in the relevant wager request is identical
to the rollback amount.
Info
**Note:** The rollback amount is not mandatory and can be null.
The casino platform must refuse the rollback if any of these assertions fail.
- Check if a request with the same transactionid has been performed before:
- If any of the essential fields transactionid, accountid, or betamount mismatch, the error Transaction parameter
mismatch is returned
- If there are no mismatches, the original response with the status 200 Success - duplicate request is returned.
The only values that may change are the balance related parameters, since the player’s balance may have changed
- A rollback can be issued by the game server later. Therefore, a rollback must be accepted even if the game session has
expired. Groove provides the game session for you as information in this call
- The only expected return code for a valid rollback call is 0 success
- If no matching wager is found, the code 102 Wager not found is returned
- If the rollback is incorrect, code 110 Operation not allowed is returned
- Return code 1000 Not logged on is never a valid response to a rollback call. The casino platform must accept the
rollback even if the session has expired
- All other return codes result in a resending of the rollback attempt
- The Casino must refund the player only if a successful wager was found. Do not refund the player in the case of a
failed wager or any other error
Request Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accountid |
String(60) [0-9a-zA-Z] |
Required |
Account ID Example: 5179068 |
apiversion |
String |
Required |
The API version that will be used Example: 1.2 |
device |
String |
Required |
The device currently used by the player Valid values: desktop, mobile |
gameid |
String |
Required |
Groove game ID Note: Can contain letters and special characters Example: 80102, game_123, slot-abc |
gamesessionid |
String(64) |
Required |
The game session id from the start game Example: 11_99d71938-c2d9-4844-b950-d598c2es |
request |
String |
Required |
Request method name Example: rollback |
rollbackamount |
Decimal (32,10) |
Optional |
The betamount in the Wager request that you want to rollback Example: 0.10 In some cases rollback amount can be 0, then rollback amount should be taken from original wager |
roundid |
String(255) |
Optional |
Each casino needs to handle the rollback by transactionId, although sometimes the roundId is sent as well Example: 802d1812c32686748f2afbcacfcc82114cf |
transactionid |
String(255) |
Required |
Transaction ID (Original Wager Transaction ID) Example: 7617edd0924c11e7abb2865556898ad0 |
Request Example
/groove?request=rollback&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&gameid=80102&apiversion=1.2&rollbackamount=10.0&roundid=nc8n4nd87&transactionid=trx_id
Response Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accounttransactionid |
String(50) |
Required |
The casino’s internal transaction ID Example: 7617edd0924c11e7abb2865556898ad0 |
apiversion |
String |
Required |
The version of the API being used Example: 1.2 |
balance |
Decimal (32,10) |
Required |
The total balance amount after the rollback Examples: 500, 140.25 |
bonus_balance |
Decimal (32,10) |
Optional |
The player’s bonus balance Example: 50.0 |
code |
Integer |
Required |
Response code Example: 200 |
game_mode |
Integer |
Optional* |
Combined real and bonus modes 1 = Real mode 2 = Bonus mode *Required for CMA-compliant games |
order |
String |
Optional* |
The type of order Valid values: cash_money, bonus_money *Required for CMA-compliant games |
real_balance |
Decimal (32,10) |
Required |
The player’s real balance Example: 100.0 |
status |
String |
Required |
The status of the response Example: Success |
Response Example
Success Response
{
"code": 200,
"status": "Success",
"accounttransactionid": "aaaaaaa",
"balance": 100,
"bonus_balance": 50,
"real_balance": 50,
"game_mode": 1,
"order": "cash_money, bonus_money",
"apiversion": "1.2"
}
Error Codes
| Code |
Status |
Description |
| 1 |
Technical error |
Technical error |
| 102 |
Wager not found |
Reasons include: • A wager with the given transactionId is not found • The roundId in the rollback request is not the same as the roundId of a wager with the specified transactionId |
| 110 |
Operation not allowed |
Reasons include: • A win request was already received for the given wager |
Wager And Result
Wager And Result
Places a wager and sets the result amount at the same time. Idempotency must be provided, which means equal requests
should only be processed once. If a request is duplicated, that is, the requests have the same transactionid, the
original response must be sent with the status 200, Success - duplicate request status.
The same as in the separate Wager and Result requests.
Request Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accountid |
String(60) [0-9a-zA-Z] |
Required |
Account ID Example: 5179068 |
apiversion |
String |
Required |
The API version that will be used Example: 1.2 |
betamount |
Decimal (32,10) |
Required |
The wager amount (total of real and bonus money) Note: Must be 0 for free round transactions when frbid is provided Examples: 2, 0.4, 0.01 (regular), 0 (free rounds) |
device |
String |
Required |
The device currently used by the player Valid values: desktop, mobile |
frbid |
String |
Optional* |
Free Round Bonus ID - Must be the templateId from FRB assign response *Required for free round transactions Example: 123abc456 (the templateId from assign response) Note: The FRB result can be sent without a separate wager |
gameid |
String |
Required |
Groove game ID Note: Can contain letters and special characters Example: 80102, game_123, slot-abc |
gamesessionid |
String(64) |
Required |
The game session id from the start game Example: 11_99d71938-c2d9-4844-b950-d598c2es |
gamestatus |
String |
Required |
Game Status Valid values: completed, pending |
request |
String |
Required |
Request method name Example: wagerAndResult |
result |
Decimal (32,10) |
Required |
The amount of money won by the player Example: 2.25 |
roundid |
String(255) |
Required |
Round ID Example: 802d1812c32686748f2afbcacfcc82114cf |
transactionid |
String(255) |
Required |
Transaction ID Example: 7617edd0924c11e7abb2865556898ad0 |
Request Examples
Regular Wager and Result (No Free Rounds)
/groove?request=wagerAndResult&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&gameid=80102&apiversion=1.2&result=10.0&betamount=5.0&roundid=nc8n4nd87&transactionid=trx_id&gamestatus=completed
Free Round Wager and Result
/groove?request=wagerAndResult&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&gameid=80102&apiversion=1.2&result=10.0&betamount=0&roundid=nc8n4nd87&transactionid=trx_id&gamestatus=completed&frbid=123abc456
**Free Round Transactions:**
- `betamount` must be `0` when using free rounds
- `frbid` must be the `templateId` from the FRB assign response
- The `result` amount represents the win from the free round
Response Parameters
| Parameter |
Data Type |
Mandatory |
Description |
apiversion |
String |
Required |
The version of the API being used Example: 1.2 |
balance |
Decimal (32,10) |
Required |
The total balance amount after the transaction Examples: 500, 140.25 |
bonus_balance |
Decimal (32,10) |
Optional |
The player’s bonus balance Example: 50.0 |
bonusmoneybet |
Decimal (32,10) |
Required |
The bonus amount used in the bet If casino doesn’t work with bonuses, value must be 0 |
bonusWin |
Decimal (32,10) |
Required |
The bonus amount won If casino doesn’t work with bonuses, value must be 0 |
code |
Integer |
Required |
Response code Example: 200 |
game_mode |
Integer |
Optional* |
Combined real and bonus modes 1 = Real mode 2 = Bonus mode *Required for CMA-compliant games |
order |
String |
Optional* |
The type of order Valid values: cash_money, bonus_money *Required for CMA-compliant games |
real_balance |
Decimal (32,10) |
Required |
The player’s real balance Example: 100.0 |
realmoneybet |
Decimal (32,10) |
Required |
The real money amount used in the bet |
realmoneyWin |
Decimal (32,10) |
Required |
The real money amount won |
status |
String |
Required |
The status of the response Example: Success |
walletTx |
String(50) |
Required |
The wallet transaction ID Example: de73550e-0612-4a1b-8a0d-a5a3745b |
Warning
- The sum of `bonusmoneybet` and `realmoneybet` must equal the `betamount` sent by the provider
- The sum of `bonusWin` and `realmoneyWin` must equal the `result` amount sent by the provider
Response Example
Success Response
{
"code": 200,
"status": "Success",
"walletTx": "aaaaaaa",
"balance": 100,
"bonusWin": 0,
"realmoneyWin": 0,
"bonusmoneybet": 0,
"realmoneybet": 5,
"bonus_balance": 50,
"real_balance": 50,
"game_mode": 1,
"order": "cash_money, bonus_money",
"apiversion": "1.2"
}
Error Codes
The error codes are the same that are used in separate Wager and Result requests.
Jackpot
Jackpot
Groove Gaming sends this request as a Result call when the player wins a jackpot. Idempotency must be provided, which
means the same request should only be processed once. If a request is duplicated, the original response must be sent
with status 200, Success - duplicate request status.
Request Parameters
| Parameter |
Data Type |
Mandatory |
Description |
accountid |
String(60) [0-9a-zA-Z] |
Required |
Account ID Example: 5179068 |
winAmount |
Decimal (32,10) |
Required |
The jackpot win amount Example: 2000 |
apiversion |
String |
Required |
The API version that will be used Example: 1.2 |
gameid |
String |
Required |
Groove game ID Note: Can contain letters and special characters Example: 80102, game_123, slot-abc |
gamesessionid |
String(64) |
Required |
The game session id from the start game Example: 11_99d71938-c2d9-4844-b950-d598c2es |
gamestatus |
String |
Required |
Game Status Valid values: completed, pending |
request |
String |
Required |
Request method name Example: jackpot |
roundid |
String(255) |
Required |
Round ID Example: 802d1812c32686748f2afbcacfcc82114cf |
transactionid |
String(255) |
Required |
Transaction ID Example: 7617edd0924c11e7abb2865556898ad0 |
Request Example
/groove?request=jackpot&gamesessionid=123_jdhdujdk&accountid=111&device=desktop&gameid=80102&apiversion=1.2&winAmount=2000.0&roundid=nc8n4nd87&transactionid=trx_id&gamestatus=completed
Response Parameters
| Parameter |
Data Type |
Mandatory |
Description |
apiversion |
String |
Required |
The version of the API being used Example: 1.2 |
balance |
Decimal (32,10) |
Required |
The total balance amount after the jackpot Examples: 500, 140.25 |
bonus_balance |
Decimal (32,10) |
Optional |
The player’s bonus balance Example: 50.0 |
bonusWin |
Decimal (32,10) |
Required |
The bonus amount won from jackpot If casino doesn’t work with bonuses, value must be 0 |
code |
Integer |
Required |
Response code Example: 200 |
game_mode |
Integer |
Optional* |
Combined real and bonus modes 1 = Real mode 2 = Bonus mode *Required for CMA-compliant games |
order |
String |
Optional* |
The type of order Valid values: cash_money, bonus_money *Required for CMA-compliant games |
real_balance |
Decimal (32,10) |
Required |
The player’s real balance Example: 100.0 |
realmoneyWin |
Decimal (32,10) |
Required |
The real money amount won from jackpot |
status |
String |
Required |
The status of the response Example: Success |
walletTx |
String(50) |
Required |
The wallet transaction ID Example: de73550e-0612-4a1b-8a0d-a5a3745b |
Warning
The sum of `bonusWin` and `realmoneyWin` must equal the `amount` sent by the provider.
Response Example
Success Response
{
"code": 200,
"status": "Success",
"walletTx": "aaaaaaa",
"balance": 2100,
"bonusWin": 0,
"realMoneyWin": 2000,
"bonus_balance": 50,
"real_balance": 2050,
"game_mode": 1,
"order": "cash_money, bonus_money",
"apiversion": "1.2"
}
Error Codes
| Code |
Status |
Message |
| 1 |
Technical error |
Technical error |
| 110 |
Operation not allowed |
Reasons include: • The result amount is less than 0 • A user with the specified accountId cannot be found • Game status is not pending or completed |
| 400 |
Transaction operator mismatch |
Transaction operator mismatch |
Signature Validation
Signature Validation
Overview
For enhanced security, Groove can sign transaction API requests using HMAC-SHA256. Your platform should validate these
signatures to ensure requests are authentic and haven’t been tampered with.
Prerequisites
Before validating signatures, you’ll need:
- Access Key Value: Provided by Groove during integration setup
- Secret: Base64 decoded version of the Access Key Value
Secret = base64_decode(<Access Key Value>)
Note: The Access Key is a pseudo-random HS512 secret provided by Groove.
Each signed request from Groove includes an Authorization header with the following format:
Authorization: HMAC-SHA256 Signature={Signature}
| Component |
Description |
Required |
HMAC-SHA256 |
Authorization scheme |
Optional (but recommended to verify) |
Signature |
Base64 encoded HMAC-SHA256 hash |
Required |
Signature Calculation
The signature is calculated using:
Signature = base64_encode(HMACSHA256(Path-And-Query, Secret))
Where:
- Path-And-Query: The canonical representation of the request path and query string
- Secret: The base64 decoded Access Key Value
The Path-And-Query is the concatenation of:
- The request’s absolute URI path
- The query string (including the
?)
Example
For a request to:
https://your-domain.com/groove?request=getbalance&gamesessionid=123&accountid=456
The Path-And-Query would be:
/groove?request=getbalance&gamesessionid=123&accountid=456
Implementation Example
PHP Implementation
function validateGrooveSignature($request, $accessKeyValue) {
// Get the Authorization header
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
// Extract signature from header
if (!preg_match('/HMAC-SHA256\s+Signature=(.+)/', $authHeader, $matches)) {
return false;
}
$providedSignature = $matches[1];
// Decode the secret
$secret = base64_decode($accessKeyValue);
// Build Path-And-Query
$pathAndQuery = $_SERVER['REQUEST_URI'];
// Calculate expected signature
$hash = hash_hmac('sha256', $pathAndQuery, $secret, true);
$expectedSignature = base64_encode($hash);
// Compare signatures (constant-time comparison)
return hash_equals($expectedSignature, $providedSignature);
}
// Usage
$accessKeyValue = "your_base64_access_key_from_groove";
if (validateGrooveSignature($_REQUEST, $accessKeyValue)) {
// Process the valid request
processTransaction();
} else {
// Reject invalid signature
http_response_code(401);
echo json_encode([
"code" => 401,
"status" => "Unauthorized",
"message" => "Invalid signature"
]);
}
Node.js Implementation
const crypto = require('crypto');
function validateGrooveSignature(req, accessKeyValue) {
// Get the Authorization header
const authHeader = req.headers['authorization'] || '';
// Extract signature from header
const match = authHeader.match(/HMAC-SHA256\s+Signature=(.+)/);
if (!match) {
return false;
}
const providedSignature = match[1];
// Decode the secret
const secret = Buffer.from(accessKeyValue, 'base64');
// Build Path-And-Query
const pathAndQuery = req.originalUrl;
// Calculate expected signature
const hash = crypto
.createHmac('sha256', secret)
.update(pathAndQuery)
.digest('base64');
// Compare signatures (constant-time comparison)
return crypto.timingSafeEqual(
Buffer.from(hash),
Buffer.from(providedSignature)
);
}
// Usage in Express.js
app.get('/groove', (req, res) => {
const accessKeyValue = process.env.GROOVE_ACCESS_KEY;
if (!validateGrooveSignature(req, accessKeyValue)) {
return res.status(401).json({
code: 401,
status: "Unauthorized",
message: "Invalid signature"
});
}
// Process valid request
processTransaction(req, res);
});
Python Implementation
import hmac
import hashlib
import base64
from flask import request, jsonify
def validate_groove_signature(access_key_value):
# Get the Authorization header
auth_header = request.headers.get('Authorization', '')
# Extract signature from header
import re
match = re.search(r'HMAC-SHA256\s+Signature=(.+)', auth_header)
if not match:
return False
provided_signature = match.group(1)
# Decode the secret
secret = base64.b64decode(access_key_value)
# Build Path-And-Query
path_and_query = request.full_path
if path_and_query.endswith('?'):
path_and_query = path_and_query[:-1]
# Calculate expected signature
hash_obj = hmac.new(
secret,
path_and_query.encode('utf-8'),
hashlib.sha256
)
expected_signature = base64.b64encode(hash_obj.digest()).decode('utf-8')
# Compare signatures (constant-time comparison)
return hmac.compare_digest(expected_signature, provided_signature)
# Usage in Flask
@app.route('/groove')
def handle_groove_request():
access_key_value = os.environ.get('GROOVE_ACCESS_KEY')
if not validate_groove_signature(access_key_value):
return jsonify({
'code': 401,
'status': 'Unauthorized',
'message': 'Invalid signature'
}), 401
# Process valid request
return process_transaction()
Testing Signature Validation
Test Example
Given:
- Access Key Value:
dGVzdF9zZWNyZXRfa2V5XzEyMw==
- Request URL:
/groove?request=getbalance&accountid=123
- Expected Path-And-Query:
/groove?request=getbalance&accountid=123
Steps:
- Decode secret:
base64_decode("dGVzdF9zZWNyZXRfa2V5XzEyMw==")
- Calculate HMAC-SHA256 of Path-And-Query with secret
- Base64 encode the hash
- Compare with provided signature
Security Best Practices
- Always validate signatures in production environments
- Use constant-time comparison to prevent timing attacks
- Store Access Key securely (environment variables, secure vault)
- Log validation failures for security monitoring
- Reject requests with invalid or missing signatures
- Rotate Access Keys periodically as per security policy
- Use HTTPS for all communications
Common Issues and Solutions
Issue 1: Signature Mismatch
Cause: Incorrect Path-And-Query construction
Solution: Ensure you’re using the exact request URI including all query parameters
Issue 2: Encoding Problems
Cause: Incorrect base64 decoding of Access Key
Solution: Verify the Access Key is properly base64 decoded before use
Cause: Header not properly forwarded by proxy/load balancer
Solution: Configure your infrastructure to forward Authorization headers
Issue 4: Query Parameter Order
Cause: Parameters reordered by framework
Solution: Use the raw request URI as received, not reconstructed
Response for Invalid Signatures
When signature validation fails, return:
{
"code": 401,
"status": "Unauthorized",
"message": "Invalid signature",
"apiversion": "1.2"
}
Integration Checklist
Note on Optional Implementation
While signature validation is highly recommended for production environments, it may be optional during initial
integration and testing phases. Coordinate with Groove to determine when signature validation should be enabled for your
integration.
Free Round Bonus API
Overview
The Free Round Bonus (FRB) API enables your game platform to receive and process free spin bonus requests from Groove.
When casino operators want to offer free spins to their players on your games, Groove sends requests to your FRB API
endpoints.
Through this API, your platform will:
- Receive bonus template creation requests from Groove
- Process player bonus assignments sent by Groove
- Track and validate free round usage during gameplay
- Support multi-currency with automatic conversion from EUR base
Integration Flow
sequenceDiagram
participant Casino as Casino Operator
participant Groove
participant YourAPI as Your FRB API
participant YourGame as Your Game Server
participant Player
Note over Casino,YourAPI: Template Creation
Casino->>Groove: Create bonus campaign
Groove->>YourAPI: POST /create (bonus template)
YourAPI-->>Groove: Template ID response
Note over Casino,YourAPI: Bonus Assignment
Casino->>Groove: Assign bonus to players
Groove->>YourAPI: POST /assign (player list)
YourAPI-->>Groove: Assignment confirmation
Note over Player,YourGame: Free Round Usage
Player->>YourGame: Play free rounds
YourGame->>Groove: Wager with frbid
Groove-->>YourGame: Transaction response
Note over Casino,YourAPI: Status Check
Casino->>Groove: Check bonus status
Groove->>YourAPI: POST /status (player + assignment)
YourAPI-->>Groove: Status response
Note over Casino,YourAPI: Cancellation
Casino->>Groove: Cancel bonus
Groove->>YourAPI: DELETE /cancel (player + assignment)
YourAPI-->>Groove: Cancellation response
API Endpoints (Your Implementation)
Your platform must implement these endpoints to receive FRB requests from Groove:
1. Create Bonus Template
Method: POST
Endpoint: https://{your_domain}/frb/create (or your specified endpoint)
Purpose: Receive and process bonus template creation requests from Groove
Direction: Groove → Your Platform
2. Assign Bonus to Players
Method: POST
Endpoint: https://{your_domain}/frb/assign (or your specified endpoint)
Purpose: Receive and process bonus assignment requests from Groove
Direction: Groove → Your Platform
3. Get FRB Status
Method: POST
Endpoint: https://{your_domain}/frb/status (or your specified endpoint)
Purpose: Provide status information for a specific bonus assignment
Direction: Groove → Your Platform
4. Cancel FRB
Method: DELETE
Endpoint: https://{your_domain}/frb/cancel (or your specified endpoint)
Purpose: Cancel an active bonus assignment for a player
Direction: Groove → Your Platform
Key Features
Bonus Template Assignment and Currency Conversion
When Groove sends you bonus assignments:
- Base Currency: All templates use EUR as the base currency
- Automatic Conversion: Your system should convert EUR amounts to each player’s currency
- Multiple Assignments: The same template can be assigned to multiple players
- Currency Alignment: Each player receives the bonus in their account currency
- Exchange Rates: Use current rates to convert from EUR to player currencies
- Content-Type:
application/json; charset=UTF-8
- Method:
POST for create, assign, and status endpoints; DELETE for cancel endpoint
- All dates/times in UTC format
- Currency codes in ISO3 format
- Country codes in ISO3 format
- Idempotency: Handle duplicate requests from Groove properly - return same response
- Template Storage: Store template IDs when Groove creates them
- Currency Conversion: Convert EUR base amounts to player currencies
- Bulk Processing: Handle multiple player assignments in single request
- Error Responses: Return appropriate error codes to Groove
- Session Validation: Validate Groove session IDs in bonus requests
- Audit Trail: Log all bonus operations from Groove
All error responses follow this structure:
{
"status": "Error Type",
"code": 400,
"templateId": null,
"exceptionResponses": "Error description"
}
Common Error Codes
| Code |
Status |
Description |
| 200 |
Success |
Request processed successfully |
| 400 |
General Error |
Invalid parameters or request |
| 443 |
Wrong Game ID |
Game ID is not valid |
| 444 |
Wrong Player ID |
Player ID is not valid |
| 449 |
Invalid Parameters |
Parameter validation failed |
| 500 |
Internal Error |
Server error occurred |
Best Practices for Your Implementation
- Request Validation: Validate all parameters from Groove before processing
- Template Management: Store template details when Groove creates them
- Partial Success: Return detailed status for each player in bulk assignments
- Audit Logging: Log all incoming requests from Groove
- Currency Precision: Maintain proper decimal precision in conversions
- Expiry Handling: Track and enforce bonus expiration dates
- Duplicate Handling: Return original response for duplicate requests from Groove
- Session Security: Always validate Groove session tokens
Integration with Game Transactions
When a player uses free rounds in your game:
- Your game checks if the player has active free rounds
- Your game sends wager request to Groove with:
frbid: The unique assignment ID your platform generated in the assign response
betamount: Must be 0 (zero) for free round transactions
- Groove validates the bonus and processes the transaction
- Your game decrements the free round count after successful wager
Warning
**Important Transaction Rules for Free Rounds:**
- **frbid**: Must be the unique `templateId` that YOUR PLATFORM generates and returns in the assign response
- **betamount**: Must always be `0` for free round wagers
- **Unique Assignment IDs**: Each assignment must return a new unique templateId, even for the same bonus template
- **Multiple Grants**: The same template can be assigned multiple times to the same player - each with its own unique
assignment ID
Integration Steps
- Set up FRB endpoints on your servers to receive Groove requests
- Implement template storage to save bonus templates from Groove
- Add assignment logic to process player bonus assignments
- Implement status tracking to provide real-time bonus status
- Add cancellation support to handle bonus cancellations
- Integrate with your games to track free round usage
- Test with Groove using their staging environment
- Monitor and log all FRB operations for reconciliation
API Documentation
Subsections of Free Round Bonus API
Create Bonus
Create Bonus Template
This endpoint receives bonus template creation requests from Groove. When casino operators want to set up free spin
campaigns for your games, Groove sends the template details to your platform.
- Method:
POST
- Endpoint:
https://{your_domain}/frb/create (or your specified endpoint)
- Content-Type:
application/json; charset=UTF-8
- Direction: Groove → Your Platform
Request Parameters (What You’ll Receive from Groove)
| Parameter |
Type |
Mandatory |
Description |
providerName |
string |
Yes |
Provider’s name |
operatorId |
int |
Yes |
Operator’s ID |
transactionId |
string |
Yes |
Transaction’s ID |
numberOfRounds |
int |
Yes |
Amount of free bets |
availableFromDate |
string |
Yes |
Date and time from which the bonus becomes available in UTC Format: YYYY-MM-DD HH:MM:SS |
availableDuration |
int |
Yes |
How long the rounds will be available (in days) |
expirationDate |
string |
Yes |
Date and time until which the bonus is available in UTC Format: YYYY-MM-DD HH:MM:SS |
balanceTypeId |
int |
Yes |
Defines if the money goes to bonus/real |
messageFirstLine |
string |
Yes |
Text message 1 |
messageSecondLine |
string |
Yes |
Text message 2 |
offerName |
string |
Yes |
Name of the offer |
gameInfoList |
array |
Yes |
Array with the game details |
gameInfoList.gameId |
string |
Yes |
Identifies specific game |
gameInfoList.betAmount |
decimal |
Yes |
Bet value for each free bet |
Request Example
{
"providerName": "Provider Name",
"operatorId": 11,
"transactionId": "292c8dbb-e00d-4807-a754-0b9ae5297c1j",
"numberOfRounds": 10,
"availableFromDate": "2023-06-19 14:56:56",
"availableDuration": 90,
"expirationDate": "2025-01-15 11:24:38",
"balanceTypeId": 1,
"messageFirstLine": "You got a Free Round Bonus",
"messageSecondLine": "It's your lucky day",
"offerName": "2e10691304314db08244f8c730055af73781878195",
"gameInfoList": [
{
"gameId": "provider_game_id",
"betAmount": 1
}
]
}
Response Examples
Success Response
{
"status": "Success",
"code": 200,
"templateId": "123456789",
"exceptionResponses": null
}
Error Responses
General Error
{
"status": "General Error",
"code": 400,
"templateId": null,
"exceptionResponses": "Invalid Parameters"
}
Wrong Game ID
{
"status": "Wrong Game ID",
"code": 443,
"templateId": null,
"exceptionResponses": "Game id 123 is not valid"
}
Invalid Parameters
{
"status": "Invalid Parameters",
"code": 449,
"templateId": null,
"exceptionResponses": "Expiration Date is already Expired"
}
Internal Error
{
"status": "Internal Error",
"code": 500,
"templateId": null,
"exceptionResponses": null
}
Alternative Internal Error format:
{
"status": "Internal Error",
"errorCode": 500,
"description": "Wrong info received"
}
Implementation Requirements
- Template ID Generation: Your system must generate and return a unique
templateId in the response
- Storage: Store the template details for future player assignments from Groove
- Currency: All bet amounts are in EUR - convert when assigning to players
- Multi-Game Support: A template can include multiple games from your portfolio
- Offer Tracking: Store the
offerName as a unique identifier from Groove
- Date Validation: Verify expiration date is after available from date
- Idempotency: If Groove resends the same
transactionId, return the original response
Processing the Request (Your Implementation)
// Example of how to process the incoming request from Groove
app.post('/frb/create', (req, res) => {
const {
providerName,
operatorId,
transactionId,
numberOfRounds,
gameInfoList,
expirationDate,
// ... other parameters
} = req.body;
// Validate the request
if (!validateGameIds(gameInfoList)) {
return res.status(443).json({
status: "Wrong Game ID",
code: 443,
templateId: null,
exceptionResponses: "Invalid game ID provided"
});
}
// Generate unique template ID
const templateId = generateUniqueTemplateId();
// Store template in your database
storeTemplate({
templateId,
transactionId,
operatorId,
gameInfoList,
// ... other fields
});
// Return success response to Groove
res.json({
status: "Success",
code: 200,
templateId: templateId,
exceptionResponses: null
});
});
Validation Checklist
When processing requests from Groove, validate:
- ✅ All required fields are present in the request
- ✅ Game IDs match games available on your platform
- ✅ Dates are in correct UTC format (
YYYY-MM-DD HH:MM:SS)
- ✅ Expiration date is after available from date
- ✅ Bet amounts are positive numbers
- ✅ Transaction ID hasn’t been processed before (idempotency check)
Assign Bonus
Assign Bonus to Players
This endpoint receives player bonus assignment requests from Groove. When casino operators want to grant free spins to
specific players on your games, Groove sends the assignment details to your platform.
- Method:
POST
- Endpoint:
https://{your_domain}/frb/assign (or your specified endpoint)
- Content-Type:
application/json; charset=UTF-8
- Direction: Groove → Your Platform
Request Parameters (What You’ll Receive from Groove)
| Parameter |
Type |
Mandatory |
Description |
templateId |
string |
Yes |
Template’s ID (from create response) |
providerName |
string |
Yes |
Provider’s name |
operatorId |
int |
Yes |
Operator’s ID |
transactionId |
string |
Yes |
Transaction’s ID |
numberOfRounds |
int |
Yes |
Amount of free bets |
availableFromDate |
string |
Yes |
Date and time from which the bonus becomes available in UTC |
availableDuration |
int |
Yes |
How long the rounds will be available (in days) |
expirationDate |
string |
Yes |
Date and time until which the bonus is available in UTC |
balanceTypeId |
int |
Yes |
Defines if the money goes to bonus/real |
messageFirstLine |
string |
Yes |
Text message 1 |
messageSecondLine |
string |
Yes |
Text message 2 |
offerName |
string |
Yes |
Name of the offer |
gameInfoList |
array |
Yes |
Array with the game details |
gameInfoList.gameId |
string |
Yes |
Identifies specific game |
gameInfoList.betAmount |
decimal |
Yes |
Bet value for each free bet |
players |
array |
Yes |
Array with the player details |
players.playerId |
string |
Yes |
Player’s ID on operator’s side |
players.playerCurrency |
string |
Yes |
Player’s currency in ISO3 format |
players.playerCountry |
string |
Yes |
Player’s country in ISO3 format |
Request Example
{
"templateId": "fe06efeb-b7fd-4249-a58d-717226507d5f",
"providerName": "Provider Name",
"operatorId": 11,
"transactionId": "292c8dbb-e00d-4807-a754-0b9ae5297c1j",
"numberOfRounds": 10,
"availableFromDate": "2023-06-19 14:56:56",
"availableDuration": 90,
"expirationDate": "2025-01-15 11:24:38",
"balanceTypeId": 1,
"messageFirstLine": "You got a Free Round Bonus",
"messageSecondLine": "It's your lucky day",
"offerName": "2e10691304314db08244f8c730055af73781878195",
"gameInfoList": [
{
"gameId": "provider_game_id",
"betAmount": 1
}
],
"players": [
{
"playerId": "12345678",
"playerCurrency": "EUR",
"playerCountry": "IRL"
}
]
}
Response Examples
Success Response
{
"code": 200,
"status": "Success",
"templateId": "assign_unique_456xyz", // Unique ID for THIS assignment (different from create templateId)
"players": [
{
"playerId": 793918407,
"playerCurrency": "EUR",
"playerCountry": "IRL"
},
{
"playerId": 793918408,
"playerCurrency": "EUR",
"playerCountry": "IRL"
}
],
"exceptionResponses": null
}
**IMPORTANT - Unique Assignment IDs**:
- Each `/assign` request must return a **unique templateId** in the response
- This is different from the templateId received in the `/create` request
- The unique assignment templateId allows casinos to track different bonus triggers (e.g., registration bonus vs deposit
bonus)
- This unique assignment templateId will be used as the `frbid` parameter in transaction requests
- Example: Same bonus template assigned twice to same player should return two different templateIds
Partially Success Response
When some players are assigned successfully but others fail:
{
"code": 200,
"status": "Partially Succeeded",
"templateId": "123abc456",
"players": [
{
"playerId": 793918407,
"playerCurrency": "EUR",
"playerCountry": "IRL"
}
],
"exceptionResponses": null
}
Error Responses
General Error
{
"status": "General Error",
"code": 400,
"templateId": null,
"players": [
{
"playerId": 793918407,
"playerCurrency": "EUR",
"playerCountry": "IRL"
}
],
"exceptionResponses": "Invalid Parameters"
}
Wrong Game ID
{
"status": "Wrong Game ID",
"code": 443,
"templateId": null,
"players": [
{
"playerId": 793918407,
"playerCurrency": "EUR",
"playerCountry": "IRL"
}
],
"exceptionResponses": "Game id 123 is not valid"
}
Wrong Player ID
{
"status": "Wrong Player Id",
"code": 444,
"templateId": null,
"players": [
{
"playerId": 793918407,
"playerCurrency": "EUR",
"playerCountry": "IRL"
}
],
"exceptionResponses": ""
}
Internal Error
{
"status": "Internal Error",
"code": 500,
"templateId": null,
"players": [
{
"playerId": 793918407,
"playerCurrency": "EUR",
"playerCountry": "IRL"
}
],
"exceptionResponses": null
}
Implementation Requirements
- Template Validation: Verify the
templateId in the request matches a template previously created by Groove
- Generate Unique Assignment ID: Create a new unique
templateId for each assignment (different from the create
templateId)
- Currency Conversion: Your system must convert bet amounts from EUR to each player’s currency
- Bet Value Mapping: After currency conversion, use the closest bet value supported by your game for that currency
- Bulk Processing: Handle multiple player assignments in a single request from Groove
- Partial Success Handling: Support partial success - some players may succeed while others fail
- Player Validation: Check if player IDs from Groove exist in your system
- Assignment Tracking: Store each unique assignment with its generated templateId for transaction reference
- Idempotency: If Groove resends the same
transactionId, return the original response with the same unique
templateId
Processing the Request (Your Implementation)
// Example of how to process the incoming assignment request from Groove
app.post('/frb/assign', (req, res) => {
const {
templateId,
transactionId,
players,
gameInfoList,
// ... other parameters
} = req.body;
// Check if template exists (created earlier by Groove)
const template = getTemplate(templateId);
if (!template) {
return res.status(400).json({
status: "General Error",
code: 400,
templateId: null,
players: players,
exceptionResponses: "Template not found"
});
}
// Generate a UNIQUE assignment ID for this specific assignment
// This is different from the templateId in the request
const uniqueAssignmentId = generateUniqueAssignmentId();
// Example: "assign_" + uuid() or "assign_" + timestamp + "_" + randomId
// Process each player
const successfulPlayers = [];
const failedPlayers = [];
for (const player of players) {
// Validate player exists in your system
if (!validatePlayer(player.playerId)) {
failedPlayers.push(player);
continue;
}
// Convert EUR bet amounts to player's currency
// and map to closest supported bet value
const convertedBets = convertBetAmounts(
gameInfoList,
player.playerCurrency
);
// Map to closest supported bet values for the game
const supportedBets = mapToSupportedBetValues(
convertedBets,
player.playerCurrency
);
// Assign bonus to player with the unique assignment ID
assignBonusToPlayer({
playerId: player.playerId,
originalTemplateId: templateId, // Store original for reference
assignmentId: uniqueAssignmentId, // Unique ID for this assignment
convertedBets: supportedBets,
expirationDate: req.body.expirationDate
});
successfulPlayers.push(player);
}
// Return appropriate response to Groove with UNIQUE assignment ID
if (successfulPlayers.length === players.length) {
res.json({
code: 200,
status: "Success",
templateId: uniqueAssignmentId, // Return the UNIQUE assignment ID
players: successfulPlayers,
exceptionResponses: null
});
} else if (successfulPlayers.length > 0) {
res.json({
code: 200,
status: "Partially Succeeded",
templateId: uniqueAssignmentId, // Return the UNIQUE assignment ID
players: successfulPlayers,
exceptionResponses: null
});
} else {
res.status(444).json({
status: "Wrong Player Id",
code: 444,
templateId: null,
players: failedPlayers,
exceptionResponses: "No valid players found"
});
}
});
Validation Checklist
When processing assignment requests from Groove:
- ✅ Template ID exists in your system (from previous create request)
- ✅ All player IDs are validated against your player database
- ✅ Currency codes are in ISO3 format and supported
- ✅ Bet amounts are converted from EUR to player currencies
- ✅ Transaction ID hasn’t been processed before (idempotency)
- ✅ Expiration date hasn’t passed
Parameter Mismatch Handling
If the assignment parameters from Groove don’t match the stored template (except availableFromDate), return an error
response:
{
"status": "General Error",
"code": 400,
"templateId": null,
"players": [...],
"exceptionResponses": "Transaction parameter mismatch"
}
Currency Conversion Example
When Groove sends a template with EUR bet amounts, convert for each player:
| Template (EUR) |
Player Currency |
Converted Amount |
| 1.00 EUR |
USD |
1.10 USD |
| 1.00 EUR |
GBP |
0.85 GBP |
| 1.00 EUR |
EUR |
1.00 EUR |
Important: After converting the EUR amount to the player’s currency, use the closest bet value supported by your
game for that currency. For example, if the conversion results in 1.13 USD but your game only supports 1.00 or 1.25
USD bets, use the closest supported value.
Get FRB Status
Get FRB Status
This endpoint allows Groove to query the status of a specific free round bonus assignment for a player on your platform.
- Method:
POST
- Endpoint:
https://{your_domain}/frb/status (or your specified endpoint)
- Content-Type:
application/json; charset=UTF-8
- Direction: Groove → Your Platform
Request Parameters (What You’ll Receive from Groove)
| Parameter |
Type |
Mandatory |
Description |
operator_id |
Integer |
Yes |
Groove operator ID Example: 11 |
player_id |
String |
Yes |
The player ID Example: 12345678 |
template_id |
String |
Yes |
The unique assignment ID (the one your platform generated during /assign) Example: assign_456xyz |
player_currency |
String |
No |
Player’s currency in ISO3 format Example: EUR |
provider_id |
Integer |
No |
Your provider ID Example: 123 |
game_info_list |
Array |
No |
Array of game details associated with the FRB |
game_info_list.game_id |
String |
No |
Game identifier Example: game001 |
game_info_list.bet_amount |
Array |
No |
Available bet amounts Example: [1.0, 2.0] |
Request Example
{
"operator_id": 11,
"player_id": "12345678",
"template_id": "assign_456xyz",
"player_currency": "EUR",
"provider_id": 123,
"game_info_list": [
{
"game_id": "game001",
"bet_amount": [1.0, 2.0]
}
]
}
Response Parameters (What You Must Return)
| Parameter |
Type |
Mandatory |
Description |
player_id |
String |
Yes |
The player ID from the request |
player_currency |
String |
Yes |
Player’s currency in ISO3 format |
operator_id |
Integer |
Yes |
The operator ID from the request |
provider_id |
Integer |
Yes |
Your provider ID |
status |
String |
Yes |
Current status of the bonus (see Status Index below) |
template_id |
String |
Yes |
The assignment ID from the request |
left_rounds |
Integer |
Conditional* |
Number of rounds remaining *Required if status is active |
total_rounds |
Integer |
Conditional* |
Total number of rounds originally granted *Required if status is active |
expiration_date |
String |
Yes |
Expiration date in ISO 8601 format Example: 2025-02-11T12:00:00Z |
games |
Array |
Conditional* |
List of games for this bonus *Required if status is active |
games.game_id |
String |
Yes |
Game identifier |
games.bet_amount |
Array |
Yes |
Available bet amounts in player’s currency |
games.currency |
String |
Yes |
Currency for the bet amounts |
error_message |
String |
No |
Error description (empty string if no error) |
Available Statuses
All FRB endpoints must use these exact status values:
| Status Value |
Description |
"active" |
The FRB is active and can be used by the player |
"canceled" |
The FRB has been canceled by the operator |
"expired" |
The FRB has passed its expiration date |
"completed" |
The player has used all available rounds |
**Note**: These are the only valid status values. Always use lowercase and return them as strings.
Response Examples
Success Response - Active Bonus
{
"player_id": "12345678",
"player_currency": "EUR",
"operator_id": 11,
"provider_id": 123,
"status": "active",
"template_id": "assign_456xyz",
"left_rounds": 10,
"total_rounds": 50,
"expiration_date": "2025-02-11T12:00:00Z",
"games": [
{
"game_id": "game001",
"bet_amount": [1.0, 2.0],
"currency": "EUR"
},
{
"game_id": "game002",
"bet_amount": [1.0, 2.0],
"currency": "EUR"
}
],
"error_message": ""
}
Success Response - Completed Bonus
{
"player_id": "12345678",
"player_currency": "EUR",
"operator_id": 11,
"provider_id": 123,
"status": "completed",
"template_id": "assign_456xyz",
"left_rounds": 0,
"total_rounds": 50,
"expiration_date": "2025-02-11T12:00:00Z",
"games": [],
"error_message": ""
}
Success Response - Expired Bonus
{
"player_id": "12345678",
"player_currency": "EUR",
"operator_id": 11,
"provider_id": 123,
"status": "expired",
"template_id": "assign_456xyz",
"left_rounds": 5,
"total_rounds": 50,
"expiration_date": "2025-02-11T12:00:00Z",
"games": [],
"error_message": ""
}
Error Response
{
"player_id": "12345678",
"operator_id": 11,
"template_id": "assign_456xyz",
"error_message": "Bonus not found"
}
HTTP Response Codes
| Code |
Status |
Description |
| 200 |
Success |
FRB status retrieved successfully |
| 400 |
Bad Request |
Invalid parameters |
| 500 |
Internal Server Error |
Server error occurred |
Implementation Example
app.post('/frb/status', (req, res) => {
const { operator_id, template_id, player_id, player_currency } = req.body;
// Validate required parameters
if (!operator_id || !template_id || !player_id) {
return res.status(400).json({
player_id: player_id || "",
operator_id: parseInt(operator_id) || 0,
template_id: template_id || "",
error_message: "Missing required parameters"
});
}
// Look up the bonus assignment
const assignment = getAssignment(template_id, player_id);
if (!assignment) {
return res.status(200).json({
player_id: player_id,
operator_id: parseInt(operator_id),
template_id: template_id,
error_message: "Bonus not found"
});
}
// Determine status
let status = 'active';
if (assignment.canceled) {
status = 'canceled';
} else if (new Date(assignment.expiration_date) < new Date()) {
status = 'expired';
} else if (assignment.left_rounds === 0) {
status = 'completed';
}
// Build response
res.json({
player_id: player_id,
player_currency: assignment.player_currency,
operator_id: parseInt(operator_id),
provider_id: 123,
status: status,
template_id: template_id,
left_rounds: assignment.left_rounds,
total_rounds: assignment.total_rounds,
expiration_date: assignment.expiration_date,
games: status === 'active' ? assignment.games : [],
error_message: ""
});
});
Important Notes
- Template ID: The
template_id in the request is the unique assignment ID your platform generated during the
/assign request
- Status Logic: Determine status based on cancellation, expiration, and remaining rounds
- Games Array: Only include games array when status is
active
- Bet Amounts: Return the converted bet amounts in the player’s currency
- Error Handling: Always return a structured response even for errors
Best Practices
- Cache Assignment Data: Keep assignment data readily available for quick status checks
- Track Round Usage: Accurately track remaining rounds as players use them
- Update Status: Automatically update status based on expiration and usage
- Validate Operator: Ensure the operator_id matches the assignment
- Log Requests: Keep audit logs of all status check requests
Cancel FRB
Cancel FRB
This endpoint allows Groove to cancel an active free round bonus assignment for a player on your platform.
- Method:
DELETE
- Endpoint:
https://{your_domain}/frb/cancel (or your specified endpoint)
- Content-Type:
application/json; charset=UTF-8
- Direction: Groove → Your Platform
Request Parameters (What You’ll Receive from Groove)
| Parameter |
Type |
Mandatory |
Description |
operator_id |
Integer |
Yes |
Groove operator ID Example: 11 |
player_id |
String |
Yes |
The player ID Example: 12345678 |
template_id |
String |
Yes |
The unique assignment ID (the one your platform generated during /assign) Example: assign_456xyz |
player_currency |
String |
No |
Player’s currency in ISO3 format Example: EUR |
provider_id |
Integer |
No |
Your provider ID Example: 123 |
game_info_list |
Array |
No |
Array of game details associated with the FRB |
game_info_list.game_id |
String |
No |
Game identifier Example: game001 |
game_info_list.bet_amount |
Array |
No |
Available bet amounts Example: [1.0, 2.0] |
Request Example
{
"operator_id": 11,
"player_id": "12345678",
"template_id": "assign_456xyz",
"player_currency": "EUR",
"provider_id": 123,
"game_info_list": [
{
"game_id": "game001",
"bet_amount": [1.0, 2.0]
}
]
}
Response Parameters (What You Must Return)
The response structure is identical to the Get FRB Status endpoint, but should reflect
the actual status of the bonus.
**Critical**: Always return the ACTUAL status of the bonus, not necessarily "canceled":
- If the bonus was already `completed`, return status: `"completed"`
- If the bonus was already `expired`, return status: `"expired"`
- If the bonus was already `canceled`, return status: `"canceled"`
- Only return status: `"canceled"` if the cancellation was actually performed
| Parameter |
Type |
Mandatory |
Description |
player_id |
String |
Yes |
The player ID from the request |
player_currency |
String |
Yes |
Player’s currency in ISO3 format |
operator_id |
Integer |
Yes |
The operator ID from the request |
provider_id |
Integer |
Yes |
Your provider ID |
status |
String |
Yes |
The ACTUAL status of the bonus (see Available Statuses below) |
template_id |
String |
Yes |
The assignment ID from the request |
left_rounds |
Integer |
Yes |
Number of rounds remaining (0 if completed) |
total_rounds |
Integer |
Yes |
Total number of rounds originally granted |
expiration_date |
String |
Yes |
Original expiration date in ISO 8601 format |
games |
Array |
No |
Empty array for non-active statuses |
error_message |
String |
No |
Error description (empty string if successful) |
Available Statuses
All FRB endpoints must use these exact status values:
| Status Value |
Description |
"active" |
The FRB is active and can be used by the player |
"canceled" |
The FRB has been canceled by the operator |
"expired" |
The FRB has passed its expiration date |
"completed" |
The player has used all available rounds |
Response Examples
Success Response - Bonus Canceled
{
"player_id": "12345678",
"player_currency": "EUR",
"operator_id": 11,
"provider_id": 123,
"status": "canceled",
"template_id": "assign_456xyz",
"left_rounds": 10,
"total_rounds": 50,
"expiration_date": "2025-02-11T12:00:00Z",
"games": [],
"error_message": ""
}
Response - Already Completed (Cannot Cancel)
{
"player_id": "12345678",
"player_currency": "EUR",
"operator_id": 11,
"provider_id": 123,
"status": "completed",
"template_id": "assign_456xyz",
"left_rounds": 0,
"total_rounds": 50,
"expiration_date": "2025-02-11T12:00:00Z",
"games": [],
"error_message": ""
}
Info
**Note**: When a cancellation is requested for an already completed bonus, return HTTP 200 with status: `"completed"` to
indicate the actual state. The error_message can be empty or contain an informational message.
Response - Already Expired
{
"player_id": "12345678",
"player_currency": "EUR",
"operator_id": 11,
"provider_id": 123,
"status": "expired",
"template_id": "assign_456xyz",
"left_rounds": 5,
"total_rounds": 50,
"expiration_date": "2025-02-11T12:00:00Z",
"games": [],
"error_message": ""
}
Error Response - Bonus Not Found
{
"player_id": "12345678",
"operator_id": 11,
"template_id": "assign_456xyz",
"error_message": "Bonus not found"
}
HTTP Response Codes
| Code |
Status |
Description |
| 200 |
Success |
FRB canceled successfully or status returned |
| 400 |
Bad Request |
Invalid parameters |
| 500 |
Internal Server Error |
Server error occurred |
Implementation Example
app.delete('/frb/cancel', (req, res) => {
const { operator_id, template_id, player_id, player_currency } = req.body;
// Validate required parameters
if (!operator_id || !template_id || !player_id) {
return res.status(400).json({
player_id: player_id || "",
operator_id: parseInt(operator_id) || 0,
template_id: template_id || "",
error_message: "Missing required parameters"
});
}
// Look up the bonus assignment
const assignment = getAssignment(template_id, player_id);
if (!assignment) {
return res.status(200).json({
player_id: player_id,
operator_id: parseInt(operator_id),
template_id: template_id,
error_message: "Bonus not found"
});
}
// Check current status and respond accordingly
if (assignment.status === 'completed') {
// Return the actual status (completed) - cannot cancel
return res.json({
player_id: player_id,
player_currency: assignment.player_currency,
operator_id: parseInt(operator_id),
provider_id: 123,
status: "completed", // Return ACTUAL status
template_id: template_id,
left_rounds: 0,
total_rounds: assignment.total_rounds,
expiration_date: assignment.expiration_date,
games: [],
error_message: ""
});
}
if (assignment.status === 'expired') {
return res.json({
player_id: player_id,
player_currency: assignment.player_currency,
operator_id: parseInt(operator_id),
provider_id: 123,
status: "expired", // Return ACTUAL status
template_id: template_id,
left_rounds: assignment.left_rounds,
total_rounds: assignment.total_rounds,
expiration_date: assignment.expiration_date,
games: [],
error_message: ""
});
}
if (assignment.status === 'canceled') {
// Already canceled - return current status
return res.json({
player_id: player_id,
player_currency: assignment.player_currency,
operator_id: parseInt(operator_id),
provider_id: 123,
status: "canceled", // Already canceled
template_id: template_id,
left_rounds: assignment.left_rounds,
total_rounds: assignment.total_rounds,
expiration_date: assignment.expiration_date,
games: [],
error_message: ""
});
}
// Cancel the bonus
cancelAssignment(template_id, player_id);
// Return success response
res.json({
player_id: player_id,
player_currency: assignment.player_currency,
operator_id: parseInt(operator_id),
provider_id: 123,
status: "canceled",
template_id: template_id,
left_rounds: assignment.left_rounds,
total_rounds: assignment.total_rounds,
expiration_date: assignment.expiration_date,
games: [],
error_message: ""
});
});
Important Notes
- Template ID: The
template_id in the request is the unique assignment ID your platform generated during the
/assign request
- Status Response Rules:
- ALWAYS return the ACTUAL status of the bonus, not the requested action
- If bonus is
completed, return status: "completed" (not "canceled")
- If bonus is
expired, return status: "expired" (not "canceled")
- If bonus is already
canceled, return status: "canceled"
- Only return
"canceled" if you actually performed the cancellation
- HTTP Response Codes:
- Return HTTP 200 even when returning
completed or expired status
- Use HTTP 200 with error_message when the bonus doesn’t exist
- Player Protection: Ensure no active game rounds are using the bonus before cancellation
- Audit Trail: Keep records of cancellation attempts, even unsuccessful ones
- Immediate Effect: Successful cancellations should take effect immediately
Business Rules
-
Active Games: If a player is currently in a game round using this bonus, handle appropriately:
- Option 1: Prevent cancellation until round completes
- Option 2: Allow cancellation but let current round complete
- Document your approach for Groove
-
Refunds: Cancellation does not imply refund - it only stops future usage
-
Notification: Consider notifying the player that their bonus has been canceled
Best Practices
- Transaction Safety: Use database transactions to ensure atomic updates
- Concurrent Access: Handle race conditions if player is actively using the bonus
- Audit Logging: Log all cancellation requests with timestamp and reason
- Status Consistency: Ensure status is consistently updated across all systems
- Error Messages: Provide clear error messages for different failure scenarios
FAQ
Frequently Asked Questions
Template Creation & Assignment Flow
Will Groove send an /assign request without first sending a /create request?
Answer: No. Groove will always send a /create request first, and your platform must respond with a templateId. Groove then uses this templateId in subsequent /assign requests.
How do template IDs flow through the FRB process?
Answer: The template ID flow works as follows:
- Create: Groove sends create request → Your platform responds with
templateId (e.g., “template_123”)
- Assign: Groove sends assign request with
templateId: "template_123" → Your platform generates and returns a NEW unique templateId (e.g., “assign_456”)
- Transaction: Your game sends wager/result with
frbid: "assign_456" (the unique assignment ID, not the original template ID)
This allows the same bonus template to be assigned multiple times with unique tracking for each assignment.
Why does Groove send similar data in both create and assign requests?
Answer: Both requests contain similar data for consistency and validation purposes. Your platform can ignore any fields that aren’t relevant to your processing logic.
What should we do if Groove sends an /assign request with different parameters than the original /create request for the same offerName?
Answer: This situation is a mismatch so error should be returned:
{
"status": "General Error",
"code": 400,
"templateId": null,
"players": [
{
"playerId": 793918407,
"playerCurrency": "EUR",
"playerCountry": "IRL"
}
],
"exceptionResponses": "Transaction parameter mismatch"
}
Date & Time Management
Can availableFromDate, availableDuration, and expirationDate be different for POST /create and POST /assign?
Answer:
expirationDate - Yes, they can be different, expiration date of assign request will be determined by the assigment date + availableDuration
availableDuration - must be the same for both create and assign requests
availableFromDate - can be different for both create and assign requests
Answer: Correct, all dates are in UTC format.
What does availableDuration mean in Groove’s requests?
Answer: It specifies how many days the free rounds will be available to the player after the availableFromDate.
How does expirationDate relate to availableFromDate in Groove’s requests?
Answer: The expirationDate can be independent of availableFromDate. It represents the final date when the bonus expires, regardless of when it became available.
Duplicate Handling
How should we handle duplicate offerName values from Groove?
Answer: For /create requests from Groove with duplicate offerName, this is an error - return:
{
"status": "General Error",
"code": 400,
"templateId": null,
"exceptionResponses": "OfferName already exist"
}
For /assign requests, duplicate offerName is normal - it means Groove is assigning the same template to different players, or the same player is receiving the template multiple times.
Game & Player Management
Will Groove send multiple games in the gameInfoList?
Answer: Yes, Groove can send multiple games in a single template. If the list contains only one game, the bonus applies to that specific game. If multiple games are included, the bonus can be used on any of those games.
Will Groove send multiple players in a single /assign request?
Answer: Yes, Groove can send multiple players in the players array for bulk assignments. Your platform should process each player and return appropriate success/failure status for each.
Transaction Integration
What should our game send as frbid when making wager requests to Groove?
Answer: The frbid must be the unique templateId that YOUR PLATFORM generates and returns in the assign response. This is NOT the templateId from the create request or from Groove’s assign request - it’s a new unique ID you generate for each assignment.
What exactly should our game use as the frbid when sending wager requests to Groove?
Answer: The frbid must be the unique templateId that your platform generates and returns in the assign response. Each assignment gets a new unique ID, even when the same bonus template is assigned multiple times to the same player. This allows casinos to differentiate between bonuses triggered by different events (registration, deposit, etc.).
What bet amount should our game send in wager requests for free rounds?
Answer: The betamount parameter must always be 0 (zero) for free round transactions. The actual bet value for the free round is already defined in the FRB template and converted to the player’s currency during assignment.
If a round starts before expirationDate but finishes after, should our game still send the result to Groove?
Answer: Yes, your game should send the result request to Groove. As long as the round started before the expirationDate, it’s valid.
Implementation Details
Currency Conversion
When Groove sends bonus assignments, your platform must convert the EUR base amounts to each player’s currency. This ensures players receive equivalent value in their account currency.
Multiple Assignments from Groove
- Groove may assign the same template to multiple players
- Groove may assign the same template to the same player multiple times
- Each assignment must generate a NEW unique
templateId in your response
- Your platform tracks each assignment with its unique ID (e.g., remaining rounds per assignment)
- When a player has multiple active assignments, each has its own unique assignment ID for transactions
- This allows casinos to differentiate bonuses by trigger event (registration vs deposit vs promotion)
Best Practices for Handling Groove Requests
- Validate that template exists when Groove sends /assign requests
- Check if players exist in your system before assignment
- Return specific error codes to help Groove understand issues
- Support partial success when Groove sends multiple players
- Log all requests from Groove for reconciliation
Testing Your FRB Implementation
- Test receiving single and multiple player assignments from Groove
- Verify EUR to player currency conversion accuracy
- Test edge cases with date validations
- Ensure proper error responses are returned to Groove
- Test idempotency - return same response if Groove resends requests
MCP Server
Overview
The Groove MCP server exposes this entire documentation set — every endpoint, parameter, response and error code —
as tools that an AI coding assistant (Claude Code, Cursor, Copilot, …) can call directly. Instead of reading these pages
and hand-writing your integration, you connect your assistant to the MCP once and ask it.
It is a read-only oracle over the Groove integration specs. It serves documentation, computes and checks HMAC-SHA256
signatures, and generates code. It performs no wallet operations, holds no player data, and calls no Groove
backend at runtime — so it is safe to point an AI assistant at while you build.
Info
**Always pass `integration: "reverse"`** on every tool call. That scopes every answer to the reverse integration
documented on this site.
What you can do with it
| Capability |
Tools |
| Look up any endpoint’s full spec — parameters, responses, status codes |
get_endpoint, list_endpoints |
| Search the docs by keyword |
search_docs |
Compute the Authorization: HMAC-SHA256 Signature=… header for a request |
sign_request |
| Check whether an inbound signature is valid — the request checker |
verify_signature |
| Get a runnable example for one endpoint in Go / Java / Python / TypeScript / curl |
generate_snippet |
Generate a complete, startable project — /groove entry point, all 7 transaction ops, wallet seams |
generate_integration |
| Inspect the server itself |
list_tools, get_server_info |
See the Tools Reference for every parameter, and Example Workflows for worked examples.
Endpoint at a glance
| Property |
Value |
| URL |
https://<groove-gateway>/mcp |
| Transport |
MCP Streamable HTTP — JSON-RPC 2.0 over POST |
| Authentication |
Authorization: Bearer <MCP access token> |
| Token lifetime |
Constant — the token does not expire |
| Sessions |
Stateless — no session id, every call is independent |
| Max body size |
4 MiB (larger requests are rejected with 413) |
| Tools served |
9 |
| Endpoints served |
19 — every reverse-integration page on this site |
Getting your access key
**Contact your Groove account manager** to receive:
1. Your **MCP access token** — the value you put in the `Authorization: Bearer` header.
2. The **gateway base URL** for your environment (staging and production differ).
There is no self-service sign-up from the provider side: the token is issued by Groove. Treat it as a **shared secret** —
store it in your secret manager, keep it out of source control, and tell your account manager immediately if it leaks so
the signing key can be rotated.
How it fits together
graph LR
A[Your AI assistant<br/>Claude Code / Cursor] -->|POST /mcp<br/>Authorization: Bearer| B[Groove Gateway]
B --> C[Groove MCP Server]
C --> D[(Reverse Integration<br/>Specs)]
style C fill:#f9f,stroke:#333,stroke-width:4px
style A fill:#e8e0f7,stroke:#333
Your assistant speaks MCP to the gateway; the gateway authenticates the bearer token and serves the tools in-process.
Nothing you ask the MCP touches a live wallet, a player account or a real transaction.
Next steps
| Page |
What it covers |
| Setup |
Getting your token, the HTTP call, auth header, and client config |
| Tools Reference |
Every tool, every parameter, with request and response examples |
| Example Workflows |
End-to-end examples: verify a signature, generate a full project |
Subsections of MCP Server
Setup
Setup
This page takes you from nothing to a working MCP connection: obtain the access token, verify it with a plain HTTP call,
then wire it into your AI assistant.
What you need
| Item |
Where it comes from |
| Gateway base URL |
Your Groove account manager — differs per environment (staging / production) |
| MCP access token |
Your Groove account manager |
| An MCP client |
Claude Code, Cursor, VS Code, or any client supporting MCP over HTTP |
You do not need a Groove backoffice login, a security key, or any firewall change: the MCP is a normal outbound
HTTPS call from your machine or CI to the Groove gateway.
The gateway routes
The gateway exposes two MCP routes. Only the first one is for you — the second is how Groove issues your token.
| Route |
Method |
Who calls it |
Auth header |
/mcp |
POST (JSON-RPC) |
You, the game provider — your AI client or your own HTTP call |
Authorization: Bearer <mcp-token> |
/mcp/token |
POST |
Groove internal only — mints the token from a backoffice login |
jwt-auth: <backoffice-session> |
Info
You will never call `/mcp/token` yourself — you have no Groove backoffice login. Your account manager mints the token on
that route and hands you the resulting value. Everything on the provider side goes to `/mcp`.
Step 1 — Get your access token
Ask your Groove account manager for an MCP access token and the gateway base URL for the environment you are
integrating against.
The token is a long opaque string. It is constant and does not expire — you set it once in your client and there is
nothing to renew. It stays valid until Groove rotates the signing key.
**Handle the token as a shared secret.** It carries no user identity and no expiry, and it cannot be revoked
individually — the only revocation is a key rotation on Groove's side, which invalidates every issued token at once.
Store it in your secret manager, never commit it, and report a leak to your account manager straight away.
Step 2 — Verify it with a plain HTTP call
Before touching any client config, confirm the token works. This lists the available tools:
curl -s -X POST https://<groove-gateway>/mcp \
-H "Authorization: Bearer <MCP_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
A healthy response lists 9 tools: list_tools, get_server_info, get_endpoint, list_endpoints, search_docs,
sign_request, verify_signature, generate_snippet, generate_integration.
A second sanity check — ask it for the reverse endpoint catalogue:
curl -s -X POST https://<groove-gateway>/mcp \
-H "Authorization: Bearer <MCP_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"list_endpoints","arguments":{"integration":"reverse"}}}'
You should get 19 endpoints, grouped by category — the Transaction Flow operations, Game Launch, the Free Round
Bonus calls, and the reference pages. If that comes back, your token and URL are both correct.
Step 3 — Connect your AI assistant
Use the HTTP (Streamable HTTP) transport, point it at https://<groove-gateway>/mcp, and pass the token in the
Authorization header.
Claude Code (CLI)
claude mcp add --transport http groove https://<groove-gateway>/mcp \
--header "Authorization: Bearer <MCP_TOKEN>"
Cursor, VS Code, and generic MCP clients (mcp.json)
{
"mcpServers": {
"groove": {
"url": "https://<groove-gateway>/mcp",
"headers": {
"Authorization": "Bearer <MCP_TOKEN>"
}
}
}
}
After adding the server, restart or reload your client — it should list the 9 tools. Ask it something simple to confirm,
for example “Using the Groove MCP, list the reverse integration transaction endpoints.”
Calling the MCP directly over HTTP
You do not need an AI client. /mcp is plain JSON-RPC 2.0 over HTTPS, so you can drive it from a script, from your test
suite, or from a build step.
Envelope:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "<tool name>",
"arguments": { }
}
}
Required headers:
| Header |
Value |
Authorization |
Bearer <MCP_TOKEN> |
Content-Type |
application/json |
Accept |
application/json, text/event-stream |
Example — verify an inbound signature on a getbalance request:
curl -s -X POST https://<groove-gateway>/mcp \
-H "Authorization: Bearer <MCP_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{
"name":"verify_signature",
"arguments":{
"integration":"reverse",
"pathAndQuery":"/groove?request=getbalance&gamesessionid=123&accountid=456",
"key":"<your base64 Access Key Value>",
"signature":"<the base64 signature from the Authorization header>"
}}}'
The result is returned as text content — valid, or invalid signature (401).
Warning
The `key` you pass to `sign_request` / `verify_signature` is your Groove **Access Key Value** — the integration secret
described in [Signature Validation](/transaction-api/signature-validation). It is **not** the MCP access token, and the
two are never interchangeable.
Response and error codes
| Code |
Meaning |
200 |
Success — the JSON-RPC result is in the body |
401 |
Missing, malformed or invalid Authorization: Bearer token, or the signing key was rotated |
404 |
The MCP is not enabled on that gateway — check the base URL with your account manager |
413 |
Request body over the 4 MiB limit |
A tool-level failure (an unknown endpoint name, a malformed query) still returns HTTP 200 with isError: true and
an explanatory message in the result content — that is normal MCP behaviour, not a transport failure.
Troubleshooting
| Symptom |
Likely cause and fix |
401 on every call |
Token missing the Bearer prefix, truncated on copy, or rotated. Re-copy it; ask your account manager for a fresh one. |
404 on /mcp |
Wrong base URL, or the MCP is not enabled on that environment. Confirm the URL with your account manager. |
| Client connects but shows no tools |
Client is configured for stdio instead of HTTP, or the Authorization header is not being sent. |
413 Payload Too Large |
The request body exceeds 4 MiB. Tool arguments are small — this normally means a malformed request body. |
Tool returns no reverse endpoint named "…" |
Endpoint names are exact. Call list_endpoints with integration: "reverse" to get the canonical spelling (e.g. Wager And Result, Cancel FRB). |
| Results include endpoints not on this site |
integration was omitted. Always pass "reverse" so answers are scoped to this integration. |
The MCP server exposes 9 tools. Your AI assistant picks them automatically from your prompt, but they are documented
here in full so you can call them directly over HTTP or check exactly what your assistant is doing.
Every argument below goes in params.arguments of a tools/call request — see
Calling the MCP directly over HTTP.
| Tool |
Purpose |
Required arguments |
list_tools |
List every tool with its description and input schema |
— |
get_server_info |
Server name, version, endpoint count, supported integrations |
— |
list_endpoints |
List every documented endpoint, grouped by integration and category |
— |
get_endpoint |
Full spec for one endpoint: parameters, responses, error codes |
integration, name |
search_docs |
Free-text search across endpoint names, summaries and categories |
query |
sign_request |
Compute the signature header for a request |
integration, key |
verify_signature |
Check whether a signature is valid — the request checker |
integration, key, signature |
generate_snippet |
A runnable example for one endpoint in your language |
integration, name, language |
generate_integration |
A complete, startable project for the whole transaction flow |
integration, language |
Info
**Always pass `integration: "reverse"`.** It scopes every answer to the reverse integration documented on this site.
list_endpoints
Lists every documented endpoint, grouped by integration and category.
| Argument |
Type |
Required |
Description |
integration |
string |
Yes |
reverse — scopes the listing to the integration on this site |
{ "name": "list_endpoints", "arguments": { "integration": "reverse" } }
Returns the 19 reverse-integration entries:
| Category |
Endpoints |
| Transaction Flow |
GetAccount, GetBalance, Wager, Result, Wager And Result, Rollback, Jackpot |
| Game Launch |
Game Launch, Dynamic Game URL |
| Free Round Bonuses |
Create Bonus, Assign Bonus, Cancel FRB, Get FRB Status |
| Getting Started |
Groove Reverse Integration Overview, Transaction API Overview, Free Round Bonus API Overview |
| Reference |
Signature Validation, Error Code Appendix, Free Round Bonus FAQ |
Endpoint names are matched **exactly**, including spacing and capitalisation — `Wager And Result`, not `wagerAndResult`;
`Cancel FRB`, not `Cancel Bonus`. Run `list_endpoints` first if you are unsure of a name.
get_endpoint
Returns the full structured spec for one endpoint: request parameters, response fields, status codes, signature scheme
and authentication.
| Argument |
Type |
Required |
Description |
integration |
string |
Yes |
reverse |
name |
string |
Yes |
Exact endpoint name, e.g. Wager, Get FRB Status |
{ "name": "get_endpoint", "arguments": { "integration": "reverse", "name": "Wager" } }
Returns JSON — the endpoint’s method, path, category, summary, every documented parameter with its type and whether it is
required, the success response shape, and the applicable status codes.
search_docs
Free-text search over endpoint names, summaries and categories.
| Argument |
Type |
Required |
Description |
query |
string |
Yes |
Free text, e.g. balance, free spin, idempotency |
integration |
string |
Yes |
reverse — scopes the search to this integration |
{ "name": "search_docs", "arguments": { "query": "free round", "integration": "reverse" } }
Both signature tools implement the reverse scheme exactly as described in
Signature Validation:
Signature = base64_encode(HMACSHA256(Path-And-Query, base64_decode(Access Key Value)))
Header = Authorization: HMAC-SHA256 Signature={Signature}
Pass the Access Key Value as key — the tool performs the base64 decode for you.
sign_request
Computes the signature and returns the ready-to-send header.
| Argument |
Type |
Required |
Description |
integration |
string |
Yes |
reverse |
pathAndQuery |
string |
Yes |
The request path plus query string, e.g. /groove?request=getbalance&accountid=1 |
key |
string |
Yes |
Your Access Key Value (base64, as issued by Groove) |
{
"name": "sign_request",
"arguments": {
"integration": "reverse",
"pathAndQuery": "/groove?request=getbalance&gamesessionid=123&accountid=456",
"key": "<your Access Key Value>"
}
}
Result:
Authorization: HMAC-SHA256 Signature=<base64 signature>
verify_signature
The request checker: confirms a signature matches the request. Use it when a signature is being rejected and you need to
know whether the fault is yours or the sender’s.
| Argument |
Type |
Required |
Description |
integration |
string |
Yes |
reverse |
pathAndQuery |
string |
Yes |
The path plus query string exactly as received |
key |
string |
Yes |
Your Access Key Value |
signature |
string |
Yes |
The base64 signature to check |
Result is valid, or invalid signature (401).
Warning
`Path-And-Query` must be the **exact** string that was signed: absolute path, the `?`, and the query in its original
parameter order with original encoding. Re-ordering, decoding or dropping a parameter changes the hash and produces a
false `invalid`.
generate_snippet
A single runnable example for one endpoint, with the signing or verification step shown explicitly.
| Argument |
Type |
Required |
Description |
integration |
string |
Yes |
reverse |
name |
string |
Yes |
Exact endpoint name, e.g. Wager |
language |
string |
Yes |
go, java, python, typescript, or curl |
{
"name": "generate_snippet",
"arguments": { "integration": "reverse", "name": "Wager", "language": "python" }
}
generate_integration
Generates a complete, startable project — not a snippet. You get the files of a working skeleton:
- A real
/groove entry point wired for all 7 reverse transaction operations: getaccount, getbalance, wager,
result, rollback, jackpot, wagerAndResult.
- Inbound
Authorization HMAC verification, implemented against the documented scheme.
- The documented success responses and the full error catalogue — HTTP
200 with the status in the body, as this API
specifies.
- One wallet seam per operation family: the small set of files you fill in with your own logic, routed per brand.
| Argument |
Type |
Required |
Description |
integration |
string |
Yes |
reverse |
language |
string |
Yes |
go, java, python, or typescript |
{ "name": "generate_integration", "arguments": { "integration": "reverse", "language": "go" } }
Returns a JSON list of files, each with a path, content, and an action:
action |
Meaning |
overwrite |
Regenerated on every call — protocol plumbing, do not hand-edit |
create-if-absent |
Written once and never clobbered — the wallet seams and config are yours to edit |
That split means you can re-run generate_integration after a docs update to refresh the plumbing without losing your
own code.
Info
The generated project emits the full core transaction flow — there is no per-endpoint subsetting. For `java`, you get an
opinionated Spring Boot blueprint.
Returns every registered tool with its description and full JSON input schema. No arguments. Useful for confirming your
client is talking to the server you expect.
get_server_info
Reports the server’s identity and the size of its loaded catalogue. No arguments.
| Field |
Meaning |
name |
Always groove-mcp |
version |
The tool catalogue version, e.g. 1.0.0 |
endpoints_loaded |
How many endpoint specs the server has in memory |
Use it as a liveness check: a successful response means your token is valid and the server is serving.
Example Workflows
Example Workflows
Once the MCP is connected, you work with it in plain language — your assistant chooses the tools. These are the requests
that come up most often during a reverse integration, plus the raw HTTP equivalents for when you want to script them.
Prompts that work well
Exploring the API
- “List the reverse-integration transaction endpoints.”
- “Show me the full spec for the reverse Wager endpoint — every parameter and status code.”
- “What does the reverse integration require me to store to handle a later Rollback?”
- “Search the reverse docs for anything about free rounds.”
Signatures
- “Compute the Authorization header for
/groove?request=getbalance&gamesessionid=123&accountid=456 with access key
<key>, reverse scheme.”
- “This request came in with signature
<sig> — is it valid for path-and-query <path> with key <key>?”
- “My signature check keeps failing on Wager. Show me exactly what string should be hashed.”
Writing code
- “Generate a Python snippet for the reverse Result endpoint, including the signature verification.”
- “Generate a full Go project for the reverse integration and write the files into
./groove-integration.”
- “Regenerate the reverse TypeScript blueprint and tell me which files are safe to overwrite.”
Info
Say **"reverse"** in your prompt. That is what makes your assistant pass `integration: "reverse"`, scoping every answer
to the integration documented on this site.
Workflow 1 — Look up an endpoint before implementing it
Ask: “Show me the full spec for the reverse Wager endpoint.”
Your assistant calls:
{
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "get_endpoint",
"arguments": { "integration": "reverse", "name": "Wager" }
}
}
You get the documented request parameters, the success response shape, and the status codes — the same content as the
Wager page, but structured, so your assistant can generate matching code from it directly.
Follow up with “now generate the handler in Java” and it chains straight into generate_snippet.
Workflow 2 — Debug a failing signature
This is the fastest use of the MCP. When a signature is rejected, the question is always whose side is wrong — and
verify_signature answers it against a reference implementation.
Give your assistant the exact path-and-query you received, the signature from the Authorization header, and your access
key:
curl -s -X POST https://<groove-gateway>/mcp \
-H "Authorization: Bearer <MCP_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{
"name":"verify_signature",
"arguments":{
"integration":"reverse",
"pathAndQuery":"/groove?request=wager&gamesessionid=123&accountid=456&transactionid=789&betamount=1.00",
"key":"<your Access Key Value>",
"signature":"<signature from the Authorization header>"
}}}'
Reading the result:
| Result |
What it means |
valid |
The signature is correct — your own validation code has the bug. Compare your Path-And-Query construction against the string you just passed. |
invalid signature (401) |
Either the key is wrong for this environment, or the Path-And-Query you reconstructed is not the one that was signed. |
Then have it compute the expected value for comparison:
{
"name": "sign_request",
"arguments": {
"integration": "reverse",
"pathAndQuery": "/groove?request=wager&gamesessionid=123&accountid=456&transactionid=789&betamount=1.00",
"key": "<your Access Key Value>"
}
}
Diffing that against what your code produces isolates the fault in one step.
Warning
Your **Access Key Value** is a production secret. Prefer running these checks against your staging key, and never paste a
production key into a chat log or a shared transcript you do not control.
Workflow 3 — Generate a working skeleton
Ask: “Generate a full Go project for the reverse integration and write the files into ./groove-integration.”
Your assistant calls generate_integration and writes out the returned files:
{
"name": "generate_integration",
"arguments": { "integration": "reverse", "language": "go" }
}
What you get is startable, not illustrative — a /groove entry point handling all seven transaction operations, inbound
signature verification, and the documented response and error catalogue already wired up.
Then do the work that is actually yours:
- Open the
create-if-absent files — these are the wallet seams, one per operation family.
- Implement your balance, bet, win, and rollback logic behind them.
- Fill in your access key and Groove endpoint configuration.
- Run it, and use
verify_signature (Workflow 2) to confirm the inbound checks pass.
The overwrite files are protocol plumbing. Leave them alone — re-running generate_integration after a docs update
refreshes them without touching your seams.
Workflow 4 — Keep implementation and docs in step
Because the MCP serves the same specs published on this site, it is worth re-asking after any Groove docs update:
- “Compare the reverse Wager spec to my handler in
wager.go — am I missing any parameter?”
- “List every status code the reverse Rollback endpoint can return, and check my switch statement covers them.”
- “Regenerate the reverse Go blueprint and show me a diff of the overwrite files.”
This turns the certification checklist into something your assistant can verify against the source of truth rather than
against your memory of it.
Getting help
| Need |
Contact |
| MCP access token, gateway URL, key rotation |
Your Groove account manager |
| Integration questions during onboarding |
Your Groove integration channel (Slack / Teams) |
| API behaviour |
This documentation, or the MCP itself — ask it |