Market States and Messages
What is a Kero Market?
Section titled “What is a Kero Market?”A Kero market is a real-time, fast micro-market typically related to what happens next in a given game. For example, in a soccer game, it could be: “Which team will take the first shot after minute XX?” Kero generates thousands of these types of markets per game and sends tens of thousands of specific market messages to adjust for changes in market states, odds, and other variables.
Let’s break each component down one by one:
Market States
Section titled “Market States”Each Kero market has a market_state field. Below are the different market states and what actions should be taken on your side:
- PUBLISHED – The market is visible to users.
- SUSPENDED – The market is visible to users but is not bettable.
- TIMED_OUT – The market is not visible to users but is not yet settled.
- RESOLVED – The market is not visible to users and has now been settled.
- DRAFT – The market is not visible to users and has been voided.
These market states are reflected in market messages, which also include a separate action field describing the change. Below, we outline the different market actions, how they impact market_state, and how they fit into the overall market flow:
Market Actions
Section titled “Market Actions”-
PUBLISH{"type": "MARKET","sub_type": "TEMPLATE","object": {"id": "f668332f-cc84-46a1-9a91-fdd8e5a46bb6","event_id": "7d11a558-5fa1-4c8b-91b6-9b1fce11a36d","event": {"alternate_game_ids": {"betradar": "55311849"}},"market_state": "PUBLISHED","answers_odds": {"answer_a": {"is_restricted": false,"prob": 0.41,"odds": {"american": "+122","european": "2.22","fractional": "61/50"}},"answer_b": {"is_restricted": true,"prob": 0.59,"odds": {"american": "-100","european": "1.87","fractional": "61/50"}}},"game_id": "55311849","key_market": "BASEBALL_A_12_7","is_core": true,"market_context": {"batter_name": "","batter_order_position": "0","batter_plate_appearance_number": "0","inning": "1","inning_side": "bottom","line": "3.5","pitch_number": "1","pitcher_name": "Matt Krook","plate_appearance_position": "","team": "AWAY"},"match_state": {"away_score": "10","balls": "0","home_score": "5","inning": "9","inning_side": "top","outs": "1","strikes": "0"},"title_variable": "{\"batter\": \"Matt Lugo\", \"target_value\": \"5th\"}","context_note_variable": "{\"player_name\": \"M. Krook\", \"target_value\": \"4.2\"}","constraint_variable": "{\"batter\": \"M. Lugo\", \"target_value1\": \"0\", \"target_value2\": \"4\"}","context_note_variable_type": "","title_variable_type": "","constraint_variable_type": "0","answers_variables": {"answer_a": "{\"line\":\"3.5\"}","answer_b": "{\"line\":\"3.5\"}"},"variables_entities": {"batter": {"type": "PLAYER","id": 1,"full_name": "Matt Lugo"},"player_name": {"type": "PLAYER","id": 2,"short_name": "M. Krook"}},"answers_restricted": {"answer_a": false,"answer_b": true}},"action": "PUBLISH","timestamp": 1747890599809}- The market must be presented to the user.
market_state = PUBLISHED- Next possible actions: either
UPDATE_MARKET_ODDS,SUSPEND, orUNPUBLISH
-
UPDATE_MARKET_ODDS(not always){"type": "MARKET","sub_type": "TEMPLATE","object": {"id": "0954fc76-3dab-4d1b-b87d-2932a085dfb1","event_id": "08814556-61f4-4557-89e8-71082beaafe8","event": {"alternate_game_ids": {"betradar": "59796334"}},"market_state": "PUBLISHED","answers_odds": {"answer_a": {"is_restricted": true,"prob": 0.37,"odds": {"american": "+200","european": "3.00","fractional": "3/1"}},"answer_b": {"is_restricted": false,"prob": 0.13,"odds": {"american": "+400","european": "5.00","fractional": "4/1"}},"answer_c": {"is_restricted": false,"prob": 0.29,"odds": {"american": "+202","european": "3.03","fractional": "203/100"}},"answer_d": {"is_restricted": false,"prob": 0.24,"odds": {"american": "+257","european": "3.57","fractional": "257/100"}}},"game_id": "59796334","key_market": "BASKETBALL_A_7_37_4","is_core": true,"title_variable": "{\"start_resolve_cl\":\"2:52\",\"target_period\":\"(OT1)\",\"team\":\"Knicks\"}","context_note_variable": "{\"target_value1\":\"36\",\"target_value2\":\"11\",\"team_abr\":\"NYK\"}","constraint_variable": "","context_note_variable_type": "","title_variable_type": "","constraint_variable_type": "","answers_variables": {"answer_a": "{}","answer_b": "{}","answer_c": "{}","answer_d": "{}"},"variables_entities": {"team": {"type": "TEAM","id": 1,"side": "HOME","short_name": "NYK","common_name": "Knicks",},"team_abr": {"type": "TEAM","id": 1,"side": "HOME","short_name": "NYK","common_name": "Knicks"}},"answers_restricted": {"answer_a": true,"answer_b": false,"answer_c": false,"answer_d": false}},"action": "UPDATE_MARKET_ODDS","timestamp": 1747883067372}- The user must receive the updated odds.
market_state = PUBLISHED- Next possible action:
SUSPENDorUNPUBLISH
-
SUSPEND{"type": "MARKET","sub_type": "TEMPLATE","object": {"id": "3c7e47be-0a53-4f76-a38f-e190c5def42d","event_id": "f3a220ab-fed5-4ad7-bffa-90c70fdc70e3","event": {"alternate_game_ids": {"betradar": "58803499","opta": "3whht8s9eu469juin68xxxjis"}},"market_state": "SUSPENDED","answers_odds": {"answer_a": {"is_restricted": false,"prob": 0.54,"odds": {"american": "-138","european": "1.72","fractional": "18/25"}},"answer_b": {"is_restricted": false,"prob": 0.46,"odds": {"american": "-100","european": "2.00","fractional": "1/1"}}},"game_id": "3whht8s9eu469juin68xxxjis","key_market": "SOCCER_P_0_21","is_core": false,"title_variable": "","context_note_variable": "","constraint_variable": "","context_note_variable_type": "","title_variable_type": "","constraint_variable_type": "","answers_variables": {"answer_a": "{\"h_abr\":\"ATH\"}","answer_b": "{\"v_abr\":\"LAM\"}"},"variables_entities": {"h_abr": {"type": "TEAM","id": 1,"side": "HOME","short_name": "ATH"},"v_abr": {"type": "TEAM","id": 2,"side": "AWAY","short_name": "LAM"}},"answers_restricted": {"answer_a": false,"answer_b": false}},"action": "SUSPEND","timestamp": 1747906864936}- The user can still see the market but should not be able to make bets on it
market_state = SUSPENDED- Next possible action:
ACTIVATEorUNPUBLISH
-
ACTIVATE(not always){"type": "MARKET","sub_type": "TEMPLATE","object": {"id": "715012cf-ebd7-41e3-87d2-e580d852b006","event_id": "7d11a558-5fa1-4c8b-91b6-9b1fce11a36d","event": {"alternate_game_ids": {"betradar": "55311849"}},"market_state": "PUBLISHED","answers_odds": {"answer_a": {"is_restricted": false,"prob": 0.12,"odds": {"american": "+426","european": "5.26","fractional": "213/50"}},"answer_b": {"is_restricted": false,"prob": 0.16,"odds": {"american": "+334","european": "4.35","fractional": "67/20"}},"answer_c": {"is_restricted": false,"prob": 0.16,"odds": {"american": "+334","european": "4.35","fractional": "67/20"}},"answer_d": {"is_restricted": false,"prob": 0.17,"odds": {"american": "+317","european": "4.17","fractional": "317/100"}},"answer_e": {"is_restricted": false,"prob": 0.17,"odds": {"american": "+317","european": "4.17","fractional": "317/100"}},"answer_f": {"is_restricted": false,"prob": 0.13,"odds": {"american": "+400","european": "5.00","fractional": "4/1"}},"answer_g": {"is_restricted": false,"prob": 0.1,"odds": {"american": "+488","european": "5.88","fractional": "122/25"}}},"game_id": "55311849","key_market": "BASEBALL_A_12_7_7","is_core": true,"market_context": {"batter_name": "Seth Brown","batter_order_position": "8","batter_plate_appearance_number": "6th","inning": "9","inning_side": "bottom","line": "0","pitch_number": "1","pitcher_name": "Connor Brogdon","plate_appearance_position": "at_bat","team": "HOME"},"match_state": {"away_score": "10","balls": "1","home_score": "5","inning": "9","inning_side": "bottom","outs": "1","strikes": "0"},"title_variable": "{\"batter\": \"Seth Brown\", \"target_value\": \"6th\"}","context_note_variable": "{\"player_name\": \"R. Zeferjahn\", \"target_value\": \"4.3\"}","constraint_variable": "{\"batter\": \"S. Brown\", \"target_value1\": \"1\", \"target_value2\": \"5\"}","context_note_variable_type": "","title_variable_type": "","constraint_variable_type": "0","answers_variables": {"answer_a": "{}","answer_b": "{}","answer_c": "{}","answer_d": "{}","answer_e": "{}","answer_f": "{}","answer_g": "{}"},"variables_entities": {"batter": {"type": "PLAYER","id": 1,"full_name": "Seth Brown","short_name": "S. Brown"},"player_name": {"type": "PLAYER","id": 2,"short_name": "R. Zeferjahn"}},"answers_restricted": {"answer_a": false,"answer_b": false,"answer_c": false,"answer_d": false,"answer_e": false,"answer_f": false,"answer_g": false}},"action": "ACTIVATE","timestamp": 1747891145638}- The user should once again be able to bet on a market that was previously suspended
market_state = PUBLISHED- Next possible actions: either
UPDATE_MARKET_ODDS,SUSPEND, orUNPUBLISH
-
UNPUBLISH{"type": "MARKET","sub_type": "TEMPLATE","object": {"id": "7dec2ae9-0e8f-48da-9819-7a5b1b124658","event_id": "1ddc5450-7d32-4015-875c-4f5141f702f0","event": {"alternate_game_ids": {"betradar": "58267293","opta": "1rncpj8trvlcnr74nvzstnehg"}},"market_state": "TIMED_OUT","answers_odds": {"answer_a": {"is_restricted": false,"prob": 0.28,"odds": {"american": "+213","european": "3.13","fractional": "213/100"}},"answer_b": {"is_restricted": false,"prob": 0.72,"odds": {"american": "-312","european": "1.32","fractional": "8/25"}}},"game_id": "1rncpj8trvlcnr74nvzstnehg","key_market": "SOCCER_A_12_20","is_core": true,"title_variable": "{\"start_resolve_cl\": \"84:00\"}","context_note_variable": "{\"team\": \"TOT\", \"team1\": \"MUN\", \"target_value\": \"1\", \"target_value1\": \"8\"}","constraint_variable": "","context_note_variable_type": "1","title_variable_type": "","constraint_variable_type": "","answers_variables": {"answer_a": "{\"h_abr\":\"TOT\"}","answer_b": "{\"v_abr\":\"MUN\"}"},"variables_entities": {"h_abr": {"type": "TEAM","id": 1,"side": "HOME","short_name": "TOT"},"v_abr": {"type": "TEAM","id": 2,"side": "AWAY","short_name": "MUN"},"team": {"type": "TEAM","id": 1,"side": "HOME","short_name": "TOT"},"team1": {"type": "TEAM","id": 2,"side": "AWAY","short_name": "MUN"}},"answers_restricted": {"answer_a": false,"answer_b": false}},"action": "UNPUBLISH","timestamp": 1747861308850}- The market may no longer be shown to the user.
market_state = TIMED_OUT- Next possible actions:
RESOLVEorCANCEL
-
RESOLVE{"type": "MARKET","sub_type": "TEMPLATE","object": {"id": "78e76baf-aa28-4867-8b95-498cc6a13993","event_id": "7d11a558-5fa1-4c8b-91b6-9b1fce11a36d","event": {"alternate_game_ids": {"betradar": "55311849"}},"resolve_condition": "answer_c","market_state": "RESOLVED","answers_odds": {"answer_a": {"is_restricted": false,"prob": 0.44,"odds": {"american": "+108","european": "2.08","fractional": "27/25"}},"answer_b": {"is_restricted": false,"prob": 0.38,"odds": {"american": "+138","european": "2.38","fractional": "69/50"}},"answer_c": {"is_restricted": false,"prob": 0.18,"odds": {"american": "+300","european": "4.00","fractional": "3/1"}}},"game_id": "55311849","key_market": "BASEBALL_A_12_20_3","is_core": true,"market_context": {"batter_name": "Maxwell Schuemann","batter_order_position": "9","batter_plate_appearance_number": "5th","inning": "9","inning_side": "bottom","line": "0","pitch_number": "8","pitcher_name": "Connor Brogdon","plate_appearance_position": "at_bat","team": "AWAY"},"match_state": {"away_score": "10","balls": "3","home_score": "5","inning": "9","inning_side": "bottom","outs": "2","strikes": "2"},"title_variable": "","context_note_variable": "{\"player_name\": \"C. Brogdon\", \"target_value\": \"66.2\"}","constraint_variable": "{\"batter\": \"M. Schuemann\", \"target_value\": \"8th\", \"target_value1\": \"5th\"}","context_note_variable_type": "","title_variable_type": "","constraint_variable_type": "","answers_variables": {"answer_a": "{}","answer_b": "{}","answer_c": "{}"},"variables_entities": {"batter": {"type": "PLAYER","id": 1,"short_name": "M. Schuemann"},"player_name": {"type": "PLAYER","id": 2,"short_name": "C. Brogdon"}},"answers_restricted": {"answer_a": false,"answer_b": false,"answer_c": false}},"action": "RESOLVE","timestamp": 1747891335220}- The market may no longer be shown to the user, and all bets on this market must be resolved.
market_state = RESOLVED- Next possible actions:
REVERSEorCANCELorNone
- If the previous market state was live, upon a resolve call, an
UNPUBLISHmessage will be sent milliseconds prior to the resolve message.
-
REVERSE(not always){"type": "MARKET","sub_type": "TEMPLATE","object": {"id": "e636224c-c4ae-40c3-b189-4fdba53c614f","event_id": "38f770f6-ff4d-4776-8f83-16643c48e215","event": {"alternate_game_ids": {"betradar": "55310633"}},"resolve_condition": "answer_b","market_state": "RESOLVED","answers_odds": {"answer_a": {"is_restricted": false,"prob": 0.07,"odds": {"american": "+567","european": "6.67","fractional": "567/100"}},"answer_b": {"is_restricted": false,"prob": 0.11,"odds": {"american": "+455","european": "5.56","fractional": "114/25"}},"answer_c": {"is_restricted": false,"prob": 0.15,"odds": {"american": "+355","european": "4.55","fractional": "71/20"}},"answer_d": {"is_restricted": false,"prob": 0.18,"odds": {"american": "+300","european": "4.00","fractional": "3/1"}},"answer_e": {"is_restricted": false,"prob": 0.2,"odds": {"american": "+317","european": "4.17","fractional": "317/100"}},"answer_f": {"is_restricted": false,"prob": 0.15,"odds": {"american": "+355","european": "4.55","fractional": "71/20"}},"answer_g": {"is_restricted": false,"prob": 0.13,"odds": {"american": "+400","european": "5.00","fractional": "4/1"}}},"game_id": "55310633","key_market": "BASEBALL_A_12_7_7","is_core": true,"title_variable": "{\"batter\": \"Kyle Schwarber\", \"target_value\": \"6th\"}","context_note_variable": "{\"player_name\": \"S. Alexander\", \"target_value\": \"4.0\"}","constraint_variable": "{\"batter\": \"K. Schwarber\", \"target_value1\": \"1\", \"target_value2\": \"5\"}","context_note_variable_type": "","title_variable_type": "","constraint_variable_type": "0","answers_variables": {"answer_a": "{}","answer_b": "{}","answer_c": "{}","answer_d": "{}","answer_e": "{}","answer_f": "{}","answer_g": "{}"},"variables_entities": {"batter": {"type": "PLAYER","id": 1,"full_name": "Kyle Schwarber","short_name": "K. Schwarber"},"player_name": {"type": "PLAYER","id": 2,"full_name": "S. Alexander"}},"answers_restricted": {"answer_a": false,"answer_b": false,"answer_c": false,"answer_d": false,"answer_e": false,"answer_f": false,"answer_g": false}},"action": "REVERSE","timestamp": 1747730860990}- The correct answer of the market has changed, so all bets on this market must be reprocessed (only possible after
RESOLVE). market_state = RESOLVED- Next possible actions:
CANCELorNone
- The correct answer of the market has changed, so all bets on this market must be reprocessed (only possible after
-
CANCEL(not always){"type": "MARKET","sub_type": "TEMPLATE","object": {"id": "b10d1774-584e-4789-9c08-e75c02bfab56","event_id": "08814556-61f4-4557-89e8-71082beaafe8","event": {"alternate_game_ids": {"betradar": "59796334"}},"market_state": "DRAFT","answers_odds": {"answer_a": {"is_restricted": false,"prob": 0.81,"odds": {"american": "-454","european": "1.22","fractional": "11/50"}},"answer_b": {"is_restricted": false,"prob": 0.19,"odds": {"american": "+285","european": "3.85","fractional": "57/20"}}},"game_id": "59796334","key_market": "BASKETBALL_A_1_107","is_core": false,"title_variable": "{\"player_name\": \"(#32) Karl-Anthony Towns\", \"target_value\": \"10\", \"target_period\": \"(OT1)\", \"start_resolve_cl\": \"3:10\"}","context_note_variable": "{\"player_name\": \"Towns\", \"target_value1\": \"7\", \"target_value2\": \"4\"}","constraint_variable": "","context_note_variable_type": "","title_variable_type": "","constraint_variable_type": "","variables_entities": {"player_name": {"type": "PLAYER","id": 1,"short_name": "Towns","full_name": "Karl-Anthony Towns","jersey_number": "32"}},"answers_restricted": {"answer_a": false,"answer_b": false}},"action": "CANCEL","timestamp": 1747883808522}- The market may no longer be shown to the user, and all bets on this market must be canceled.
market_state = DRAFT- Next possible action:
None
Market Mapping
Section titled “Market Mapping”Market mapping is the simplest but longest part as it involves mapping individual market types from Kero of which there are hundreds for each sport. Below we will walk through an individual market and the required steps to map. Once you have completed one market end to end, the rest should be quite easy to do. However, this step requires a good understanding of various details in order to be executed properly. Below are the core concepts that must be understood and explained through a single example.
-
"key_market": a key is a unique identifier for the static state of a single market. For example, Kero has a market with a key “SOCCER_A_12_45” which corresponds to a market that will always ask “Will the next{team}shot after{start_resolve_cl}be on or off target? This means that in every soccer event, anytime a message with the key “SOCCER_A_12_45” was generated, it will always be related to this construct of a market that is asking about an individual team’s shot type after a particular time. -
Market Catalogue: This catalogue contains all the various market keys that Kero has. Across all sports. You can browse the entire collection of all Kero Market templates by visiting this page, including translations across a number of languages. All of the market templates and their respective translations are available as a REST response which you can generate by following the guide here. Pull markets catalogue via
GET /ms/markets/templates -
Market Variables: Continuing the above example of “SOCCER_A_12_45”. We know that the market is asking about a team’s shot type after a particular moment in the game. Therefore there are two variables that will comprise each individual publish instance of this market key. Variable 1 =
{team}and variable 2 ={start_resolve_cl}. The Message Examples page demonstrates a single payload for this market key where we find the object ” “title_variable”: “{\"team\": \"GET\", \"start_resolve_cl\": \"85:00\"}”. -
Processing Variables with Templates. The first step is to ensure that you are always combining the static content of each market with the variables which are represented inside the curly brackets. I.e. Variable values will be sent to you in Market Messages, and you must replace them inside the title, options, context notes, or any other place where it is represented by curly brackets.
Example:
- Static Market data(Template) for key_market
SOCCER_A_12_45pulled viaGET /ms/markets/templates:
“Will the next {team} shot after {start_resolve_cl} be on or off target?”- Variables values recieved via Market Message
"type": "MARKET", "sub_type":"TEMPLATE":
"title_variable": "{"team": "GET", "start_resolve_cl": "85:00"}"- Result Market Title:
“Will the next GET shot after 85:00 be on or off target?"What is critical to remember is that variables will be present across different parts of a market. They can be in a title, in the answers, or inside context notes.
- Static Market data(Template) for key_market
-
Title Variables: Title variables are a special object in market messages that indicate rare conditional titles based on the construct of a market. They will be represented as numeric values “0” or “1”.
For example, a three point NBA player market that references the context of the player’s current performance.
title _variable_type: 0 = “Lebron James has 1 Three Point basket in the game. Will he score his next 3PT attempt?”
title _variable_type: 1 = “Lebron James has 3 Three Point baskets in the game. Will he score his next 3PT attempt?”
As you can see, there is a slight difference in the plural and singular version of the word “basket” between these two title types.
Most markets will not have title variables as the construct of most markets is simple. In such cases, the title_variable_type value will be empty. However, if present, you must ensure that you have matched the market title to the correct version you pulled from the translations catalogue.
Core vs Contextual Markets
Section titled “Core vs Contextual Markets”When mapping markets it is important to understand the distinction between a core and a contextual market type. In order to illustrate the difference we will use two market keys.
Core Markets are markets that are available throughout the entire game and usually will republish every minute. For example the below market which is asking about the number of shots a team will have in a 10 minute window:
SOCCER_A_12_33: “Total {team_name} shots between {start_resolve_cl} and {end_resolve_cl}?
Contextual Markets are markets that are very similar to a core version but are only published when there is a specific context unfolding in the game. These markets also have a contextual market title. Here is an example of a very similar market as above, but this one only publishes if a team didn’t have a shot in the game for a long time and then suddenly did.
SOCCER_A_11_9: {team_name} just took their first shot all game! How many shots will they take between {start_resolve_cl} and {end_resolve_cl}?
Map Core Markets First. While contextual markets are very unique and are a great way for your brand to differentiate, the core markets will drive a big portion of the turnover because of their always on availability state. You should always map core markets first before proceeding to the contextual ones. The Market Catalogue page contains a filter titled “All Cores” which will enable you to filter core markets from others. Similarly, any rest response or RabbitMQ market message will always contain an “is_core:true/false” payload to help you differentiate.
Status reasons
Section titled “Status reasons”The status_reason field in the market object provides additional context for the current market state.
It is particularly useful for understanding why a market is in a specific state.
The reasons can vary based on the sport and the specific market, but they generally help clarify the conditions leading to the current market state.
play inactive- Used when a play becomes inactivefeed resumed- Used when the data feed resumesfeed suspended- Used when the data feed is suspendedgame ended- Used when the game has endedplay voided- Used when a play is voidedend half before action- Used when half ends before action occurspublished play reversed- Used when a published play is reversedplay penalty received after publish- Used when a penalty is received after publishingplay active- Used when a play becomes activeplayer injured- Used when a player is injuredno field goal attempt- Used when there’s no field goal attemptinvalid field position to start drive- Used when field position is invalid to start drivemarket resulted in neither option- Used when market results in neither optionno 2-pt conversion attempt- Used when there’s no 2-point conversion attemptno punt attempt- Used when there’s no punt attempt