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:
GET
- Endpoint:
https://{your_domain}/frb/{version}/bonus?operator_id={operator_id}&template_id={template_id}&player_id={player_id}
- Direction: Groove → Your Platform
Request Parameters (What You’ll Receive from Groove)
| Parameter |
Type |
Mandatory |
Description |
version |
String |
Yes |
The API version. Currently supports 1.0 Example: 1.0 |
operator_id |
Integer |
Yes |
Groove operator ID Example: 11 |
template_id |
String |
Yes |
The unique assignment ID (the one your platform generated during /assign) Example: assign_456xyz |
player_id |
String |
Yes |
The player ID Example: 12345678 |
Request Example
GET /frb/1.0/bonus?operator_id=11&template_id=assign_456xyz&player_id=12345678
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": ""
}
Error Response
{
"player_id": "12345678",
"player_currency": "EUR",
"operator_id": 11,
"provider_id": 123,
"template_id": "assign_456xyz",
"expiration_date": "2025-02-11T12:00:00Z",
"error_message": "Bonus not found"
}
HTTP Response Codes
| Code |
Status |
Description |
| 200 |
Success |
FRB status retrieved successfully |
| 400 |
Bad Request |
Invalid parameters |
| 403 |
Forbidden |
Access denied |
| 500 |
Internal Server Error |
Server error occurred |
Implementation Example
app.get('/frb/:version/bonus', (req, res) => {
const { operator_id, template_id, player_id } = req.query;
const { version } = req.params;
// Validate parameters
if (!operator_id || !template_id || !player_id) {
return res.status(400).json({
player_id: player_id || "",
player_currency: "",
operator_id: parseInt(operator_id) || 0,
provider_id: 123,
template_id: template_id || "",
expiration_date: "",
error_message: "Missing required parameters"
});
}
// Look up the bonus assignment
const assignment = getAssignment(template_id, player_id);
if (!assignment) {
return res.status(404).json({
player_id: player_id,
player_currency: "EUR",
operator_id: parseInt(operator_id),
provider_id: 123,
template_id: template_id,
expiration_date: "",
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/{version}/bonus?operator_id={operator_id}&template_id={template_id}&player_id={player_id}
- Direction: Groove → Your Platform
Request Parameters (What You’ll Receive from Groove)
| Parameter |
Type |
Mandatory |
Description |
version |
String |
Yes |
The API version. Currently supports 1.0 Example: 1.0 |
operator_id |
Integer |
Yes |
Groove operator ID Example: 11 |
template_id |
String |
Yes |
The unique assignment ID (the one your platform generated during /assign) Example: assign_456xyz |
player_id |
String |
Yes |
The player ID Example: 12345678 |
Request Example
DELETE /frb/1.0/bonus?operator_id=11&template_id=assign_456xyz&player_id=12345678
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": ""
}
Error Response - Bonus Not Found
{
"player_id": "12345678",
"player_currency": "EUR",
"operator_id": 11,
"provider_id": 123,
"template_id": "assign_456xyz",
"expiration_date": "",
"error_message": "Bonus not found"
}
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.
HTTP Response Codes
| Code |
Status |
Description |
| 200 |
Success |
FRB canceled successfully |
| 400 |
Bad Request |
Invalid parameters or bonus cannot be canceled |
| 403 |
Forbidden |
Access denied |
| 404 |
Not Found |
Bonus assignment not found |
| 500 |
Internal Server Error |
Server error occurred |
Implementation Example
app.delete('/frb/:version/bonus', (req, res) => {
const { operator_id, template_id, player_id } = req.query;
const { version } = req.params;
// Validate parameters
if (!operator_id || !template_id || !player_id) {
return res.status(400).json({
player_id: player_id || "",
player_currency: "",
operator_id: parseInt(operator_id) || 0,
provider_id: 123,
template_id: template_id || "",
expiration_date: "",
error_message: "Missing required parameters"
});
}
// Look up the bonus assignment
const assignment = getAssignment(template_id, player_id);
if (!assignment) {
return res.status(404).json({
player_id: player_id,
player_currency: "EUR",
operator_id: parseInt(operator_id),
provider_id: 123,
template_id: template_id,
expiration_date: "",
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 the actual status (expired) - can still mark as canceled for records
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 404 only 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 - must be the same for both create and assign requests
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