# Virtual Sports Suite for Mobile Integration

## General information

The Sportradar Virtual Sports Mobile Suite is the ready-to-use solution for offering our product portfolio in a mobile environment.

Our Virtual Sports Mobile Suite includes the video area with the live scores, market offer for the upcoming two match days and the possibility to switch between the available matches.

Additionally it includes the separator bars for the odds area, in order to show the information for the upcoming 2 match days.

<figure><img src="/files/AVwGUzx9FlkoUYeRPlFs" alt=""><figcaption></figcaption></figure>

## Host page HTML requirements

Sportradar’s Virtual Sports Mobile Suite is a framework for a mobile web application, which integrates into an existing mobile-optimized website as a JavaScript plugin.

In order to integrate the plugin, the following steps must be implemented in the host webpage:

### Include the vsmobile JavaScript plugin

```javascript
<script type="text/JavaScript" src="https://{domain}/ls/mobile/?/<CUSTOMER>/<LANGUAGE_CODE>/[<TIME_ZONE>/]page/vsmobile"></script>
```

The JavaScript plugin is hosted on Sportradar's servers. `{domain}` will be provided by your assigned integration manager during integration.

Configurable parts in the URL are the customer name (`<CUSTOMER>`), language code (`<LANGUAGE_CODE>`, e.g. en) and time zone (`<TIME_ZONE>`, e.g. Europe:Berlin). The time zone parameter is optional. The UI customization is based on the client name URL parameter, therefore each client is assigned a unique client name. Language should follow the localization of the host page.

The following is an example script URL:

```javascript
<script type="text/JavaScript" src="https://{domain}/ls/mobile/?/<CUSTOMER>/en/Europe:Berlin/page/vsmobile"></script>
```

### Provide container DOM elements in which the UI will be injected

A container element is typically a `div` tag or some other block element with `id` attribute set. Example\
is shown below:

```html
<div id="vsm_container"></div>
```

If you want to use optional features like the match day title components, you need to provide\
container elements for those as well:

```html
<div id="vsm-current-matchday-title" class="vsm-current-matchday-title"></div>
<div id="vsm-next-matchday-title" class="vsm-next-matchday-title"></div>
```

### Add `meta` tags to the `<HEAD>` section

Sportradar’s Virtual Sports Mobile Suite is a web page optimized for mobile browsing. For optimal mobile experience the following meta tags should be added to a section in the host\
HTML page.

```html
<meta name="viewport" content="initial-scale=1, maximum-scale=1, width=device-width, minimal-ui"/>
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta names="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
```

The first `<meta>` tag is needed for setting the `viewport` to a size of the display on the device and for\
disabling zoom. It also instructs the browser to minimize the address bar and toolbars on some\
devices.

The second and third lines enable the use of full-screen mode in iOS devices under certain\
circumstances.

It is also recommended to add `<link rel="icon" />`, `<link rel="apple-touch-icon />` and `<link rel="manifest" />` tags to the head of the document in order to customize the application icon if the user adds the page to their home screen.

## Application initialization

