Betslip Command Bus
betslipApi is a singleton command bus that lets any code — including code that runs before the <Betslip /> widget mounts — add or remove selections programmatically and read the current betslip state.
For the widget itself, see the Betslip component page.
Import
import { betslipApi } from "fansunited-frontend-components";
import type { BetslipState } from "fansunited-frontend-components";Important: Always import
betslipApifromfansunited-frontend-components, not fromfansunited-frontend-core. The Betslip widget bundles its own copy of the command bus; importing from the components package guarantees you use the same singleton instance the widget is listening on.
API
setSelection(selectionId: string): void
setSelection(selectionId: string): voidAdd a selection. If the same eventId + market already exists, the outcome is replaced (upsert behavior — no need to remove first).
betslipApi.setSelection("fb:m:451678:FT_1X2:1");removeSelection(selectionId: string): void
removeSelection(selectionId: string): voidRemove a selection by its exact id. No-op if the selection is not present.
betslipApi.removeSelection("fb:m:451678:FT_1X2:1");getState(): BetslipState
getState(): BetslipStateOne-shot snapshot — returns the last known state immediately.
const { selections, stake, totalOdds } = betslipApi.getState();subscribe(listener): () => void
subscribe(listener): () => voidReactive subscription — fires whenever selections, stake, or odds change. Returns an unsubscribe function.
const unsubscribe = betslipApi.subscribe((state: BetslipState) => {
console.log("selections:", state.selections.length);
console.log("stake:", state.stake);
console.log("totalOdds:", state.totalOdds);
});
// Stop receiving updates
unsubscribe();BetslipState shape
BetslipState shapeinterface BetslipState {
selections: BetslipSelectionInput[]; // current raw selections
stake: number; // parsed numeric stake (0 when empty)
totalOdds: number; // product of all selection decimal odds (0 when none)
}Selection ID format
"{eventId}:{market}:{outcome}"
| Segment | Examples |
|---|---|
eventId | fb:m:451678 |
market | FT_1X2, DOUBLE_CHANCE, OVER_GOALS_2_5, CORRECT_SCORE, PLAYER_SCORE_FIRST_GOAL |
outcome | 1 (home), x (draw), 2 (away), 1x, yes, no, 1-2 (correct score) |
Over/Under markets: Use "yes" for Over and "no" for Under (not "over"/"under").
Correct Score market: Outcomes use hyphen notation, e.g. "1-2". The widget also accepts colons.
Pre-mount queuing
Calls to setSelection made before the <Betslip /> component has mounted are queued and automatically replayed once the widget initializes. There is no need to delay external code to wait for the widget.
import { betslipApi } from "fansunited-frontend-components";
// Safe to call before <Betslip /> is rendered
betslipApi.setSelection("fb:m:451678:FT_1X2:1");
// Later, when <Betslip /> mounts, it receives the queued selection
ReactDOM.render(<Betslip sdk={sdk} language="en" />, root);Typical integration pattern
// 1. Render the Betslip widget once at app root level
<Betslip sdk={sdk} language="en" />
// 2. From anywhere in your app — e.g. a match card — call betslipApi
import { betslipApi } from "fansunited-frontend-components";
function MatchCard({ eventId, market, outcome }) {
const selectionId = `${eventId}:${market}:${outcome}`;
return (
<button onClick={() => betslipApi.setSelection(selectionId)}>
Add to Betslip
</button>
);
}Use cases for subscribe
subscribe- Syncing a "selection count" badge somewhere else in your app's chrome.
- Enabling/disabling a custom CTA based on the current selection state.
- Forwarding stake changes to your own backend for analytics.
- Persisting the betslip state across page navigations.
const unsubscribe = betslipApi.subscribe((state) => {
document.title = state.selections.length > 0
? `(${state.selections.length}) Your bet — MySite`
: "MySite";
});