Sport Free Bets (Digitain and Betby)
Sport Free Bets (Digitain and Betby)
Grant, check and cancel free bets on a sportsbook provider. Two sportsbook providers are supported: Digitain and Betby.
All three endpoints are the same for both providers. What changes is the set of fields you send.
| Operation | Endpoint | Method |
|---|---|---|
| Grant a sport free bet | /frb/sport-free-bet |
POST |
| Get sport free bet status | /frb/sport-free-bet/status?operator_id=XXXXX |
POST |
| Cancel a sport free bet | /frb/sport-free-bet/cancel |
POST |
These requests require an authorization token: Bearer authorization token.
Token Format: The authorization token must be Base64-encoded as follows:
AuthorizationToken = encode(back_office_email:back_office_password)
Digitain or Betby: what is different
| Topic | Digitain | Betby |
|---|---|---|
providerName |
Digitain |
Betby, spelled exactly like this |
| Where the rules live | In the request (odds, cash out, bet type, selections, duration) | In a Betby template, created in the Betby back office before granting |
templateId |
Do not send | Required. The ID of the template from the Betby back office |
| Free bet amount | minBet |
minBet, in the player’s currency, up to 2 decimals, at least 0.01 |
duration |
Required, greater than 0 (minutes) | Optional. The validity set in the Betby template applies |
| Odds and rules fields | Required (see below) | Not needed. If sent, they are ignored |
| Players per request | One | One |
Betby templates are created in the Betby back office, not through the Groove API. Create the template there first,
then send its ID as templateId in every grant. The template defines the bonus type, the allowed sports and markets,
the odds limits and the validity period.
Grant a sport free bet
Grant one free bet to one player.
Request endpoint: /frb/sport-free-bet
Request Method: POST
Request parameters:
| Parameter | Data type | Digitain | Betby | Description |
|---|---|---|---|---|
| providerName | String | Required | Required | Digitain or Betby. |
| operatorId | Integer | Required | Required | Groove operator ID. |
| grooveGameId | String | Required | Required | The Groove game ID of the sportsbook for your brand. |
| playerId | String | Required | Required | The player ID. |
| playerCurrency | String | Required | Required | ISO 4217 currency code of the player. |
| playerCountry | String | Required | Required | Country code of the player. |
| playerCity | String | Required | Required | City of the player. |
| offerName | String | Required | Required | A name for the offer. |
| transactionId | String | Required | Required | Unique ID of this request, generated by the casino. A repeated transactionId returns the first result. |
| minBet | Decimal | Required | Required | The free bet amount. For Betby: at most 2 decimals, at least 0.01. |
| templateId | String | — | Required | Betby template ID from the Betby back office. |
| duration | Integer | Required | Optional | Validity in minutes. Digitain: greater than 0. Betby: not sent to Betby, the template validity applies. |
| userBonusTypeId | Integer | Required | — | Digitain bonus type ID. |
| maxCashOut | Decimal | Required | — | Maximum cash out. Greater than 0. |
| minTotalOdd | Decimal | Required | — | Minimum total odd. Greater than 0. |
| maxTotalOdd | Decimal | Required | — | Maximum total odd. Greater than 0 and not lower than minTotalOdd. |
| minWageringOdd | Decimal | Optional | — | Minimum wagering odd. Not higher than maxWageringOdd. |
| maxWageringOdd | Decimal | Optional | — | Maximum wagering odd. |
| allowedBetTypeId | Integer | Optional | — | Allowed bet type. |
| minNumberOfSelections | Integer | Optional | — | Minimum number of selections in the bet. |
| oneTimeBet | Boolean | Optional | — | The free bet can be used in one bet only. |
| bonusEventTypeId | Integer | Optional | — | Bonus event type. |
| sportIds | String | Optional | — | Allowed sports. |
| tournamentIds | String | Optional | — | Allowed tournaments. |
| gameIds | String | Optional | — | Allowed events. |
| Authorization | Header | Required | Required | Sinatra back office user. |
“—” means the field is not used for this provider. If you send it, it is ignored.
Request body: Betby
{
"providerName": "Betby",
"operatorId": 11,
"grooveGameId": "XXXXXXXXX",
"playerId": "player_001",
"playerCurrency": "EUR",
"playerCountry": "MT",
"playerCity": "Valletta",
"offerName": "Weekend free bet",
"transactionId": "550e8400-e29b-41d4-a716-446655440000",
"templateId": "2291845327163297792",
"minBet": 5.00
}Request body: Digitain
{
"providerName": "Digitain",
"operatorId": 11,
"grooveGameId": "236000000",
"playerId": "player_001",
"playerCurrency": "EUR",
"playerCountry": "MT",
"playerCity": "Valletta",
"offerName": "Weekend free bet",
"transactionId": "550e8400-e29b-41d4-a716-446655440001",
"userBonusTypeId": 2,
"duration": 10080,
"minBet": 5.00,
"maxCashOut": 100,
"minTotalOdd": 1.5,
"maxTotalOdd": 10,
"minWageringOdd": 1.5,
"maxWageringOdd": 10,
"allowedBetTypeId": 1,
"minNumberOfSelections": 1,
"oneTimeBet": true,
"bonusEventTypeId": 1
}Success response
The response has the same shape for both providers.
{
"status": "Success",
"data": {
"status": "Success",
"transactionId": "550e8400-e29b-41d4-a716-446655440000",
"bonusId": "2291846012345678901"
}
}Keep bonusId. You need it to check the status and to cancel the free bet.
When the provider rejects the grant, the HTTP code is still 200. data.status is Failed and
data.exceptionResponses holds the reason:
{
"status": "Success",
"data": {
"status": "Failed",
"transactionId": "550e8400-e29b-41d4-a716-446655440000",
"exceptionResponses": ["betby external api config is not available for this casino"]
}
}Get sport free bet status
Get the free bets granted to a player.
Request endpoint: /frb/sport-free-bet/status?operator_id=XXXXX
Request Method: POST
Request parameters:
| Parameter | Data type | Description |
|---|---|---|
| operator_id | Integer required | Groove operator ID (query string). |
| providerName | String required | Digitain or Betby. Must be the provider used for the grant. |
| playerId | String required | The player ID. |
| freeBetIds | Array optional | The bonusId values from the grant response. Empty returns the player’s free bets. |
| currency | String optional | ISO 4217 currency code of the player. |
| Authorization | Header | Sinatra back office user. |
Request body:
{
"providerName": "Betby",
"playerId": "player_001",
"freeBetIds": ["2291846012345678901"],
"currency": "EUR"
}Success response
{
"status": "Success",
"data": {
"items": [
{
"free_bet_id": "2291846012345678901",
"player_id": "player_001",
"casino_id": 11,
"currency": "EUR",
"number_of_spins": 1,
"spins_used": 0,
"bet_amount": "5",
"status": "active",
"expiration_date": "2026-10-30T00:00:00Z",
"created_at": "2026-09-30T10:00:00Z"
}
]
}
}Status Index:
| Status | Description | Betby status |
|---|---|---|
| active | The free bet is available. The player can use it. | new, active |
| completed | The player used the free bet. | activated, done |
| expired | The free bet was not used before the expiration date. | expired |
| canceled | The operator canceled the free bet. | revoked |
For Betby, the status of an active free bet is read from Betby on every request. If Betby does not answer, the last known status is returned.
Cancel a sport free bet
Cancel a free bet the player has not used yet. The request is the same for both providers. You do not need to send
providerName: Groove finds the provider from the original grant.
Request endpoint: /frb/sport-free-bet/cancel
Request Method: POST
Request parameters:
| Parameter | Data type | Description |
|---|---|---|
| operatorId | Integer required | Groove operator ID. |
| grooveGameId | String required | The Groove game ID of the sportsbook for your brand. |
| items | Array required | The free bets to cancel. |
| items[].bonus_id | String required | The bonusId from the grant response. |
| items[].player_id | String required | The player ID. |
| items[].request_id | Integer optional | Your ID for this cancel item. |
| Authorization | Header | Sinatra back office user. |
Request body:
{
"operatorId": 11,
"grooveGameId": "XXXXXXXXX",
"items": [
{
"bonus_id": "2291846012345678901",
"player_id": "player_001",
"request_id": 1001
}
]
}Success response
{
"status": "Success",
"data": {
"response_code": 0,
"description": "",
"bonus_id": "2291846012345678901",
"player_id": "player_001",
"request_id": 1001,
"retryable": false
}
}Only an unused free bet can be canceled. response_code other than 0 means the free bet was not canceled.
Betby cancel response codes
For Betby, response_code in the cancel response is one of these. retryable: true means you can send the same
request again later.
| Code | Meaning | Retryable |
|---|---|---|
| 0 | Canceled | No |
| 1005 | Cannot be canceled: the free bet is not found, already used, or ended | No |
| 1007 | Betby is not configured for this operator | No |
| 1100 | Betby returned an error. See description |
No |
| 1101 | Betby is not available | Yes |
| 1102 | Internal error | Yes |
How a Betby free bet reaches the wallet
When the player places a Betby free bet, Groove sends the normal Transaction API calls to the
casino. The wager carries the bonus ID in frbid.
| Betby bonus type | Wager amount sent to the casino |
|---|---|
Free bet (freebet_freemoney) |
0 |
Free bet refund (freebet_refund) |
0 |
No risk free bet (freebet_no_risk) |
The real stake |
Combo boost (comboboost) |
The real stake |
Wins, losses and rollbacks follow the same rules as a normal bet.
Response codes
| Code | Status | Message |
|---|---|---|
| 200 | success | The request was processed. Check data for the result. |
| 400 | bad request | The request body is not valid JSON. |
| 403 | forbidden access | The user has no access to this operator. |
| 422 | unprocessable entity | A required field is missing or not valid. The response lists each problem. |
| 500 | internal server error | internal server error |
Validation error example (Betby grant without templateId):
{
"status": "Error",
"data": ["template ID is required for provider betby"],
"message": "sport free bet validation failed[template ID is required for provider betby]",
"userFriendlyMessage": "sport free bet validation failed"
}