The application is initialized using the `vsmobile.init()` method. The first parameter is the value of the ID property (and a prepended #) of the container element specified above and the second parameter contains initialization options. Sample code of the initialization call is shown below. Note that only one application instance may be initialized on the host page at any given time.

```javascript
var vsm = vsmobile.init('#vsm_app_container', options);
```

## Initialization options

The options are added as a second parameter in the `init` method. Below is an example options object that contains all possible available options.initialization. Please note that this is just an example and usually only a fraction of these options are needed for production (i.e. a working application).

```javascript
var options = {
    sport: sport,
    onLoad: onLoad,
    betsChanged: betsChanged,
    showSlip: showSlip,
    loginRequired: loginRequired,
    setEvents: setEvents,
    roundOddsOverride: roundOddsOverride,
    topHeaderHeight: 0,
    bottomFooterHeight: 0,
    betSelectionMode: 'all',
    outrightSelectionMode: 'market',
    useBrowserHistoryAPI: true,
    displayMode: 'fixed',
    showBetButton: true,
    persistSelections: false,
    showUnsupportedDeviceWarning: true,
    referrer: 'referrerId',
    clientId: <CLIENT_ID>,
    enableMenuShortcuts: true,
    maintenanceCallback: maintenanceCallback,
    oddType: 'dec'
};
```

The initialization options are documented in the table below. Callback functions are described in detail below the table.

<table><thead><tr><th width="160" valign="top">Option</th><th width="110" valign="top">Required</th><th width="89" valign="top">Type</th><th width="97" valign="top">Default</th><th valign="top">Comment</th></tr></thead><tbody><tr><td valign="top"><code>sport</code></td><td valign="top">yes</td><td valign="top"><code>string</code></td><td valign="top"><code>null</code></td><td valign="top"><p>The sport to display on this page. The only supported options are:</p><p><br><code>vflm</code><br><code>vfnc</code><br><code>vfwc</code><br><code>vfas</code><br><code>vfc</code><br><code>vfcc</code><br><code>vbl</code></p></td></tr><tr><td valign="top"><code>onLoad</code></td><td valign="top">no</td><td valign="top"><code>function</code></td><td valign="top">/</td><td valign="top">Callback function which is called when application is loaded.</td></tr><tr><td valign="top"><code>betChanged</code></td><td valign="top">no</td><td valign="top"><code>function</code></td><td valign="top">/</td><td valign="top">Callback function which is called each time betting selections in the application user interface changed. For example, if a user selects a bet, deselects a previously selected bet, or if bets are automatically deselected because the time to<br>confirm such bets has expired.</td></tr><tr><td valign="top"><code>showSlip</code></td><td valign="top">yes</td><td valign="top"><code>function</code></td><td valign="top">/</td><td valign="top">Callback function which is called when a user clicks on the 'Confirm bets' button. This callback function should usually be implemented by the customer. Alternatively, the customer may implement <code>betsChanged</code> and render their own<br>button or UI control for bringing up the bet slip.</td></tr><tr><td valign="top"><code>roundOddsOverride</code></td><td valign="top">no</td><td valign="top"><code>function</code></td><td valign="top">/</td><td valign="top">Implement this callback to override all odds for a given round, i.e. a match day (vflm).</td></tr><tr><td valign="top"><code>topHeaderHeight</code></td><td valign="top">no</td><td valign="top"><code>numeric</code></td><td valign="top"><code>0</code></td><td valign="top">Height of client's top header (e.g. navigation, banner). Inserted top header element must have a fixed height and fixed positioning.</td></tr><tr><td valign="top"><code>bottomFooterHeight</code></td><td valign="top">no</td><td valign="top"><code>numeric</code></td><td valign="top"><code>0</code></td><td valign="top">Height of client's bottom footer. Inserted footer element must have a fixed height and fixed positioning.</td></tr><tr><td valign="top"><code>betSelectionMode</code></td><td valign="top">no</td><td valign="top"><code>string</code></td><td valign="top"><code>match</code></td><td valign="top"><p>Bet selection mode. Valid modes are:</p><p></p><p><code>all</code> - all bets can be selected; <code>market</code> - for each market only one bet can be<br>selected per match; </p><p><code>match</code> - for each match only one bet can be selected;</p></td></tr><tr><td valign="top"><code>outrightSelectionMode</code></td><td valign="top">no</td><td valign="top"><code>string</code></td><td valign="top"><code>market</code></td><td valign="top"><p>Outright bet selection mode. Valid modes are:</p><p></p><p><code>all</code> - all bets can be selected; <code>market</code> - for each market only one bet can be selected;</p></td></tr><tr><td valign="top"><code>useBrowserHistoryAPI</code></td><td valign="top">no</td><td valign="top"><code>boolean</code></td><td valign="top"><code>true</code></td><td valign="top"><p>When set to <code>false</code>, the application will not store page transitions into the browser history.</p><p></p><p>Recommendation: set to <code>false</code> if your host application is using the Browser History API library.</p></td></tr><tr><td valign="top"><code>displayMode</code></td><td valign="top">no</td><td valign="top"><code>string</code></td><td valign="top"><code>fixed</code></td><td valign="top"><p>Display mode. Valid modes are:</p><p></p><p><code>fixed</code> - popup windows are displayed in full screen mode with content centered inside;<br><code>inline</code> - popup windows are displayed inline (use this option if you use inline footer and you don't want popups to display over it);</p></td></tr><tr><td valign="top"><code>showBetButton</code></td><td valign="top">no</td><td valign="top"><code>boolean</code></td><td valign="top"><code>true</code></td><td valign="top">If set to <code>false</code>, the bet confirmation button will not be shown when the user selects bets. This is typically used if there is an existing button on the host web page which links to the betting slip.</td></tr><tr><td valign="top"><code>persistSelect</code><br><code>ions</code></td><td valign="top">no</td><td valign="top"><code>boolean</code></td><td valign="top"><code>false</code></td><td valign="top">If set to <code>true</code>, odds selected by the user will be persisted to local storage and reconstructed upon reload.</td></tr><tr><td valign="top"><code>showUnsupportedDeviceWarning</code></td><td valign="top">no</td><td valign="top"><code>boolean</code></td><td valign="top"><code>true</code></td><td valign="top">Set to false to disable warning for<br>unsupported devices (this warning is shown once on the first load).</td></tr><tr><td valign="top"><code>clientId</code></td><td valign="top">no</td><td valign="top"><code>numeric</code></td><td valign="top">implicit</td><td valign="top">The numeric client identifier (Sportradar S4 client ID). Primarily used for internal testing purposes.</td></tr><tr><td valign="top"><code>loginRequired</code></td><td valign="top">no</td><td valign="top"><code>function</code></td><td valign="top">/</td><td valign="top"><p>Callback function which is called when a user tries to conduct an action that requires an established RGS user session (user should be authenticated). </p><p></p><p><strong>Used for RGS integrations only.</strong></p></td></tr><tr><td valign="top"><code>referrer</code></td><td valign="top">no</td><td valign="top"><code>string</code></td><td valign="top">/</td><td valign="top"><p>This is the referrer ID to use with RGS when different endpoints are needed. </p><p></p><p><strong>Used for RGS integrations only.</strong></p></td></tr><tr><td valign="top"><code>setEvents</code></td><td valign="top">no</td><td valign="top"><code>function</code></td><td valign="top">/</td><td valign="top">Callback function which is called every<br>betstop phase. Returns information<br>regarding the current sport (including<br>event_ids).</td></tr><tr><td valign="top"><code>enableMenuShortcuts</code></td><td valign="top">no</td><td valign="top"><code>boolean</code></td><td valign="top"><code>false</code></td><td valign="top">Show icons in the navigation bar for menu items.</td></tr><tr><td valign="top"><code>maintenanceCallback</code></td><td valign="top">no</td><td valign="top"><code>function</code></td><td valign="top">undefined</td><td valign="top">Will be called when a product is in <code>maintenance</code> or <code>pause</code> mode or when that mode is not active anymore. Returns information about the sport, current server time, and which mode is active.</td></tr><tr><td valign="top"><code>oddType</code></td><td valign="top">no</td><td valign="top"><code>string</code></td><td valign="top"><code>dec</code></td><td valign="top">Format of the odds in the odds area. Valid values are <code>dec</code>, <code>us</code>, <code>hk</code>, <code>indo</code>, <code>my</code>, <code>frac</code></td></tr></tbody></table>

## Callbacks

With callbacks, you can respond to events in the `VSM` application. There are several callbacks that can be implemented on client side. The first parameter to all callbacks is the `VSM` instance that triggered the callback.

### `onLoad`

This callback function is called when the application is loaded. API methods may safely be called only after the application is loaded, as signaled by this callback.

Callback example:

```javascript
function onLoad(vsmInstance) {
    console.log('vsm loaded');
};
```

### `betsChanged`

This callback function is called every time the betting selections in the user interface change.

The typical use of this method is to display or update a bet slip on the host page. An array of all current selections is passed in the `currentBets` parameter.

Furthermore, bets that have been added and bets that have been removed since the previous change are passed for convenience in the `betsAdded` and `betsRemoved` parameters.

Callback example:

```javascript
function betsChanged(vsmInstance, currentBets, betsAdded, betsRemoved, betsChangedReason) {
    console.log("Bets currently selected in the VSM interface:");
    for (var i = 0; i < currentBets.length; ++i) {
        var bet = currentBets[i];
        console.log(" --------");
        console.log(" Selection unique key: " + bet.selectionKey);
        console.log(" Sport: " + bet.sport);
        console.log(" Tournament id: " + bet.tournamentId);
        console.log(" Tournament name: " + bet.tournamentName);
        console.log(" Tournament number: " + bet.tournamentNumber);
        console.log(" Tournament stage: " + bet.tournamentStage);
        console.log(" Round number: " + bet.roundNumber);
        console.log(" Match id: " + bet.matchId);
        console.log(" Fixture: " + bet.fixture);
        console.log(" Bet id: " + bet.xmlBetId);
        console.log(" Bet type id: " + bet.xmlTypeId);
        console.log(" Bet subtype id: " + bet.xmlSubtypeId);
        console.log(" Special odds value: " + bet.xmlSpecialOddsValue);
        console.log(" Bet outcome id: " + bet.betOutcomeId);
        console.log(" Market name: " + bet.marketName);
        console.log(" Market status: " + bet.status);
        console.log(" Outcome name: " + bet.outcomeName);
        console.log(" Odds: " + bet.odds);
        console.log(" Is outright market: " + bet.isOutrightMarket);
    }
    console.log(" --------");
    console.log("Total number of unconfirmed bets: " + currentBets.length);
};
```

The following properties are provided for each bet:

<table><thead><tr><th width="230" valign="top">Property</th><th valign="top">Comment</th></tr></thead><tbody><tr><td valign="top"><code>asianOutcome</code></td><td valign="top">When <code>asianSpreads</code> are enabled and available for the selected market, this object will contain the asian spreads. It has 4 fields: <code>marketName</code>, <code>outcomeName</code>, <code>prefix</code>, <code>value</code>.</td></tr><tr><td valign="top"><code>selectionKey</code></td><td valign="top">The unique key to be used to reference this selection in API calls. Does not exist on outrights.</td></tr><tr><td valign="top"><code>selectionDescription</code></td><td valign="top">For non asian market this field will simply contain the <code>outcomeName</code>. For asian markets this field will contain the <code>asianOutcome</code> name.</td></tr><tr><td valign="top"><code>selfDestruct</code></td><td valign="top">For VTI this field contains a function which will remove the bet from the betslip if it's not valid anymore.</td></tr><tr><td valign="top"><code>sportForUrl</code></td><td valign="top">The sport product name. For example each vf (vflm, vfwc, vfnc, vfas) product will contain vfc as a string on this field.</td></tr><tr><td valign="top"><code>outRightSelectionKey</code></td><td valign="top">The unique key to be used to reference this selection in API calls. Only exists on outrights.</td></tr><tr><td valign="top"><code>sport</code></td><td valign="top">Virtual sport, e.g. <code>vflm</code>.</td></tr><tr><td valign="top"><code>tournamentId</code></td><td valign="top">Tournament/competition identifier.</td></tr><tr><td valign="top"><code>tournamentName</code></td><td valign="top">The human-readable name of the tournamant, e.g. "Virtual Football League".</td></tr><tr><td valign="top"><code>tournamentNumber</code></td><td valign="top">The consecutive iteration of the competition/tournament (season number).</td></tr><tr><td valign="top"><code>tournamentStage</code></td><td valign="top">Tournaments which consist of multiple stages will have this parameter set. Only used by <code>vfnc</code> and <code>vfwc</code> with one of the two following values: <code>group</code> or <code>knockout</code>.</td></tr><tr><td valign="top"><code>roundNumber</code></td><td valign="top"><p>The sequential number of the match day or round within an iteration of the competition. </p><p><br>For <code>vfnc</code> and <code>vfwc</code> the round number depends on the tournament stage. In the <code>group</code> stage the <code>roundNumber</code> will be the sequential<br>number of the match day. In the <code>knockout</code> stage, round number will have on of the following values: </p><p></p><p>4 (round 16), 3 (quarterfinals), 2 (semifinals), 1 (finals).</p></td></tr><tr><td valign="top"><code>matchId</code></td><td valign="top">Match unique identifier. Undefined on outrights.</td></tr><tr><td valign="top"><code>matchStartTime</code></td><td valign="top">A timestamp when the match the bet is for starts. Undefined on outrights.</td></tr><tr><td valign="top"><code>meta</code></td><td valign="top">When an palAvv id exists, for example for italian markets, the meta object will contain a field with the palAvv id.</td></tr><tr><td valign="top"><code>fixture</code></td><td valign="top">Display name for the fixture, e.g. "VFL Bern - VFL London".</td></tr><tr><td valign="top"><code>marketName</code></td><td valign="top">Localized display name for the selected market, e.g. "Total Goals - Over/Under 2.5".</td></tr><tr><td valign="top"><code>status</code></td><td valign="top">Contains the current market status as available in the unified odds feed, e.g. 1 for an active market.</td></tr><tr><td valign="top"><code>outcomeName</code></td><td valign="top">Localized display name for the selected outcome, e.g. "Over", "Under".</td></tr><tr><td valign="top"><code>odds</code></td><td valign="top">Odds as string, depending on client setup, e.g. "5.0", "4/1".</td></tr><tr><td valign="top"><code>isOutrightMarket</code></td><td valign="top">true - if the selected bet is from an outright market, false - if the selected bet is from a match market.</td></tr><tr><td valign="top"><code>unified</code></td><td valign="top"><p>Contains values used to identify odds from the unified odds feed. It has two fields, <code>marketId</code> and <code>outcomeId</code>.</p><p><br>In case of season outrights the unified object will contain one field, <code>teamid:{teamid}</code>, e.g. <code>teamid:8982005</code>. The field will contain the<br>unified object with the two fields,<br><code>marketId</code> and <code>outcomeId</code>, where <code>outcomeId</code> will contain the competitor <code>sr:competitor:{competitorId}</code>, e.g. <code>sr:competitor:276505</code>.</p></td></tr><tr><td valign="top"><code>validity</code></td><td valign="top">Contains the validity of the bet in ms.</td></tr></tbody></table>

Examples for unified objects:

```json
unified: {
    marketId: 799,
    outcomeId: "13"
}
```

Example for season outright unified objects:

```json
unified: {
    teamid:8982016: {
        marketId: 806,
        outcomeId: "sr:competitor:276516"
    }
}
```

{% hint style="danger" %}
Before accepting a bet, the user's betting selections must be validated on the server-side against markets/odds data sent via Unified Feed.
{% endhint %}

The `betsChanged` callback may be triggered due to several different reasons. The `betsChangedReason` `string` parameter provides context information on the reason why the callback was triggered. It is usually not necessary to use this additional information in typical integration scenarios.

<table><thead><tr><th valign="top">betsChangedReason</th><th>Description</th></tr></thead><tbody><tr><td valign="top"><code>selectionsClicked</code></td><td>The user selected or deselected a bet by clicking on a selection.</td></tr><tr><td valign="top"><code>selectionsRestored</code></td><td>Selections were restored from local storage at initial load (see also <code>persistSelections</code> option).</td></tr><tr><td valign="top"><code>selectionsExpired</code></td><td>Selections were automatically removed due to the corresponding betting period expiring, therefore bets on these selections<br>would no longer be accepted.</td></tr><tr><td valign="top"><code>selectionsDismissedViaAPI</code></td><td>Selections were removed due to a call to the <code>deselectBet()</code> API method (see also <code>deselectBet</code> method description).</td></tr><tr><td valign="top"><code>selectionsConfirmedViaAPI</code></td><td>Selections were removed due to a call to the <code>confirmBet()</code> API method (see also <code>confirmBet</code> method description).</td></tr><tr><td valign="top"><code>selectionsDismissedInBetslip</code></td><td><p>Selections were removed by the user using the embedded betting slip.</p><p></p><p><strong>Used for RGS integrations only.</strong></p></td></tr><tr><td valign="top"><code>selectionsConfirmedInBetslip</code></td><td><p>Selections were removed after the user successfully placed a ticket through the embedded betting slip.</p><p></p><p><strong>Used for RGS integrations only.</strong></p></td></tr><tr><td valign="top"><code>selectionsSuspended</code></td><td>Selections were automatically removed due to the corresponding betting period suspending, therefore bets on these selections would not be accepted until unsuspending.</td></tr><tr><td valign="top"><code>selectionsUnsuspended</code></td><td>Selections were automatically added due to the corresponding betting period unsuspending, therefore bets on these selections<br>would be accepted again.</td></tr></tbody></table>

### `showSlip`

This callback function is called when a user clicks on the 'Confirm bets' button. The customer should hide the `VSM` user interface and show the betting slip. If the user removes bets from the betting slip or confirms the bets in the betting slip, the customer should call `deselectBet` or `confirmBet` on the respective bets, identified by `bet.selectionKey`, so that the state of the bets in the `VSM` user interface reflects the users' actions in the betting slip.

Callback example:

```javascript
function showSlip(vsmInstance, bets) {
    vsmInstance.hide();
    for (var i = 0; i < bets.length; ++i) {
        if (window.confirm("Do you accept the bet (" + bets[i].fixture + " : " + bets[i].marketName + " : " + bets[i].outcomeName + ")?")) {
            vsmInstance.confirmBet(bets[i].selectionKey);
        }
        else {
            vsmInstance.deselectBet(bets[i].selectionKey);
        }
    }
    vsmInstance.show();
};
```

### `roundOddsOverride`

This optional callback function is called when the application is about to display odds for a given round. The callback provides the client with the ability to override the odds values. The client may choose not to override the default odds and not implement this callback function. If the callback function is\
implemented, new odds must be passed to the callback function that is supplied as a parameter to `roundOddsOverride()`.

{% hint style="danger" %}
Overridden odds must be in the same format as they are received in the function's parameter `oddsSuggestions`. Only the odds values may be changed.
{% endhint %}

In the callback example below, an `ajax` request is made. After receiving a response, the odds can be changed, but in the example below the default odds are simply passed back to the application, and therefore no change to the odds values is made.

```javascript
function roundOddsOverride(vsmInstance, roundInfo, oddsSuggestions, callback) {
    jQuery.ajax({
        url: 'http://www.test.com/newRoundOddsJson',
        type: 'GET',
        contentType: 'application/json; charset=utf-8',
        data: {
            sport: roundInfo.sport,
            tournamentId: roundInfo.tournamentId,
            roundNumber: roundInfo.roundNumber
        },
        dataType: 'json',
        error: function(error) {
            console.error(error);
        },
        success: function(data) {
            // implement logic for overriding oddsSuggestion using received data here, e.g.
            for (var i = 0; i < oddsSuggestions.length; ++i) {
                marketId = oddsSuggestions[i].xmlBetId;
                outcomeId = oddsSuggestions[i].betOutcomeId;
                oddsSuggestions[i].odds = data.markets[marketId].outcomes[betOutcomeId];
            }
            // after change is made the provided callback is used to pass new odds
            callback(oddsSuggestions);
        }
    });
}
```

This method can also, for example, be used to convert decimal odds to fractional odds. Here is an example:

```javascript
roundOddsOverride: function(vsmInstance, roundInfo, oddsSuggestions, callback) {
    for (var i = 0; i < oddsSuggestions.length; ++i) {
        if (oddsSuggestions[i].odds < 1) {
            continue;
        }
        var numerator = Math.round(100 * oddsSuggestions[i].odds);
        var denominator = 100;
        for (var j = denominator; j >= 1; --j) {
            if ((numerator % j) == 0 && (denominator % j) == 0) {
                numerator /= j;
                denominator /= j;
                break;
            }
        }
        oddsSuggestions[i].odds = numerator.toString() + "/" + denominator.toString();
    }
    callback(oddsSuggestions);
}
```

### `setEvents`

This callback function is called once every betstop phase. Returns information regarding the current sport.

Callback example:

```javascript
function setEvents(vsmInstance, data) {
    console.log(data);
};
```

The data object has the following properties:

| Property               | Description                                                                                                                                                                                                          |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `screen_name`          | E.g. `mobile-cup` (for VFNC, VFWC, ...) or `mobile-league`  (for VFLM, ...).                                                                                                                                         |
| `sport`                | VFWC, VFNC, ...                                                                                                                                                                                                      |
| `unique_tournament_id` | The unique tournament id.                                                                                                                                                                                            |
| `chunks`               | Array containing chunk objects. This first chunk contains the next events that can be bet on, the second chunk contains the events after that, and so on. Usually 2 entries, but can only 1 during a knockout stage. |

A chunk object has the following properties:

| Property                 | Description                                                                                                 |
| ------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `competition_nr`         | Continuous number of the competition which this event belongs to, as displayed on-screen. Positive integer. |
| `competition_stage_type` | Type of the stage this event belongs to. 'league' (group stage or league mode) or 'cup' (knockout stage).   |
| `eventset_nr`            | Number of the event set (round or match day). Between 1 and 30.                                             |
| `event_ids`              | Array containing the event\_ids (matches) that occur at the same time. Positive integer.                    |

### `maintenanceCallback`

This callback is called when the product is in either `maintenance` or `pause` mode or when that mode is not active anymore. Returns the current instance and an object.

Callback example:

<pre class="language-javascript"><code class="lang-javascript">function maintenanceCallback(vsmInstance, data) {
<strong>    console.log(data);
</strong>};
</code></pre>

The object 'data' has the following properties:

| Property           | Type              | Description                                                                          |
| ------------------ | ----------------- | ------------------------------------------------------------------------------------ |
| `application`      | `string`          | Type of the application. Currently only 'mobile'.                                    |
| `sport`            | `string`          | The sport in `maintenance` or `pause` (e.g. vflm, vfwc, vbl, ...)                    |
| `server_timestamp` | `integer \| null` | The current server timestamp of the response. `null` if no server time is available. |
| `is_maintenance`   | `boolean`         | `true` if the sport is in `maintenance` mode.                                        |
| `is_pause`         | `boolean`         | `true` if the sport is in `pause` mode.                                              |

If both `is_maintenance` and `is_pause` are `false`, then the previous mode (`maintenance` or `pause` ) is not active anymore.

## Plugin instance methods

Instance methods provided by the `VSM` object that is returned at initialization are as follows:

### `getSelector`()

Returns the CSS selector of the container DOM element, where the application is located. It was set in the `init` function as the first parameter.

### `getOptions`()

Returns all effective plugin options that were set on initialization.

### `getLanguage`()

Returns the effective language code.

### `destroy`()

Used to remove the current instance of the application (e.g. when changing language). It stops polling data, removes all UI elements from the DOM, and unloads all JavaScript and CSS assets from the page.

### `show`()

Show application.

### `hide`()

Hide application. This is useful, for example, if you need to show an overlay above the `VSM` application and wish to temporarily hide the application below.

### `isShown`()

Returns `true` if the application is shown.

### `isHidden`()

Returns `true` if the application is hidden.

### `confirmBets`(`selectionKey`)

Used for confirming a betting selection. The selection is identified using the `selectionKey` property of the bet object passed to `showSlip()` and `betsChanged()` callbacks. You may also enumerate all currently selected and still unconfirmed bets using the `getAllSelectedBets()` API function.

### `deselectBet`(`selectionKey`)

Used for deselecting a betting selection in the user interface. The specified selection becomes unselected and will no longer be returned from `getAllSelectedBets()`.

### `getAllSelectedBets`()

Used to retrieve all currently selected (and still unconfirmed) bets.

### `getStatus()`

Returns the current state of the `VSM` instance, as one of the following string values: `INITIALIZING`, `INITIALIZED`, `DESTROYED`.

## RGS integration

The Virtual Sports Suite for Mobile API includes certain options and methods that are specific for customers integrating via Sportradar's Remote Game Server (RGS).&#x20;

These RGS specific parts of the API are described in this section.

### Callbacks

#### `loginRequired`

This callback function is called when user tries to conduct an action that requires an established RGS user session (for example, placing a bet). When this callback occurs you can use the `setUserToken` method to re-authenticate user, same as in the example below. The callback implementation should be\
passed in the `loginRequired` attribute in the widget initialization options.

Callback example:

```javascript
function loginRequired(vsmInstance) {
    console.log('Login required...');
    vsmInstance.setUserToken('USER_TOKEN');
};
```

### Methods

#### `setUserToken`(`userToken`)

Sets the user token which can be used to authenticate with the RGS server.

#### `setCurrency`(`currencyCode, currencyLabel, decimalPlaces, defaultStake`)

Sets the currency configuration to be used in the application (specified currency must be supported and configured on the RGS server side).

<table><thead><tr><th valign="top">Property</th><th valign="top">Description</th></tr></thead><tbody><tr><td valign="top"><code>currencyCode</code></td><td valign="top">3 digit currency code (eur, usd).</td></tr><tr><td valign="top"><code>currencyLabel</code></td><td valign="top">Currency label string (€, Eur, $, Usd).</td></tr><tr><td valign="top"><code>decimalPlaces</code></td><td valign="top">Number of decimal places for the entered stakes.</td></tr><tr><td valign="top"><code>defaultStake</code></td><td valign="top">Default stake automatically entered when user clicks on the stake field.</td></tr></tbody></table>

### Implementing a custom betting slip with RGS

This section describes methods that may be used in order to implement your own betting slip when integrating through the RGS. In this scenario, your betting slip implementation should use the API methods described in this section in order to validate and place bets with the RGS.

#### `getUserAccountInfo`(`callback`)

Retrieves the RGS user account info from the RGS server. You need to supply a callback function which will be executed after the request is processed. A response, with the following object structure, will be served in the callback function:

```json
{
    success: true,
    errors: [],
    data: {
        balance: 500000131609.15, // user account balance
        currency: "eur", // default user currency
        language: "en", // default user language
        username: "sportradar1" // username
    }
}
```

Example usage:

```javascript
instance.getUserAccountInfo(function(response) {
    if (response.success) {
    console.log(response.data);
    }
});
```

#### `getLimits`(`callback`)

Retrieves the bookmaker limits configured by the RGS server. You need to supply a callback function which will be executed after the request is processed. A response, with the following object structure, will be served in the callback function:

```json
{
    success: true,
    errors: [],
    data: {
        defaultCurrency: "eur", // default bookmaker currency
        defaultLanguage: "en", // default bookmaker language
        maxLinesPerTicket: 9, // maximum number of lines allowed per bet ticket
        minLinesPerTicket: 1, // minimum number of lines allowed per bet ticket
        perCurrencyLimits: { // currency specific settings
            eur: {
                maxPerBetStake: 1000, // maximum stake per bet
                maxWinMulti: 9999999, // maximum winning amount for 'multibet' system
                maxWinSingle: 9999999, // maximum winning amount for signle system
                minPerBetStake: 1 // minimum stake per bet
            },
            usd: {
                maxPerBetStake: 1000,
                maxWinMulti: 9999999,
                maxWinSingle: 9999999,
                minPerBetStake: 1
            }
        },
        supportedCurrencies: { // the list of bookmakers supported currencies
            0: 'eur',
            1: 'usd'
        }
    }
}
```

Example usage:

```javascript
instance.getLimits(function(response) {
    if (response.success) {
        console.log(response.data);
    }
});
```

#### `getSystems`(`callback`)

Retrieves the list of RGS supported bet types for the currently selected bets. You need to supply a callback function which will be executed after the request is processed. A response, with the following object structure, will be served in the callback function:

```json
{
    success: true,
    errors: [],
    data: {
        systems: {
            0: {
                betType: "single" // bet type 'signle' - individual bet for each ticket line (bet selection)
                noOfBets: 4, // number of bets to be placed by this type of bet
                systemType: undefined
            },
            1: {
                betType: "multibet" // bet type 'multibet' - single bet for the whole ticket
                noOfBets: 1, // number of bets to be placed by this type of bet
                systemType: undefined
            },
            2: {
                betType: "system" // bet type 'system' - combination of bets pet ticket (in this case 2 of 4)
                noOfBets: 6 // number of bets to be placed by this type of bet
                systemType: 2 // type of the system bet (in this case 2 of 4)
            },
            3: {
                betType: "system" // bet type 'system' - combination of bets pet ticket (in this case 3 of 4)
                noOfBets: 4 // number of bets to be placed by this type of bet
                systemType: 3 // type of the system bet (in this case 3 of 4)
            },
            ...
        }
    }
}
```

Example usage:

```javascript
instance.getSystems(function(response) {
    if (response.success) {
        console.log(response.data);
    }
});
```

Systems can contain one or more of the following betting options:

<table><thead><tr><th valign="top">Bet Type</th><th valign="top">Bet System</th><th valign="top">Description</th></tr></thead><tbody><tr><td valign="top"><code>single</code></td><td valign="top">undefined</td><td valign="top">A bet on an individual  selection or outcome.</td></tr><tr><td valign="top"><code>multibet</code></td><td valign="top">undefined</td><td valign="top">A linked series of win singles where the return from the first selection is automatically staked on the second selection as a win single and so on until all selections have won, thus giving a return, or until one selection loses in which case the whole bet is lost.</td></tr><tr><td valign="top"><code>system</code></td><td valign="top">-4</td><td valign="top">Full cover bet with singles. A wager consisting of all possible singles, doubles, trebles, and accumulators across a given number of selections.</td></tr><tr><td valign="top"><code>system</code></td><td valign="top">-3</td><td valign="top">Full cover bet. A wager consisting of all possible doubles, trebles, and accumulators across a given number of selections.</td></tr><tr><td valign="top"><code>system</code></td><td valign="top">2</td><td valign="top">A bet on two selections; both of which must win to gain a return.</td></tr><tr><td valign="top"><code>system</code></td><td valign="top">3</td><td valign="top">A bet on three selections; all three of which must win to gain a return.</td></tr><tr><td valign="top"><code>system</code></td><td valign="top">4 or higher</td><td valign="top">Accumulator. A bet on four or more selections; all of which must win to gain a return. Accumulators are often named after the number of selections they contain - thus we can get a fourfold, fivefold or sixfold accumulator (or even higher).</td></tr></tbody></table>

#### `validateTickets`(`tickets, calback`)

Validates the requested tickets (selected bet types) with the RGS and returns odds and possible winnings for the currently selected bets. You need to pass in betting options and a callback function which will be executed after the request is processed. The `tickets` parameter must be an object prepared as specified in this example:

```json
{
    currencyCode: 'eur', // currency code to be used by RGS to prepare the ticket validation / calculations
    bets: [{ // array of selected bet types
        betType: 'single', // bet type - one of the betting options returned by getSystems function
        stake: 1.00 // stake for this bet type
    }, { // array of selected bet types
        betType: 'multibet',
        stake: 1.50
    }, {
        betType: 'system',
        systemType: 3, // system type must be provided if the bet type is set to
        'system'
        stake: 2.00
    }]
}
```

Here you can see, that we are setting stakes for three bet types. You can use any of the betting options returned by the `getSystems` method.

A response, with the following object structure, will be served in the callback function:

```json
{
    success: true,
    errors: [],
    data: {
        balance: 500000131573.65, // user account balance before the transaction
        currency: "eur", // betslip currency
        totalPossibleWinning: 388.13453875000005, // total possible winning
        totalStake: 47.5, // total stake
        bets: [{
            betType: "single", // bet type
            systemType: undefined, // system type
            currency: "eur", // bet currency
            perBetStake: 0, // per bet stake
            possibleWinning: 11.2, // possible winning for this bet type
            possibleWinningTax: Object, // additional tax info if needed
            stakeTax: Object, // additional tax info if needed
            ticketStake: 6, // ticket stake for this bet type
            ticketStakeType: "per_line" // ticket stake type for this bet type
        }, {
            betType: "multibet",
            currency: "eur",
            perBetStake: 0,
            possibleWinning: 55.84,
            possibleWinningTax: Object,
            stakeTax: Object,
            ticketStake: 1.5,
            ticketStakeType: "total"
        }, {
            betType: "system",
            systemType: 3,
            currency: "eur",
            perBetStake: 2,
            possibleWinning: 254.05,
            possibleWinningTax: Object,
            stakeTax: Object,
            ticketStake: 40,
            ticketStakeType: "per_bet"
        }]
    }
}
```

Example usage:

```javascript
var tickets = {
    currencyCode: 'eur',
    bets: [{
        betType: 'single',
        stake: 1.00
    }, {
        betType: 'multibet',
        stake: 1.50
    }, {
        betType: 'system',
        systemType: 3,
        stake: 2.00
    }]
};
    
instance.validateTickets(tickets, function(response) {
    if (response.success) {
        console.log('Validation OK', response.data);
    }
});
```

#### `placeTickets`(`tickets, callback`)

Places the requested tickets (selected bet types) for the currently selected bets. You need to pass in betting options and a callback function which will be executed after the request is processed. The `tickets` parameter must be an object prepared as specified in this example (the same object as in the\
`validateTickets` example):

```json
{
    currencyCode: 'eur', // currency code to be used by RGS to prepare the ticket validation / calculations
    bets: [{ // array of selected bet types
        betType: 'single', // bet type - one of the betting options returned by getSystems function
        stake: 1.00 // stake for this bet type
    }, { // array of selected bet types
        betType: 'multibet',
        stake: 1.50
    }, {
        betType: 'system',
        systemType: 3, // system type must be provided if the bet type is set to 'system'
        stake: 2.00
    }]
}
```

Here you can see, that we are setting stakes for three bet types. You can use any of the betting options returned by the `getSystems` method.

A response, with the following object structure, will be served in the callback function:

```json
{
    success: true,
    errors: [],
    data: {
        bets: [{
            ticketId: '56e7ffcc60b2d65423c933e5', // id of the betting ticket
            betType: "single" // bet type
            systemType: undefined // system type
            status: "placed" // ticket status
        }, {
            ticketId: '56e7ffcc60b2d65423c933e5', // id of the betting ticket
            betType: "multibet"
            systemType: undefined
            status: "placed"
        }, {
            ticketId: '56e7ffcc60b2d65423c933e5', // id of the betting ticket
            betType: "system"
            systemType: 3
            status: "placed"
        }]
    }
}
```

Example usage:

```javascript
var tickets = {
    currencyCode: 'eur',
    bets: [{
        betType: 'single',
        stake: 1.00
    }, {
        betType: 'multibet',
        stake: 1.50
    }, {
        betType: 'system',
        systemType: 3,
        stake: 2.00
    }]
};

instance.placeTickets(tickets, function(response) {
    if (response.success) {
        for (var i = 0; i < response.data.bets.length; i++) {
            var bet = response.data.bets[i];
            console.log(bet.status === 'placed' ? 'Bet placed' : 'Bet place failed', bet);
        }
        console.log('Ticket placed.', response.data);
    }
});
```

{% hint style="warning" %}
**IMPORTANT**: In the placement phase, it can happen, that two of the total three bets get successfully placed and the third one fails due to, for example, insufficient funds.&#x20;

It is important to always check the status of all bets in the placement response.
{% endhint %}

Here is the list of possible statuses:

<table><thead><tr><th valign="top">Status</th><th valign="top">Description</th></tr></thead><tbody><tr><td valign="top">placed</td><td valign="top">Ticket placed.</td></tr><tr><td valign="top">rejected_basic_validation</td><td valign="top">Ticket rejected - e.g. invalid #lines, missing fields, bet stake limits, etc.</td></tr><tr><td valign="top">rejected_calc_validation</td><td valign="top">Ticket rejected - single / multi / system calculation failed.</td></tr><tr><td valign="top">rejected_risk_validation</td><td valign="top">Ticket rejected - risk / liability threshold breached.</td></tr><tr><td valign="top">rejected_market_validation</td><td valign="top">Ticket rejected - e.g. markets closed, prices changed.</td></tr><tr><td valign="top">rejected_insufficient_funds</td><td valign="top">Ticket rejected - stake failed.</td></tr><tr><td valign="top">rejected_user_is_disabled</td><td valign="top">User account is disabled.</td></tr><tr><td valign="top">rejected_user_not_authenticated</td><td valign="top">User is not authenticated.</td></tr><tr><td valign="top">rejected_user_not_authorized</td><td valign="top">User is not authorized.</td></tr><tr><td valign="top">rejected_user_session_expired</td><td valign="top">User session has expired.</td></tr><tr><td valign="top">rejected_user_blocked</td><td valign="top">User is blocked.</td></tr><tr><td valign="top">rejected_risk_user_identified</td><td valign="top">Risk user identified.</td></tr><tr><td valign="top">internal_error</td><td valign="top">Internal system error while processing a ticket.</td></tr><tr><td valign="top">external_error</td><td valign="top">External / Integrations system error while processing a ticket.</td></tr></tbody></table>

### RGS errors

The requests that communicate with the RGS server for ticket validation and placement will always have the response structured in the following way:

```json
{
    success: true, // wether the response was executed without errors
    errors: [], // the list of errors
    data: {} // data object
}
```

Possible requests are:

* `getUserAccountInfo`
* `getLimits`
* `getSystems`
* `validateTickets`
* `placeTickets`

If the `success` property is set to `false`, the list of errors will be written in the `errors` property. Each error contains an error code, an error message and a `selectionId` if the error is related to a specific betting selection.&#x20;

Example:

```json
{
    success: true,
    errors: [{
        errorCode: 1001, // error code
        errorMessage: "Authentication failed.", // error description
        selectionId: undefined // selection id if the error is related to the particular line in the betslip
    }],
    data: {}
}
```

Possible error codes are:

<table><thead><tr><th valign="top">Code</th><th valign="top">Description</th></tr></thead><tbody><tr><td valign="top">1001</td><td valign="top">User is not authenticated.</td></tr><tr><td valign="top">1002</td><td valign="top">No bets were selected.</td></tr><tr><td valign="top">1003</td><td valign="top">No bets were provided to the validate or place bets function.</td></tr><tr><td valign="top">1004</td><td valign="top">Unknown bet type sent to validate or place bets function.</td></tr><tr><td valign="top">10001</td><td valign="top">Missing currency code.</td></tr><tr><td valign="top">10002</td><td valign="top">Invalid or unsupported currency.</td></tr><tr><td valign="top">10003</td><td valign="top">Bet stake is too low.</td></tr><tr><td valign="top">10004</td><td valign="top">Bet stake is too high.</td></tr><tr><td valign="top">10005</td><td valign="top">The win for the single bet type is too high.</td></tr><tr><td valign="top">10006</td><td valign="top">The win for the system bet type is too high.</td></tr><tr><td valign="top">10007</td><td valign="top">Insufficient balance.</td></tr><tr><td valign="top">10008</td><td valign="top">Too few lines in the betting ticket.</td></tr><tr><td valign="top">10009</td><td valign="top">Too many lines per betting ticket.</td></tr></tbody></table>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sportradar.com/games/virtual-sports/virtual-sports-via-unified-odds-feed-uof/frontend-integration/mobile-integration/virtual-sports-suite-for-mobile-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
