Bifrost API Reference
Source: BFST-Bifrost API Public Documentation (2026-03-06)
1. Sports Identifiers
| Sport Name | Sport ID |
|---|---|
| FOOTBALL | 1 |
| CRICKET | 2 |
| KABADDI | 19 |
2. Queue Architecture
All queue names are prefixed with {customerPrefix} — the customer's unique prefix assigned by Bifrost.
2.1 Outbound Queues (from Bifrost to customer)
| Queue Name | Produces | Description |
|---|---|---|
{customerPrefix}.category.queue | Category | Messages containing category (Country or Competition) details. |
{customerPrefix}.event.queue | Event | Messages containing full event details. Upon arrival, it should fully override the existing snapshot after version check. |
{customerPrefix}.market-catalogue.queue | MarketCatalogue | Messages containing full market static details. Upon arrival, it should override the existing snapshot after the version check. |
{customerPrefix}.market-book.queue | MarketBook | Messages containing full market dynamic details. Upon arrival, it should override the existing snapshot after the version check. |
2.2 Broker Data Queues (bet lifecycle)
Bets (single bets)
| Queue Name | Produces | Description |
|---|---|---|
{customerPrefix}.bets.snapshot.queue | BetSnapshot | Messages containing the Bet holding the current state of the bet. Covers: acceptance, rejections, voiding, size matching and cancellation. Upon arrival, fully override the existing snapshot after the version check. |
{customerPrefix}.bets.cancel.queue | BetSnapshot | Messages containing cancelled bet. Upon arrival, should fully override existing snapshot after version check. |
Multibets
| Queue Name | Produces | Description |
|---|---|---|
{customerPrefix}.bets.multi-bet.snapshot.queue | MultiBetSnapshot | Messages containing the Multibet holding the current state of the bet. Covers: acceptance, rejections, voiding. Upon arrival, fully override the existing snapshot after the version check. |
{customerPrefix}.bets.multi-bet.outcomes.queue | MultiBetOutcome | Messages containing full bet outcome snapshot. Upon arrival, should fully override existing snapshot after version check. |
{customerPrefix}.bets.multi-bet.price.queue | MultibetPriceBetSnapshot | Messages containing multibet price response. |
Bet Outcomes (settlement)
| Queue Name | Produces | Description |
|---|---|---|
{customerPrefix}.bets.outcomes.queue | BetOutcome | Messages containing full bet outcome snapshot. Upon arrival, should fully override existing snapshot after version check. |
3. Outbound Data Structures
3.1 Category
Queue: {customerPrefix}.category.queue
Routing patterns:
customerPrefix— customer unique prefix
Model
| Field | Data Type | Description |
|---|---|---|
| id | string | Category id |
| parentId | string | Link to parent. Category should be treated as a hierarchy. |
| categoryType | string | Type of category. e.g. 'Country' or 'Competition' |
| value | string | Name of category. e.g. Country (England), Competition (Premier League) |
| sportId | string | Sport Id |
Proto
message Category {
string id = 1;
string parentId = 2;
string categoryType = 3;
string value = 4;
string sportId = 5;
}
3.2 Event
Queue: {customerPrefix}.event.queue
Routing patterns:
customerPrefix— customer unique prefix
Upon arrival, it should fully override the existing snapshot after version check.
Event Model
| Field | Data Type | Description |
|---|---|---|
| eventId | string | A unique id for the event. |
| name | string | A display name for the event. |
| startTime | string | The event start time in UTC zone. E.g. '2025-05-06T18:00' |
| sportId | string | Sport id |
| categoryId | string | The category/competition reference |
| competitors | Competitor[] | A list of competitors that are involved in this event. |
| externalIds | EventMapping[] | A possibly empty list of other providers event ids. The list may change at any time as no mapping should be assumed as static nor unique. Example providers: Betfair, Sportradar. |
| status | string | Event status enum. One of: CANCELLED — the game was cancelled; POSTPONED — the game was postponed. |
| version | long | Version of event. This can be used for deduplication and ordering of updates downstream. |
Event Proto
message Event {
string eventId = 1;
string name = 2;
string startTime = 3;
string categoryId = 4;
repeated Competitor competitors = 5;
repeated EventMapping externalIds = 6;
string status = 7;
int64 version = 8;
string sportId = 9;
}
EventMapping Model
| Field | Data Type | Description |
|---|---|---|
| provider | string | Provider of the id e.g. Betfair |
| eventId | string | The id of the event for the provider. |
EventMapping Proto
message EventMapping {
string provider = 1;
string eventId = 2;
}
3.3 Competitor / Team
Model
| Field | Data Type | Description |
|---|---|---|
| id | string | Competitor id |
| shortName | string | Competitor short name. e.g. 'ENG' |
| fullName | string | Competitor full name. e.g. 'England' |
Proto
message Competitor {
string id = 1;
string shortName = 2;
string fullName = 3;
}
3.4 MarketCatalogue
Queue: {customerPrefix}.market-catalogue.queue
Routing patterns:
customerPrefix— customer unique prefix
Messages containing full market static details. Upon arrival, it should override the existing snapshot after the version check.
MarketCatalogue Model
| Field | Data Type | Description |
|---|---|---|
| id | string | The unique id of the market. |
| eventId | string | The id of the event. |
| marketType | string | The market type. |
| oddsType | string | Odds type. |
| name | string | The market name. |
| startTime | string | The market start time. |
| prematchOnly | boolean | Boolean flag indicating whether the market will be open during prematch only or will go live on game start. |
| sortOrder | long | Recommended sort order of the market. |
| runners | RunnerCatalogue[] | The set of betable selections on the market. |
| metadata | MarketMetadata | The market metadata. |
| version | long | Version of market. This can be used for deduplication and ordering of updates downstream. |
| sportId | string | The id of the sport. |
| tradingMarketType | string | Original market type (from Bifrost trading system internals). |
MarketCatalogue Proto
message MarketCatalogue {
string id = 1;
string eventId = 2;
string marketType = 3;
string name = 4;
string startTime = 5;
string oddsType = 6;
bool prematchOnly = 7;
int64 sortOrder = 8;
repeated RunnerCatalogue runner = 9;
MarketMetadata metadata = 10;
int64 version = 11;
string sportId = 12;
string tradingMarketType = 13;
}
RunnerCatalogue Model
| Field | Data Type | Description |
|---|---|---|
| id | long | The id of the runner. |
| name | string | The name of the runner. |
| sortPriority | integer | The recommended positional order of the selection when being displayed. |
| metadata | map<String, String> | The metadata of the runner. |
RunnerCatalogue Proto
message RunnerCatalogue {
int64 id = 1;
string name = 2;
int32 sortPriority = 3;
map<string, string> metadata = 4;
}
MarketMetadata Model
| Field | Data Type | Description |
|---|---|---|
| competitors | MarketCompetitorMetadata | Market competitors metadata. |
MarketMetadata Proto
message MarketMetadata {
repeated MarketCompetitorMetadata competitor = 1;
}
MarketCompetitorMetadata Model
| Field | Data Type | Description |
|---|---|---|
| name | string | Market competitor full name. |
| shortName | string | Market competitor short name. |
MarketCompetitorMetadata Proto
message MarketCompetitorMetadata {
string name = 1;
string shortName = 2;
}
3.5 MarketBook
Queue: {customerPrefix}.market-book.queue
Routing patterns:
customerPrefix— customer unique prefix
Messages containing full market dynamic details. Upon arrival, it should override the existing snapshot after the version check.
MarketBook Model
| Field | Data Type | Description |
|---|---|---|
| marketId | string | The unique id of the market. |
| marketStatus | string | The status of the market. One of: INACTIVE, OPEN, BALL_RUNNING, SUSPENDED, CLOSED, SETTLED. Note: BALL_RUNNING is currently supported but is planned for deprecation. |
| maxMarket | double | Max market liability per b2b client member in HKD. |
| maxMarketCurrencies | map<string, double> | Max market liability per b2b client member in provided currencies. |
| runners | Runner[] | The set of betable selections on the market. |
| variables | map<string, string> | The market variables. |
| version | Long | The version of market. This can be used for deduplication and ordering of updates downstream. |
| sportId | string | The id of the sport. |
| minStake | double (optional) | Minimum stake. |
| minStakeCurrencies | map<string, double> | Minimum stake in provided currencies. |
| tradingMarketType | string | Original market type (from Bifrost trading system internals). |
| oddsType | string | The odds type, one of: HAAR_JEET, DECIMAL. Authoritative pricing format — use this field (not MarketCatalogue.oddsType) to determine how to interpret runner prices. |
marketStatus Values
| Value | Meaning |
|---|---|
INACTIVE | Market is not available for bet placement. |
OPEN | Market is available for bet placement. |
BALL_RUNNING | Market is currently in ball-running state. Currently supported but planned for deprecation. |
SUSPENDED | Market is not available for bet placement. |
CLOSED | Market is not available for bet placement. |
SETTLED | Market is fully settled. |
MarketBook Proto
message MarketBook {
string marketId = 1;
string marketStatus = 2;
double maxMarket = 3;
map<string, double> maxMarketCurrencies = 4;
repeated Runner runner = 5;
map<string, string> variables = 6;
int64 version = 7;
string sportId = 8;
optional double minStake = 9;
map<string, double> minStakeCurrencies = 10;
string tradingMarketType = 11;
string oddsType = 12;
}
3.6 Runner / RunnerPriceLadder / RunnerPriceSize
Runner Model
| Field | Data Type | Description |
|---|---|---|
| id | string | The id of the runner that should be provided when placing a bet. |
| status | string | The bettable status of the runner. |
| priceLadder | RunnerPriceLadder | The prices ladder of the runner. |
| version | long | The runner version. |
Runner Proto
message Runner {
int64 id = 1;
string status = 2;
RunnerPriceLadder priceLadder = 3;
int64 version = 4;
}
RunnerPriceLadder Model
| Field | Data Type | Description |
|---|---|---|
| availableToBack | RunnerPriceSize[] | The available BACK prices and available max stake to bet at that price. |
| availableToLay | RunnerPriceSize[] | The available LAY prices and available max stake to bet at that price. Only populated for exchange markets. |
RunnerPriceLadder Proto
message RunnerPriceLadder {
repeated RunnerPriceSize availableToBack = 1;
repeated RunnerPriceSize availableToLay = 2;
}
RunnerPriceSize Model
| Field | Data Type | Description |
|---|---|---|
| price | double | The price at which this runner can be bettable by customer. |
| midPrice | double | The mid price. |
| size | double | (field 3 in proto) |
| line | double | The runner line. |
| midLine | double | The runner mid line. |
| priceIndex | integer | The position order of the line. |
| maxStake | double | The maximum stake size of a bet at this price. |
| maxStakeCurrencies | map<string, double> | The maximum stake size of a bet at this price in provided currencies. |
RunnerPriceSize Proto
message RunnerPriceSize {
double price = 1;
double midPrice = 2;
double size = 3;
double line = 4;
double midLine = 5;
int32 priceIndex = 6;
double maxStake = 7;
map<string, double> maxStakeCurrencies = 8;
}
3.7 FootballStatistics
Note: Football-specific live statistics message.
FootballStatistics Model
| Field | Type | Description |
|---|---|---|
| eventId | String | Unique identifier for the event |
| matchPhase | String | Current phase of the match |
| phaseMinute | Integer | Minute within the current phase |
| homeTeamName | String | Name of the home team |
| awayTeamName | String | Name of the away team |
| goalsHalfTime | StateStatistic | Goals scored by half-time |
| goalsFullTime | StateStatistic | Goals scored by full-time |
| goalsOvertimeHalfTime | StateStatistic | Goals scored by overtime half-time |
| goalsOvertimeFullTime | StateStatistic | Goals scored by overtime full-time |
| goalsPenaltyKicks | StateStatistic | Goals scored by penalty kicks |
| cornersHalfTime | StateStatistic | Corners taken by half-time |
| cornersFullTime | StateStatistic | Corners taken by full-time |
| cornersOvertimeHalfTime | StateStatistic | Corners taken by overtime half-time |
| cornersOvertimeFullTime | StateStatistic | Corners taken by overtime full-time |
| yellowCardsHalfTime | StateStatistic | Yellow cards by half-time |
| yellowCardsFullTime | StateStatistic | Yellow cards by full-time |
| yellowCardsOvertimeHalfTime | StateStatistic | Yellow cards by overtime half-time |
| yellowCardsOvertimeFullTime | StateStatistic | Yellow cards by overtime full-time |
| redCardsHalfTime | StateStatistic | Red cards by half-time |
| redCardsFullTime | StateStatistic | Red cards by full-time |
| redCardsOvertimeHalfTime | StateStatistic | Red cards by overtime half-time |
| redCardsOvertimeFullTime | StateStatistic | Red cards by overtime full-time |
FootballStatistics Proto
message FootballStatistics {
string eventId = 1;
string matchPhase = 3;
int32 phaseMinute = 4;
string homeTeamName = 5;
string awayTeamName = 6;
StateStatistic goalsHalfTime = 7;
StateStatistic goalsFullTime = 8;
StateStatistic goalsOvertimeHalfTime = 9;
StateStatistic goalsOvertimeFullTime = 10;
StateStatistic goalsPenaltyKicks = 11;
StateStatistic cornersHalfTime = 12;
StateStatistic cornersFullTime = 13;
StateStatistic cornersOvertimeHalfTime = 14;
StateStatistic cornersOvertimeFullTime = 15;
StateStatistic yellowCardsHalfTime = 16;
StateStatistic yellowCardsFullTime = 17;
StateStatistic yellowCardsOvertimeHalfTime = 18;
StateStatistic yellowCardsOvertimeFullTime = 19;
StateStatistic redCardsHalfTime = 20;
StateStatistic redCardsFullTime = 21;
StateStatistic redCardsOvertimeHalfTime = 22;
StateStatistic redCardsOvertimeFullTime = 23;
}
StateStatistic Model
| Field | Type | Description |
|---|---|---|
| home | String | Statistic for the home team |
| away | String | Statistic for the away team |
StateStatistic Proto
message StateStatistic {
int32 home = 1;
int32 away = 2;
}
3.8 BetSnapshot
Queue: {customerPrefix}.bets.snapshot.queue
Covers: acceptance, rejections, voiding, size matching and cancellation.
BetSnapshot Model
| Field | Data Type | Required | Description |
|---|---|---|---|
| requestId | String | Yes | A request unique identifier. It could be generated on the customer side. |
| betId | Long | Yes | Unique identifier for the placed bet. Generated on Public API level. |
| memberCode | String | Yes | Code identifying the member placing the bet. |
| status | String | Yes | Bet status enum. One of: PENDING — the bet placement request has been sent, waiting for provider's response; FAILED — the bet placement has failed; PLACED — the bet was successfully placed (fully matched); VOIDED — the bet was voided by the provider/operator; PARTIALLY_MATCHED — part of the bet has been matched, the rest is waiting in the market; UNMATCHED — the bet is in the market but has not been matched yet; CANCEL_PENDING — the client requested to cancel the bet (or remaining part), but the provider has not yet confirmed the cancellation; CANCELLED — the bet (or its unmatched portion) was canceled by the user; LAPSED — the bet automatically expired because the market closed or conditions were no longer valid. |
| side | String | Yes | Side enum. One of: BACK — selection occurrence side selection; LAY — selection non-occurrence side selection. |
| marketId | String | Yes | Identifier for the specific market within an event. |
| runnerId | Long | Yes | Identifier for the specific runner within a market. |
| size | double | Yes | Bet size requested for placement in customer currency. |
| sizeMatched | double | Yes | Bet size matched at the time of bet request placement. Applicable for Exchange markets. |
| odds | double | Optional | Accepted bet odds. |
| line | int | Optional | The bet line, can be empty. |
| errorMessage | String | Optional | Message from a provider accompanying failed or voided bet; empty if a bet is placed. |
| errorCode | String | Optional | Code from a provider accompanying failed or voided bet; empty if a bet is placed. |
| version | long | Yes | Timestamp when the bet was placed (UTC). |
| sizeRemaining | double | Yes | The remaining unmatched portion of the bet that is still active in the market. Applicable for Exchange markets. |
| sizeLapsed | double | Yes | The portion of the bet that has lapsed (i.e. was not matched before the market closed or the event started) and was automatically removed. Applicable for Exchange markets. |
| sizeCancelled | double | Yes | The portion of the bet that was cancelled by the user or system before being matched. Applicable for Exchange markets. |
| sizeVoided | double | Yes | The portion of the bet that was voided (e.g. due to event cancellation or market rule changes). Applicable for Exchange markets. |
| averageOdds | double | Yes | The weighted average odds at which the bet was matched. If the bet is partially matched at different odds, this value reflects the overall effective odds based on matched sizes. Applicable for Exchange markets. |
| voidReason | String | Optional | Message from operator accompanying failed or voided bet. |
BetSnapshot Proto
message BetSnapshot {
string requestId = 1;
int64 betId = 2;
string marketId = 3;
int64 runnerId = 4;
double size = 5;
optional double odds = 6;
optional int32 line = 7;
string side = 8;
string memberCode = 9;
string status = 10;
optional string errorMessage = 11;
optional string errorCode = 12;
int64 version = 13;
double sizeMatched = 14;
double sizeRemaining = 15;
double sizeLapsed = 16;
double sizeCancelled = 17;
double sizeVoided = 18;
double averageOdds = 19;
optional string voidReason = 20;
}
3.9 BetOutcomeSnapshot
Queue: {customerPrefix}.bets.outcomes.queue
Settlement information. Upon arrival, should fully override existing snapshot after version check.
BetOutcomeSnapshot Model
| Field | Data Type | Description |
|---|---|---|
| requestId | String | (from BetSnapshot.requestId) |
| betId | long | Bet id. |
| outcome | string | Bet outcome enum. One of: WON — the bet has won; LOST — the bet has lost; VOID — the bet was voided. |
| pnl | double | Bet profit and loss outcome. |
| version | Long | Timestamp when the bet was settled (UTC). |
| sizeSettled | double | Provider matched size in the case of a partial match. |
BetOutcome Proto
message BetOutcomeSnapshot {
string requestId = 1;
int64 betId = 2;
string outcome = 3;
double pnl = 4;
int64 version = 5;
double sizeSettled = 6;
}
3.10 MultiBetSnapshot
Queue: {customerPrefix}.bets.multi-bet.snapshot.queue
Covers: acceptance, rejections, voiding.
MultiBetSnapshot Model
| Field | Data Type | Required | Description |
|---|---|---|---|
| requestId | String | Yes | A request unique identifier. It could be generated on the customer side. |
| betId | Long | Yes | Unique identifier for the placed bet. Generated on Public API level. |
| status | String | Yes | Bet status enum: PENDING, FAILED, PLACED, VOIDED. |
| errorMessage | String | Optional | Message from a provider accompanying failed or voided bet. |
| errorCode | String | Optional | Code accompanying failed or voided bet. |
| version | long | Yes | Timestamp when the bet was placed (UTC). |
| stake | double | Optional | Stake. |
| multibetPrice | double | Optional | Multibet price. |
| memberCode | String | Yes | Code identifying the member placing the bet. |
| voidReason | String | Optional | Message from operator accompanying failed or voided bet. |
| multibetLegs | List<MultibetLegSnapshot> | Yes | List of multibet legs. |
MultiBetSnapshot Proto
message MultiBetSnapshot {
string requestId = 1;
int64 betId = 2;
string status = 3;
optional string errorMessage = 4;
optional string errorCode = 5;
optional double stake = 6;
optional double multibetPrice = 7;
string memberCode = 8;
optional string voidReason = 9;
repeated MultibetLegSnapshot multibetLeg = 10;
int64 version = 11;
}
message MultibetLegSnapshot {
string eventId = 1;
string marketId = 2;
int64 selectionId = 3;
string side = 4;
double requestedOdds = 5;
double odds = 6;
}
MultibetLegSnapshot Model
| Field | Data Type | Description |
|---|---|---|
| eventId | String | Identifier for the specific event within a multibet event. |
| marketId | String | Identifier for the specific market within a multibet event. |
| selectionId | Long | Identifier for the specific selection within a multibet event. |
| side | String | Side enum. BACK — selection occurrence side selection. |
| requestedOdds | double | The requested odds within a multibet event. |
| odds | double | The accepted odds within a multibet event. |
| memberCode | String | Code identifying the member placing the bet. |
| voidReason | String | Message from operator accompanying failed or voided bet. |
3.11 MultiBetOutcomeSnapshot
Queue: {customerPrefix}.bets.multi-bet.outcomes.queue
MultiBetOutcomeSnapshot Model
| Field | Data Type | Description |
|---|---|---|
| requestId | String | A request unique identifier. It could be generated on the customer side. |
| betId | long | Bet id. |
| outcome | string | Bet outcome enum: WON, LOST, VOID. |
| pnl | double | Bet profit and loss outcome. |
| version | Long | Timestamp when the bet was settled (UTC). |
| sizeSettled | double | Provider matched size in the case of a partial match. |
| voidReason | string | Message from operator accompanying failed or voided bet. |
| unvoidReason | string | Message from operator accompanying failed or unvoided bet. |
MultiBetOutcome Proto
message MultiBetOutcomeSnapshot {
string requestId = 1;
int64 betId = 2;
string outcome = 3;
double pnl = 4;
int64 version = 5;
double sizeSettled = 6;
string voidReason = 7;
string unvoidReason = 8;
}
3.12 MultibetPriceSnapshot
Queue: {customerPrefix}.bets.multi-bet.price.queue
MultibetPriceSnapshot Model
| Field | Data Type | Description |
|---|---|---|
| requestId | string | A request unique identifier. |
| marginedOdds | double | Margined odds of multibet price request. |
| success | boolean | Status of the multibet price request. |
| errorMessage | string | Error message. |
MultibetPriceSnapshot Proto
message MultiBetPriceSnapshot {
string requestId = 1;
double marginedOdds = 2;
string success = 3;
optional string errorMessage = 4;
}
4. REST Betting API
Base URL: Provided by Bifrost on customer onboarding.
Authentication: All endpoints require Authorization: Bearer YOUR_API_TOKEN.
Content-Type: application/json
4.1 Place Bet
Endpoint: POST /api/v1/bets/place
Description: Allows the customer to place a new bet on an event.
Note: All successful bet responses will be returned with PENDING status. After the provider processes the bet placement, results (placed or not) will be provided in the RabbitMQ queue.
Request Headers
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
PlaceBetRequest Fields
| Field | Type | Required | Description |
|---|---|---|---|
| sportId | String | Yes | Sport identifier. |
| marketId | String | Yes | Identifier for the specific market within an event. |
| runnerId | Long | Yes | Identifier for the specific runner within a market. |
| priceIndex | Integer | No | The index of the price level on the price ladder within the selection. For example, if a selection had prices 1.91 and 1.90 then a price_level_index of 0 would be 1.91 and 1 would be for 1.90. |
| size | BigDecimal | Yes | Bet size requested for placement. |
| memberSize | BigDecimal | Yes | Bet size initially requested by the member (before PT). |
| odds | BigDecimal | Yes | Bet odds requested for placement. |
| line | Integer | No | Bet line, for line fancy markets only. |
| side | Side | Yes | Side enum. One of: BACK — selection occurrence side selection; LAY — selection non-occurrence side selection. |
| memberCode | String | Yes | Code identifying the member placing the bet. |
| ipAddress | String | Yes | IP address of the client placing the bet. |
| currency | String | No | Currency code (e.g., "USD"). |
| requestId | String | No | A unique identifier that can be generated on the customer side for the request to ensure idempotency. |
Request Body Example
{
"sportId": "2",
"marketId": "9.1223445",
"runnerId": 100123,
"priceIndex": 0,
"size": 50,
"memberSize": 50,
"odds": 100,
"line": 10,
"side": "BACK",
"memberCode": "member_code",
"currency": "HKD",
"ipAddress": "member_ip_address",
"requestId": "123456789"
}
PlaceBetResponse Fields
| Field | Type | Description |
|---|---|---|
| betId | Long | Unique identifier for the placed bet. |
| requestId | String | A request unique identifier. |
| memberCode | String | Code identifying the member placing the bet. |
| status | BetStatus | Bet status enum: PENDING, FAILED, PLACED, VOIDED. |
| side | Side | BACK or LAY. |
| size | BigDecimal | Bet size requested for placement. |
| odds | BigDecimal | Bet odds requested for placement. |
| line | Integer | Bet line requested for placement. |
| version | long | Timestamp when the bet was placed (UTC). |
Response Example — Success (201 Created)
{
"id": 3,
"requestId": "123456789",
"memberCode": "member_code",
"status": "PENDING",
"side": "BACK",
"size": 5,
"memberSize": 5,
"odds": 100,
"line": 10,
"version": 1727702890748
}
PlaceBetErrorResponse Fields
| Field | Type | Description |
|---|---|---|
| errorCode | String | Code representing the type of error. |
| errorMessage | String | Human-readable message describing the error. |
| version | String | Timestamp when the error was returned. |
Response Example — Error (4xx)
[
{
"error_code": "some_error_code",
"errorMessage": "Member code is missing",
"version": "2024-10-10T12:21:00.995612Z"
}
]
4.2 Cancel Bet
Endpoint: POST /api/v1/bets/cancel
Note: Cancel bet is only supported by exchanges.
Description: Allows the customer to cancel a bet.
Note: All successful cancel responses will be returned with CANCEL_PENDING status. After the provider has processed the bet results (cancelled or not), they will be sent to the RabbitMQ queue.
Request Headers
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Request Body
| Field | Type | Description |
|---|---|---|
| marketId | String | Market identifier. |
| betId | String | Bet identifier. |
Request Body Example
{
"marketId": "9.1223445",
"betId": "2"
}
Response Example — Success (201 Created)
{
"id": 3,
"status": "CANCEL_PENDING",
"version": 1727702890748
}
Response Example — Error (4xx)
[
{
"error_code": "some_error_code",
"errorMessage": "Cancel bet request is not valid",
"version": "2024-10-10T12:21:00.995612Z"
}
]
4.3 Get Outcomes
Endpoint: POST /api/v1/bets/outcomes
Description: Allows the customer to request bet outcomes with optional filtering by market ID and pagination support.
Request Headers
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| marketId | String | No | Filter results by specific market ID. If not provided, returns outcomes for all markets. |
| pageSize | Integer | No | Number of results per page. Default is 1000 if not specified. |
| pageNumber | Integer | No | Page number starting from 0. Default is 0 if not specified. |
Request Body Example
{
"marketId": "14.780243_3",
"pageSize": 20,
"pageNumber": 0
}
Response — Success (200 OK)
| Field | Type | Description |
|---|---|---|
| content | Array | Array of bet outcome objects (BetOutcomeSnapshot). |
| pageNumber | Integer | Current page number (0-based). |
| pageSize | Integer | Number of items per page. |
| totalElements | Long | Total number of bet outcomes available. |
| totalPages | Integer | Total number of pages. |
| first | Boolean | True if this is the first page. |
| last | Boolean | True if this is the last page. |
| empty | Boolean | True if the content array is empty. |
Content item fields:
requestId(String): Original request ID from the bet.betId(Long): Unique bet identifier.outcome(String):WON,LOST,VOID, etc.pnl(BigDecimal): Customer profit/loss amount.sizeSettled(BigDecimal): Amount that was settled.version(Long): Version timestamp.
Response Example — Success (200 OK)
{
"content": [
{
"requestId": "1e28c0ab-d799-48d0-bb0f-c1c0ef7bfd78",
"betId": 12345,
"outcome": "WON",
"pnl": 150.50,
"sizeSettled": 100.00,
"version": 1704067260995
},
{
"requestId": "2f39d1bc-e8aa-59e1-cc1g-d2d1fg8cgd89",
"betId": 12346,
"outcome": "LOST",
"pnl": -75.25,
"sizeSettled": 75.25,
"version": 1704067261123
}
],
"pageNumber": 0,
"pageSize": 20,
"totalElements": 150,
"totalPages": 8,
"first": true,
"last": false,
"empty": false
}
Notes
- Authentication Required: Valid Bearer token with appropriate betting permissions.
- Pagination: Default page size 1000. Use
pageSizeandpageNumberto control. - Market Filtering: Without
marketId, all bet outcomes for the customer are returned. - Ordering: Results are ordered by bet ID in descending order (newest first).
- Customer Scope: Only returns bet outcomes for the authenticated customer.
- Performance: For better performance, use pagination with smaller page sizes for large result sets.
Error Responses
// 4xx
[{ "error_code": "INVALID_REQUEST", "errorMessage": "Invalid pagination parameters", "version": "2025-01-10T12:21:00.995612Z" }]
// 401 Unauthorized
[{ "error_code": "UNAUTHORIZED", "errorMessage": "Invalid or missing authorization token", "version": "2025-01-10T12:21:00.995612Z" }]
// 403 Forbidden
[{ "error_code": "INSUFFICIENT_PERMISSIONS", "errorMessage": "User does not have permission to access bet outcomes", "version": "2025-01-10T12:21:00.995612Z" }]
4.4 Get Multibet Price
Endpoint: POST /api/v1/bets/multibet/requestprice
Description: Allows the customer to request a price on a multibet.
Note: All successful price requests will have MULTIBET_PRICE_REQUESTED status and all successful price responses will have MULTIBET_PRICE_FILLED status and will be sent into the RabbitMQ queue.
Request Headers
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| requestId | String | No | Optional, random UUID will be generated if not included. |
| multibetLegs | Array | Yes | From 2 to 20 legs. Each leg has: eventId, marketId, side, selectionId. |
Request Body Example
{
"requestId": "testRequestId1",
"multibetLegs": [
{
"eventId": "14.221657_1",
"marketId": "14.780243_3",
"side": "BACK",
"selectionId": 2084382
},
{
"eventId": "14.221657_1",
"marketId": "14.780244_3",
"side": "LAY",
"selectionId": 2084370
}
]
}
Response — Success (201 Created)
{
"requestId": "1e28c0ab-d799-48d0-bb0f-c1c0ef7bfd78",
"legs": [
{
"eventId": "14.221657_1",
"marketId": "14.780243_3",
"selectionId": "2084382",
"side": "Back"
},
{
"eventId": "14.221657_1",
"marketId": "14.780244_3",
"selectionId": "2084370",
"side": "Back"
}
]
}
Response — Error (4xx)
[
{
"error_code": "some_error_code",
"errorMessage": "Event id is missing",
"version": "2025-04-10T12:21:00.995612Z"
}
]
4.5 Place Multibet
Endpoint: POST /api/v1/bets/multibet/place
Description: Allows the customer to place a new multibet on an event.
Note: All successful bet responses will be returned with PENDING status. After the provider processes the bet placement, results (placed or not) will be provided in the RabbitMQ queue.
Request Headers
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| stake | number | Yes | Stake amount. |
| currency | String | Yes | Currency code (e.g., "hkd"). |
| memberCode | String | Yes | Code identifying the member placing the bet. |
| account | String | Yes | Account identifier. |
| ip | String | Yes | IP address of the client. |
| stakeFactor | number | Yes | Stake factor. |
| multiBetLegs | Array | Yes | List of legs. Each leg has: marketId, runnerId, side, requestedOdds, expectedOperatorOdds, priceLevelIndex, tolerancePercentage, eventId. |
| multiBetPrice | number | Yes | Combined multibet price. |
| positionTake | value or null | No | Position take. |
| fixedPendingUntil | value or null | No | Fixed pending until. |
| turnoverRebatePercentage | value or null | No | Turnover rebate percentage. |
| requestId | String | No | Optional request identifier for idempotency. |
| placedDate | number | No | Timestamp of placement. |
Request Body Example
{
"stake": 10,
"currency": "hkd",
"memberCode": "testCustomer11",
"account": "testCustomer",
"ip": "127.0.0.1",
"stakeFactor": 10,
"multiBetLegs": [
{
"requestedOdds": 2.16,
"expectedOperatorOdds": 2.16,
"priceLevelIndex": 0,
"tolerancePercentage": 0
},
{
"requestedOdds": 9.00,
"expectedOperatorOdds": 9.00,
"priceLevelIndex": 0,
"tolerancePercentage": 0
}
],
"multiBetPrice": 101.626319807,
"positionTake": null,
"fixedPendingUntil": null,
"turnoverRebatePercentage": null,
"requestId": "8c9a42c2-0784-4481-a2b4-97ff528daa08",
"placedDate": 1747396906880
}
Response — Success (201 Created)
Returns the full multibet snapshot including all leg details, multiBetPrice, and a placedTime.
Response — Error (4xx)
[
{
"error_code": "some_error_code",
"errorMessage": "Event id is missing",
"version": "2025-04-10T12:21:00.995612Z"
}
]
5. Key Domain Rules
5.1 oddsType Semantics
MarketCatalogue.oddsType (string) — represents market STRUCTURE:
- Values seen in practice:
LINE,ODDS LINE: Line/session markets (have a target runs/value). Example: Over/Under session markets in cricket.ODDS: Standard odds markets with multiple runners.- Note: Both LINE and ODDS markets use haar jeet (paise) pricing in practice.
MarketBook.oddsType (string) — represents PRICING FORMAT (authoritative for display):
HAAR_JEET: Price is in paise. e.g.100= even money (2.0 decimal),172= 2.72 decimal.DECIMAL: Standard decimal odds (e.g.2.72means 2.72).- Always prefer
MarketBook.oddsTypeoverMarketCatalogue.oddsTypefor determining how to interpret runner prices.
5.2 marketStatus Lifecycle
INACTIVE → OPEN → SUSPENDED → OPEN (can oscillate)
→ CLOSED → SETTLED
BALL_RUNNING (deprecated, treat as suspended/not available)
- Only
OPENstatus allows bet placement. BALL_RUNNINGis currently supported but planned for deprecation.SUSPENDEDandINACTIVEdo not allow bets.CLOSEDandSETTLEDare terminal states.
5.3 tradingMarketType
The tradingMarketType field appears in both MarketCatalogue and MarketBook. It represents the original market type string from Bifrost's internal trading system. It is informational — Hannibal does not need to parse or act on this field for routing or settlement decisions.
5.4 Version Field Usage
The version field on all messages (Category, Event, MarketCatalogue, MarketBook, BetSnapshot, etc.) is a monotonically increasing value used for deduplication and ordering. Upon receiving a message, the consumer should only process and store it if the incoming version is greater than the stored version. Never process a lower version — it is a stale update.
5.5 MarketCatalogue + MarketBook Correlation
MarketCatalogue.id == MarketBook.marketId— this is the only join key.MarketCatalogueprovides static metadata: market type, name, start time, runner names.MarketBookprovides dynamic data: prices, status, limits.- A market is valid and bettable only when BOTH
MarketCatalogueANDMarketBookare present.
5.6 Side Values
| Value | Meaning |
|---|---|
BACK | Selection occurrence side — bet FOR the selection to happen. |
LAY | Selection non-occurrence side — bet AGAINST the selection happening. Only supported on exchange markets. |
5.7 Cancel Bet Constraint
Cancel bet (POST /api/v1/bets/cancel) is only supported by exchanges. Non-exchange markets (bookmaker/sportsbook type markets within Bifrost) do not support cancellation.
6. Hannibal Integration Notes
OddsType Semantics (Confirmed with Michael Cheremuhin, 2026-03-09)
MarketCatalogue.oddsType:LINEorODDS— represents market STRUCTURE (trading system internals).LINE: line/session markets (have a target runs value).ODDS: standard odds markets (multiple runners).- Both LINE and ODDS use haar jeet (paise) pricing.
MarketBook.oddsType:HAAR_JEETorDECIMAL— represents PRICING FORMAT (authoritative for display).- Prefer
MarketBook.oddsTypeoverMarketCatalogue.oddsTypefor display decisions. - If
MarketBook.oddsType = HAAR_JEET: price is in paise (e.g. 100 = even money, 172 = 2.72 decimal). - If
MarketBook.oddsType = DECIMAL: standard decimal odds.
- Prefer
Queue Usage
bets.snapshot.queue: ALL bet status updates (acceptance, rejection, cancellation, voiding, size matching).bets.outcomes.queue: Settlement information only.bets.cancel.queue: Cancelled bet snapshots (also BetSnapshot, but separate queue for cancellation flow).- NO separate "bets.cancel.queue" carries a different message type — it still produces
BetSnapshot.
PlaceBet: providerId field
NOT in current API spec. Was removed. Do not send.
MarketCatalogue + MarketBook Correlation
MC.id == MB.marketId(only join key).- MC: static metadata (market type, name, start time, runner names).
- MB: dynamic data (prices, status, limits).
- A market is valid/bettable only when BOTH MC and MB are present.
- Michael: "we recommend to store both entities and consider market to be correct and available for betting if both parts are present."
LAY Bets on 9.x Markets
- Bifrost API supports
side: LAYsyntactically. - LAY is defined as: selection non-occurrence side selection.
- Cancel bet is exchange-only (9.x markets are exchange markets in Bifrost's classification).
- All LAY bets currently fail with error code
0.1001— under investigation with Bifrost.
Odds Conversion (Hannibal Internal)
- All canonical odds stored as decimal in Hannibal DB.
BifrostAdapterconverts at API boundary:haarJeetToDecimal()on read,decimalToHaarJeet()on write.- Haar jeet formula:
decimal = 1 + (haarJeet / 100)haarJeet = (decimal - 1) * 100
- Example:
haarJeet = 100→decimal = 2.0(even money);haarJeet = 172→decimal = 2.72.
Currency
- Bifrost operates in HKD. Exchange rate:
10(1 FP = 0.1 HKD). Configured in theproviderstable. - The
currencyfield in PlaceBetRequest is optional per API spec.
memberCode
- MUST be
order.userId(the Hannibal user's UUID). NOT a static platform config value. - Using a static memberCode breaks per-user risk management on Bifrost's side.
Bet Status Mapping (Bifrost → Hannibal)
| Bifrost BetSnapshot.status | Hannibal Order Status |
|---|---|
PENDING | submitted |
PLACED | accepted |
PARTIALLY_MATCHED | partially_accepted |
FAILED | declined |
CANCELLED | cancelled |
LAPSED | lapsed |
VOIDED | settled (settlementOutcome: void) |
Settlement Mapping (Bifrost → Hannibal)
| Bifrost BetOutcomeSnapshot.outcome | Hannibal settlementOutcome |
|---|---|
WON | win |
LOST | lose |
VOID | void |