By completing this tutorial, you will:
tickets adapter endpointtickets endpoint that retrieves and transforms user bet dataBetShareResponse type specificationBefore implementing the tickets endpoint, ensure you have:
The tickets endpoint is one of several adapter endpoints. Implement additional endpoints (event, eventMarkets, availableMarketsForEvent, etc.) as needed for your widget features.
The tickets endpoint retrieves a user's bet history and returns it in the BetShareResponse format. This endpoint enables features like bet sharing and bet copying in Virtual Stadium widgets.
The endpoint receives request arguments including the customer ID, optional event filters, and pagination data. Your implementation should:
BetSlip formatFor the frontend implementation that allows users to interact with and copy bets in the UI, see the Copy Bet Button documentation.
First, register your adapter with the SIR global function before adding any widgets. Ensure only one adapter is registered per page load.
const adapter = {
endpoints: {
// Your endpoints will go here
}
};
SIR('registerAdapter', adapter);Add the tickets endpoint handler to your adapter. This function receives request arguments and a callback to return results.
const adapter = {
endpoints: {
// NOTE: The `tickets` endpoint is one of several adapter endpoints.
// Implement additional endpoints (event, eventMarkets, availableMarketsForEvent, etc.)
// as documented in the Adapter Types documentation based on your widget requirements.
tickets: (args, callback) => {
// Implementation continues below
}
}
};Request Parameters (args):
endCustomerId (string) — The user's unique identifierevents (SelectionEvent[], optional) — Events to filter tickets bypage (number, optional) — Page number for paginationuseCashOut (boolean, optional) — Include cash out informationRetrieve user bets from your backend system and apply filtering based on request arguments.
tickets: (args, callback) => {
// Fetch user's bets from your backend API or tickets system
fetchUserBets(args.endCustomerId, (error, allBets) => {
if (error) {
return callback(error);
}
let filteredBets = allBets;
// Filter by events if provided
if (args.events && args.events.length > 0) {
const eventIds = args.events.map(event => event.event); // event is the id in SelectionEvent
filteredBets = filteredBets.filter(bet =>
bet.bets.some(betItem => eventIds.includes(betItem.event.id))
);
}
// Note: exclusion of already shared bets should be done on the client side
// or via your custom logic, as it's not a standard property of TicketsRequest
// Continue to Step 4
});
}Transform your bet data into the BetSlip format (part of BetShareResponse) and invoke the callback with the formatted response.
tickets: (args, callback) => {
fetchUserBets(args.endCustomerId, (error, allBets) => {
if (error) {
return callback(error);
}
let filteredBets = allBets;
if (args.events && args.events.length > 0) {
const eventIds = args.events.map(event => event.event);
filteredBets = filteredBets.filter(bet =>
bet.bets.some(betItem => eventIds.includes(betItem.event.id))
);
}
// Transform your bet data into the BetSlip format (BetShareResponse).
// The callback returns: { bets: BetSlip[] } — the BetShareResponse type.
const bets = filteredBets.map(bet => ({
id: bet.id || 'sr:bet-share-event:single',
betSlipId: bet.betSlipId || bet.id || 'sr:bet-share-event:single',
betType: bet.betType || 'single',
currency: bet.currency || 'USD',
combinedOdds: bet.combinedOdds || {
decimalValue: bet.odds?.decimalValue || 2.55,
displayValue: String(bet.odds?.decimalValue || 2.55)
},
stake: bet.stake || { value: '50.00' },
payout: bet.payout || { value: String((bet.odds?.decimalValue || 2.55) * parseFloat(bet.stake?.value || '50.00')) },
cashOut: bet.cashOut || { value: '0.00' },
bets: bet.bets || []
}));
// Return formatted response to the widget
callback(undefined, { bets });
});
// Return cleanup function for any subscriptions or listeners created in fetchUserBets
return () => {
// Unsubscribe from data sources or clean up any resources allocated during fetchUserBets
// Example: if fetchUserBets opened a database connection or subscribed to updates,
// this cleanup function should close/unsubscribe to prevent memory leaks
};
}The response must conform to the BetShareResponse type: { bets: BetSlip[] }
| Property | Type | Description |
|---|---|---|
id | string | Unique identifier for the bet (required) |
betSlipId | string | Optional secondary identifier for client-side matching |
betType | string | Bet type (e.g., "single", "multibet") |
currency | string | Currency code (e.g., "USD") |
combinedOdds | { decimalValue: number; displayValue: string } | Combined odds for the bet |
stake | { value: string } | Stake amount as a string |
payout | { value: string } | Potential payout as a string |
cashOut | { value: string } | Cash out value as a string |
bets | Bet[] | Array of bets within the slip (market, outcome, event details) |
The response object must include the bets property and not include a tickets property. The BetShareResponse type explicitly excludes tickets (defined as tickets?: never).