Skip to content
  • There are no suggestions because the search field is empty.

Oddin.gg Trading Service documentation

1. General information

1.1. OTS API

Our API is based on gRPC and protocol buffers. The gRPC-based communication is battle-proven by software industry giants like Google, Microsoft, and others. It offers simple export and client/server code generation for many languages (Java, C#, Python, Node.js, Go, and others). We use protocol buffers as a message format; it is an extremely lightweight and data saving format used in many applications.

1.2. Environments

We currently provide two different environments - Production and Integration. The Production environment is intended to be used only when you have finished with the integration and are ready to go live. Please use the Integration environment for all testing and integration purposes.

You can find the endpoint for each environment in the following table:

Environment API URL
Production api-ots.oddin.gg
Integration api-ots.integration.oddin.gg

1.3. gRPC concepts

You can find the service description and message scheme on https://github.com/oddin-gg/otsschema. You can generate binding codes from this message scheme for your desired language, or you can use pre-generated bindings for Java, Go, and Node.js:

  • A typical request to gRPC is a unary request. You will send us a request, and we will deliver a response in one rpc call.
  • For tickets, we are using gRPC bidirectional streaming, where you need to send keepalive messages if you want to have an open stream for a long time.

ℹ You should not create one stream for each ticket, but rather keep only one stream open and send multiple tickets as needed.

1.4. Authentication

Access to the API is only allowed from known IP addresses. Please send us your IP range(s) to us through your dedicated Oddin.gg communication channels and we will whitelist you.

You have to use an access token to access the OTS API. You should be able to obtain this access token for each environment in Oddin.gg Settings Platform (back-office). Typically, access tokens are valid for one year and are extended automatically.

The token has to be inserted to the gRPC context with the “token” key.

grpc.Dial(target,
grpc.WithPerRPCCredentials(&grpcToken{
token: "xxxxx",
}))

Example of a token setting (Go)

1.5. Integration environment

Please use the integration environment to test your connection and message format. It automatically accepts bets, but every fifth bet is rejected. You can cancel bets at will.

1.6. Handicap markets

Handicap markets can be communicated differently in various Oddin.gg betting products:

  • Vanilla: default handicap sign
  • Inverted: inverted handicap sign (used by most booking operators)
Odds Feed & OTS Back office platform (Freya) iFrame visualisation iFrame API (transactions)
Vanilla or Inverted (configurable) Inverted Inverted + Away Inverted Vanilla

Example - Team handicap +/-1.5:

Team Odds Feed & OTS
INVERTED
Back office platform (Freya)
INVERTED
iFrame visualisation
INVERTED + AWAY INVERTED
iFrame API (transactions)
VANILLA
home handicap=-1.5 handicap=-1.5 handicap=-1.5 handicap=+1.5
home handicap=+1.5 handicap=+1.5 handicap=+1.5 handicap=-1.5
away handicap=-1.5 handicap=-1.5 handicap=+1.5 handicap=+1.5
away handicap=+1.5 handicap=+1.5 handicap=-1.5 handicap=-1.5

2. Exchange rates

We use euro (EUR) as our system currency. All non-EUR currencies are converted by exchange rates from OpenExchange: https://openexchangerates.org - all valid ISO 4217 currency codes should be accepted: https://en.wikipedia.org/wiki/ISO_4217. Exchange rates are updated every 30 minutes.

Ticket currency conversion process:

  • Exchange rates are rounded to 6 digits after the comma
  • The tickets are converted using the exchange rate based on the ticket timestamp
  • The winning values are calculated based on the converted EUR value

3. Bettor bonuses

Please include information about the betting bonuses (the bettor receiving a percentage uplift on the winnings base by some criteria) present in the ticket for the given bettor. We use it as additional information to monitor bettors and its potential abuse of betting bonuses. It does not affect bettor liability and risk score.

If such a bonus is offered, the bonus winning amount must be included in the appropriate BetBonus (see the chapter BetBonus fields) object for each bet.

4. Odds auto acceptance

We offer the option to automatically accept tickets if odds move outside the acceptable limit. You can set this field in the ticket request to ANY or HIGHER enum.

  • ANY - all odds changes will be accepted
  • HIGHER - only higher odds will be accepted

5. Ticket reoffer

We offer the option to “reoffer” a ticket again with a different stake. This will significantly reduce bettors' rejection rates and improve their experience. Please check the following bet reoffer flow:

  1. The ticket is sent to the OTS
  2. The ticket is rejected because of limited liability
  3. The rejected ticket contains the reoffer stake in the local currency of the bet
  4. A new ticket is placed with the reoffer_id set to the previously rejected ticket

6. Ticket processing flow

This chapter provides a complete reference on how tickets are handled by OTS. It is very important to follow the flow described here; otherwise, the OTS cannot guarantee the ticket processing. Please check the diagram at the end of this chapter for a more detailed description.

6.1. Ticket process flowchart

6.2. Acceptance process

  • The Client sends a ticket to the OTS.
  • The system sends back a Ticket Response with an acceptance status of Accepted or Rejected
    • If a response is not received within bet delay + 5 seconds (default betting delay is 0 seconds for prematch and 5 seconds for live), the bet should be rejected, and the ticket cancellation message sent to the OTS (please check Ticket Cancellation). These times are configurable and can be changed based on tournament/bettor specific settings. Maximum delay is 120 seconds.
  • If the ticket was Accepted by the OTS, we expect the ticket to be accepted by the client’s system as well. If you need to reject the ticket, please follow this:
    • Send the ticket cancellation to the OTS (please check the chapter Ticket Cancellation)
    • If the ticket cancellation was Accepted
      • Client rejects the bet
      • The ticket acknowledgment request with the Rejected status is sent to OTS
    • If the ticket cancellation was Rejected
      • The Client should accept the bet, however if you still need to cancel it, please contact us at support@oddin.gg or your integration channel
  • If the ticket was Rejected by OTS, we expect the ticket to be rejected by the client’s system as well. If you need to accept the rejected ticket, then send the ticket acknowledgment request with Accepted status.

6.3. Ticket cancellation

It is sometimes necessary to cancel a bet. Bet cancellation can have various reasons, but the OTS system needs to know about all cancellations on the client’s side in order to properly manage the liability. We support specific bet cancel scenarios (please check the next table), which need to be correctly set in the TicketCancelRequest message. A ticket can be cancelled only up to 5 minutes after it has been accepted.

CancelReason Description
CANCEL_REASON_UNSPECIFIED Not a valid reason. Used for blocking 0 as invalid state.
CANCEL_REASON_TICKET_TIMEOUT Please use this code if a ticket response was not received within a given time.
CANCEL_REASON_WRONG_TICKET Should be used in the case the ticket information is incorrect, and the client is going to send the corrected ticket in the future.
CANCEL_REASON_TECHNICAL_ISSUE Clients should use this if they discover a technical issue, correct it, and then need to cancel the affected tickets.
CANCEL_REASON_REGULATOR The regulator requested to cancel the ticket.
CANCEL_REASON_UNEXPECTED_ISSUE Should be used in the case none of the above codes work.

CancelReason descriptions

The ticket cancellation can be Accepted or Rejected by the OTS system. Please check the possible rejection codes for the ticket cancellation:

CancelRejectionReason Description
CANCEL_REJECT_REASON_UNSPECIFIED Not a valid reason. Used for blocking 0 as invalid state.
CANCEL_REJECT_REASON_TICKET_NOT_FOUND The ticket was not found in the OTS system.
CANCEL_REJECT_REASON_TIME_EXPIRED The time for receiving the ticket cancellation has passed (max. 5 minutes after the ticket acceptance).
CANCEL_REJECT_REASON_ALREADY_SETTLED The ticket has already been settled and cannot be cancelled.
CANCEL_REJECT_REASON_OTHER A reason has not been specified. More info should be contained in the message field.

CancelRejectionReason descriptions

6.4. Ticket acknowledgment

By default, clients should follow the ticket Accepted or Rejected status, otherwise we cannot guarantee liability processing. In case you do not follow our recommendation, you have to always cancel the ticket and send a ticket acknowledgment message with the final ticket state. We expect to receive the ticket acknowledgment within 10s after you receive the initial ticket response.

7. Message schemas

This chapter offers an in-depth description of each field of the message schemas. Please check https://github.com/oddin-gg/otsschema for the protocol buffer definition of the messages.

7.1. Ticket request schema

7.1.1. TicketRequest fields

We are using gRPC bidirectional streaming for tickets, where you need to send keepalive messages if you want to have an open stream for a long time. Keepalive messages must be sent every 10 seconds.

Parameter Details Required Type Description
ticket Ticket fields yes/no* Ticket Your ticket.
keepalive StreamKeepalive fields yes StreamKeepalive StreamKeepalive is used for keeping alive an open client, server, or bidirectional stream.
cashout TicketCashout fields yes/no* TicketCashout Ticket cashout parameters.
max_stake TicketMaxStake fields yes/no* TicketMaxStake Used to get the maximum stake available to be placed by the user.

*One of the parameters must be present TicketRequest fields

7.1.1.1. Ticket fields
Parameter Details Required Type Description
id - yes string Unique ticket ID from the operator’s system. Allowed characters [a-zA-Z0-9\-_].
timestamp - yes Timestamp Timestamp of the ticket placement in UTC.
bets Bet fields yes array of Bet List of bets in the ticket. There should be only one bet object in the bets[] array -
⚠ multiple bet objects in a ticket are not (yet) supported.
accept_odds_change enums schema yes AcceptOddsChange Specifies if odds change is acceptable for the ticket - None, Any, Higher.
total_combinations - yes integer Total number of system combinations to validate against the generated combinations. Since system bets are not yet supported, the value should always be 1.
customer TicketCustomer fields yes TicketCustomer Customer information.
reoffer_id - no string Reoffer ticket ID. Allowed characters [a-zA-Z0-9\-_].
selections TicketSelection fields yes map of TicketSelection Map of all selections. The key is the selection ID and the value is the TicketSelection object.
location_id - no string ID of terminal or shop where bet is received.
currency - yes string Currency of bets stakes. Must be the same for the whole ticket.
channel enums schema yes TicketChannel Channel from which ticket was placed (internet, terminal, etc.).
lastForeignEventStartTime - yes/no* Timestamp Timestamp of the latest foreign (non-Oddin) event start time, the selections of which are present on the ticket. The ticket is marked as lost if we do not receive a resolution for the foreign selections within 30 days.
Not to be used for TicketMaxStake requests.
lastForeignEventEndTime - yes/no* Timestamp Timestamp of the latest foreign (non-Oddin) event end time, the selections of which are present on the ticket. The ticket is marked as lost if we do not receive a resolution for the foreign selections within 30 days.
Not to be used for TicketMaxStake requests.
stake_multiplier - no integer Stake multiplier for stake - an optional value, to be used instead of 10000.

*In the case of foreign (non-Oddin) event odds selections on the ticket, one of the fields needs to be present.
Ticket fields

7.1.1.1.1. Bet fields
Parameter Details Required Type Description
id - no string Bet ID for multi-bets ticket. Allowed characters [a-zA-Z0-9\-_].
bonus BetBonus fields no BetBonus Bonus part of the bet.
stake BetStake fields yes BetStake Stake of the bet.
reoffer_id* - no string Reoffer bet ID. Allowed characters [a-zA-Z0-9\-_]. * deprecated
total_wins - no integer Total wins for all generated combinations for the bet. We use this for validation purposes.
systems - yes array of integers Array of all the systems in the bet - [0] is not allowed, use [1] for single bets or the number of selections in combo bets (e.g., [3] for treble, etc.).
selections BetSelection fields yes array of BetSelection Array of selection IDs from TicketSelection which form this bet.

Bet fields

7.1.1.1.1.1. BetBonus fields
Parameter Details Required Type Description
value - yes integer Bonus amount to add to the win; it needs to be multiplied by 10000 and rounded to long value in local currency.
type - yes BetBonusType Bonus type - only supported TOTAL for now.
mode - yes BetBonusMode Bonus payout mode; typically used for system bets - the only supported value for now is ALL (it means that all bets need to be winning).

BetBonus fields

7.1.1.1.1.2. BetStake fields
Parameter Details Required Type Description
value - yes integer Stake amount. It needs to be multiplied by 10000 and rounded to long value in local currency.
type enums schema yes BetStakeType Stake type - SUM or UNIT. Until multiple bets on a ticket are supported, SUM should be used by default.

BetStake fields

7.1.1.1.1.3. Bet types for the systems field
Name Description
Single One selection, one bet - systems[1] and selections count = 1.
Double Two selections, one bet - systems[2] and selections count = 2.
Treble Three selections, one bet - systems[3] and selections count = 3.
Combo / Accumulator Four or more selections. It does not matter how many selections there are in a combo bet, it is still counted as one bet - systems[number of folds] and selections count = selections count.

Bet type descriptions

7.1.1.1.1.4. BetSelection fields
Parameter Details Required Type Description
id Selection ID yes string Selection ID.

BetSelection fields

7.1.1.1.2. TicketCustomer fields
Parameter Details Required Type Description
id - yes string Bookmaker unique user ID. Allowed characters [a-zA-Z0-9\-_].
ip - no string Bettor’s IP address.
device_id - no string Bettor unique device ID from which the ticket was placed.
language - yes string Supported language’s ISO 639-1 code.
nickname - no string Optional bettor nickname.

TicketCustomer fields

7.1.1.1.3. TicketSelection fields
Parameter Details Required Type Description
id Selection ID yes string Selection ID.
odds - yes integer Odds multiplied by 10000 and rounded to integer value.
foreign - yes boolean Information if the selection is foreign, i.e., not based on Oddin.gg Odds Feed. Can be true or false. If the foreign field value is true, the “id” field can take any string as a value.
Not to be used for TicketMaxStake requests.
obb_session_info   no OBBSessionInfo If obb_session_info property is null, then the TicketSelection message represents a regular ticket selection. If obb_session_info property is defined, then the TicketSelection message represents a BetBuilder (OBB) ticket selection.

TicketSelection fields

7.1.1.1.3.1. Selection ID

Please use the selection information you get from the odds feed in this format:

"<event_urn>/<market_id>/<outcome_id>?<specifier1>=<value1>[&<specifierN=valueN>]*"

  • event_urn - event urn from feed REST API
  • market_id - market ID from feed REST API
  • outcome_id - outcome ID from feed REST API
  • specifier and value - specific specifiers for every market from feed AMQP messages

example:

"od:match:1234/6/1?map=1&way=two"

7.1.1.1.3.2. OBBSessionInfo fields
Parameter Details Required Type Description
session_id - yes string Represents a BetBuilder session_id. If it is defined, then the selection is a BetBuilder TicketSelection, if not, then it is a regular selection.
sub_selections - yes array of strings An individual sub_selection ID for the OBB session selections must have a specific format, which is the same format as for regular market selections (but without odds). E.g.: "od:<product_id>:<event_id>/<market_id>/<outcome_id>?<specifier1>=<value1>[&<specifierN=valueN>]*"
The OBB format (e.g.: "od:obb_session:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") is not allowed here.
7.1.1.2. StreamKeepalive fields
Parameter Details Required Type Description
timestamp commons schema yes Timestamp Timestamp of the keepalive message.

StreamKeepalive fields

7.1.1.3 TicketCashout fields
Parameter Details Required Type Description
id - yes string Unique ticket ID from the operator’s system. Allowed characters [a-zA-Z0-9\-_].
timestamp - yes Timestamp Timestamp of the ticket placement in UTC.
cashout_stake   yes integer Total cashout amount. Applicable for the whole ticket. It needs to be multiplied by 10000 (or ticket stake multiplier) and rounded to long value in local currency. All subsequent partial cashouts must include previous values.
cashout_percent   yes integer

Cashout ratio in relation to the total potential winnings. Applicable for the whole ticket. It needs to be multiplied by 10000 (or ticket stake multiplier) and rounded to long value. Examples:

  • 1 * stake_multiplier = 100% cashout
  • 0.5 * stake_multiplier = 50% cashout
  • 0.3333 * stake multiplier = 33.33% cashout
bet_cashout - no BetCashout Should be omitted or set to null. The required cashout information should be included in the other TicketCashout fields.
stake_multiplier - no integer Stake multiplier for stake - an optional value, to be used instead of 10000.

TicketCashout fields

7.1.1.3.1 BetCashout fields (NOT to be used!)
Parameter Details Required Type Description
id - yes string Bet ID.
cashout_stake   yes integer Total cashout amount. Applicable for the bet. It needs to be multiplied by 10000 (or ticket stake multiplier) and rounded to long value in local currency. All subsequent partial cashouts must include previous values.
cashout_percent   yes integer Total cashout percent. Applicable for the bet. It needs to be multiplied by 10000 (or ticket stake multiplier) and rounded to long value.

BetCashout fields (NOT to be used!)

7.1.1.4. TicketMaxStake fields
Parameter Details Required Type Description
ticket Ticket fields yes Ticket Your ticket. Please use 0 as the stake value in Ticket > Bets[] > Stake.

TicketMaxStake fields

7.2. Ticket response schema

7.2.1. TicketResponse fields
Parameter Details Required Type Description
state TicketState fields yes/no* TicketState State of the ticket.
keepalive StreamKeepalive fields yes StreamKeepalive Used to maintain the stream connection.
cashout TicketCashoutState fields yes/no* TicketCashoutState Cashout state.
max_stake TicketMaxStakeState fields yes/no* TicketMaxStakeState Ticket max stake state.

*One of the parameters must be present TicketResponse fields

7.2.1.1. TicketState fields
Parameter Details Required Type Description
id - yes string Unique ticket ID from operator’s system.
ticket_status - yes AcceptanceStatus Acceptance status - PENDING | REJECTED | ACCEPTED.
reject_reason TicketRejectReason fields no TicketRejectReason Information about the rejection reason.
bet_info TicketResponseBetInfo fields no map of TicketResponseBetInfo Rejection details of bets.
selection_info TicketSelectionRejectReason fields no map of TicketSelectionRejectReason Rejection details of selections.
exchange_rate - no integer Exchange rate used to convert currency to EUR, multiplied by 10000 and rounded to long value. No value sent for TicketMaxStakeState responses.
auto_accepted_odds AutoAcceptedOdds fields no map of AutoAcceptedOdds Alternative odds used to accept the bet.
reoffer - no ResponseReoffer Information about the reoffer stake.
total_odds - no Integer Total odds for the whole ticket.
pending_delay - no Integer Possible ticket pending delay.

TicketState fields

ℹ We recommend not to set a fixed time limit for voiding tickets without a response. The preferred method is to take the delay information (seconds) from the pending_delay field and add 5 seconds to it - if after this combined time there is no response from the OTS system, the ticket should be voided.

7.2.1.1.1. TicketRejectReason fields
Parameter Details Required Type Description
code TicketRejectReason codes yes ReasonCode Reject reason code.
message - yes string Message describing the reason.

TicketRejectReason fields

7.2.1.1.1.1. TicketRejectReason codes
Name Code Description
CODE_UNSPECIFIED 0 Not a valid value. Used for blocking 0 as invalid state.
CODE_INTERNAL 1 Internal issues on Oddin.gg.
CODE_INVALID_ARGUMENT 2 The ticket is not valid.
CODE_ALREADY_EXISTS 3 The ticket already exists in our system.
CODE_STAKE_TOO_LOW 4 Bet stake is lower than the minimum allowed stake.
CODE_STAKE_TOO_HIGH 5 Bet stake is higher than the maximal allowed stake.
CODE_MAX_PAYOUT_BREACHED 6 Max. payout limit breached.
CODE_BETS_NOT_ACCEPTABLE 7 Ticket bets are not acceptable, check the bet_info field for details.
CODE_SELECTIONS_NOT_ACCEPTABLE 8 Ticket selections are not acceptable, check selection_info field for details.
CODE_NOT_FOUND 9 Ticket not found in our system.

TicketRejectReason code descriptions

7.2.1.1.2. TicketResponseBetInfo fields
Parameter Details Required Type Description
id - yes string Unique bet ID from operator’s system.
reject_reason TicketBetRejectReason fields no TicketBetRejectReason Information about the rejection/acceptance reason.
reoffer - no ResponseReoffer Information about the reoffer stake.
total_odds - no integer Total odds for the whole bet.

TicketResponseBetInfo fields

7.2.1.1.2.1. TicketBetRejectReason fields
Parameter Details Required Type Description
code TicketBetRejectReason codes yes Code Reject reason code.
message - yes string Message describing the reason.

TicketSelectionRejectReason fields

7.2.1.1.2.1.1. TicketBetRejectReason codes
Name Code Description
CODE_UNSPECIFIED 0 Not a valid value. Used for blocking 0 as invalid state.
CODE_ODDS_CHANGED 1 At least one odds value in the bet is different from the current odds.
CODE_SELECTION_NOT_ACTIVE 2 At least one selection in the bet is not active.
CODE_STAKE_TOO_LOW 3 Bet stake is lower than the minimum allowed stake.
CODE_STAKE_TOO_HIGH 4 Bet stake is higher than the maximum allowed stake.
CODE_MAX_PAYOUT_BREACHED 5 Maximum payout breached.
CODE_MARKET_LIABILITY_BREACHED 6 Market liability breached.
CODE_BETTOR_LIABILITY_BREACHED 7 Bettor liability breached.
CODE_EVENT_LIABILITY_BREACHED 8 Event liability breached.
CODE_MARKET_BETTOR_LIABILITY_BREACHED 9 Market bettor liability breached.

TicketBetRejectReason codes

7.2.1.1.3. TicketSelectionRejectReason fields
Parameter Details Required Type Description
code TicketSelectionRejectReason codes yes Code Reject reason code.
message - yes string Message describing the reason.

TicketSelectionRejectReason fields

7.2.1.1.3.1. TicketSelectionRejectReason codes
Name Code Description
CODE_UNSPECIFIED 0 Not a valid value. Used for blocking 0 as invalid state.
CODE_CHANGED 1 Selection odds are different from the current odds.
CODE_NOT_ACTIVE 2 Selection is not active.
CODE_INDEPENDENT 3 Selection is not independent. Sent in the case of correlated team or market rejections.

TicketSelectionRejectReason code descriptions

7.2.1.1.4. AutoAcceptedOdds fields
Parameter Details Required Type Description
id Selection ID yes string Selection ID.
requested_odds - yes integer Odds which were ticked placed, multiplied by 10000 and rounded to long value.
used_odds - yes integer Odds which were ticked accepted, multiplied by 10000 and rounded to long value.

AutoAcceptedOdds fields

7.2.1.2. TicketCashoutState fields
Parameter Details Required Type Description
id - yes string Unique ticket ID from operator’s system.
ticket_status - yes AcceptanceStatus Acceptance status - REJECTED | ACCEPTED. PENDING is not used.
reject_reason TicketCashoutRejectReason fields no TicketCashoutRejectReason Information about the rejection reason.

TicketCashoutState fields

7.2.1.2.1. TicketCashoutRejectReason fields
Parameter Details Required Type Description
code TicketCashoutRejectReason codes yes Code Reject reason code.
message - yes string Message describing the reason.

TicketCashoutRejectReason fields

7.2.1.2.1.1. TicketCashoutRejectReason codes
Name Code Description
CODE_UNSPECIFIED 0 Not a valid value. Used for blocking 0 as invalid state.
CODE_INTERNAL 1 We are having internal problems.
CODE_INVALID_ARGUMENT 2 Ticket cashout is not valid.
CODE_NOT_FOUND 3 Ticket not found.
CODE_WRONG_TICKET_STAKE 4 The ticket is not in the accepted state.
CODE_MAX_PAYOUT_BREACHED 5 Cashout amount is higher than possible payout.

TicketCashoutRejectReason code descriptions

7.2.1.3. TicketMaxStakeState fields
Parameter Details Required Type Description
state TicketState fields yes TicketState State of the ticket.

TicketMaxStakeState fields

7.3. Ticket result request schema

7.3.1. TicketResult request
Parameter Details Required Type Description
ticket TicketResult fields yes/no* TicketResult Ticket result.
keepalive StreamKeepalive fields yes StreamKeepalive Used to maintain the stream connection.
after TicketsAfter fields yes/no* TicketsAfter Request tickets after this date/time.

*One of the parameters must be present TicketResultRequest fields

7.3.1.1 TicketResult fields
Parameter Details Required Type Description
id - yes string Bookmaker unique betting ticket ID. Allowed characters [a-zA-Z0-9\-_].

TicketResult fields

7.3.1.2. TicketsAfter fields
Parameter Details Required Type Description
request_id - yes TicketResult Unique request id.
after - yes Timestamp Request tickets after this date/time. The past period of max. 24 hours is supported.

TicketsAfter fields

7.4. Ticket result response schema

7.4.1. TicketResult response
Parameter Details Required Type Description
state TicketResultState fields yes/no* TicketResultState Ticket result.
keepalive StreamKeepalive fields yes StreamKeepalive Used to maintain the stream connection.
after TicketsAfterState fields yes/no* TicketsAfterState Request tickets after this date/time.

*Based on the request, one will be sent TicketResultResponse fields

7.4.1.1. TicketResultState fields
Parameter Details Required Type Description
id - yes string Unique ticket ID from the operator’s system.
ticket_status enums schema yes ResultingStatus Resulting status - WON | VOIDED | LOST | PENDING_LOST | NOT_RESULTED | REJECTED.
won_amount - yes integer Won amount of the ticket, converted by exchange_rate, multiplied by 10000 and rounded to uint value.
bet_info TicketResultStateBetInfo fields no array of TicketResultStateBetInfo Rejection details of bets.
selection_info TicketResultStateSelectionInfo fields no array of TicketResultStateSelectionInfo Rejection details of selections.
exchange_rate - no integer Exchange rate used to convert currency to EUR, multiplied by 10000 and rounded to long value.
resulted_at - no Timestamp Ticket result timestamp.
error TicketResultError fields no TicketResultError Information about a possible error during processing.
modified_at - no Timestamp Time when the ticket was modified.
ticket_result_state_type enums schema yes TicketResultStateType Information about the result type.

TicketResultState fields

7.4.1.1.1. TicketResultStateBetInfo fields
Parameter Details Required Type Description
id - yes string Unique ticket ID from the operator’s system.
ticket_status enums schema yes ResultingStatus Resulting status - WON | VOIDED | LOST | PENDING_LOST | NOT_RESULTED | REJECTED.
won_amount - yes integer Won amount of the ticket, converted by exchange_rate, multiplied by 10000 and rounded to uint value.

TicketResultStateBetInfo fields

7.4.1.1.2. TicketResultStateSelectionInfo fields
Parameter Details Required Type Description
ticket_status enums schema yes ResultingStatus Resulting status - WON | VOIDED | LOST | PENDING_LOST | NOT_RESULTED | REJECTED.

TicketResultStateSelectionInfo fields

7.4.1.1.3. TicketResultError fields
Parameter Details Required Type Description
code enums schema yes ReasonCode Reject reason code.
message - yes string Message describing the reason.

TicketResultError fields

7.4.1.2. TicketAfterState fields
Parameter Details Required Type Description
request_id - yes string Unique request ID from the TicketsAfter request.
after - yes Timestamp Requested tickets after this date/time.
tickets TicketResultState fields yes array of TicketResultState Tickets resulted after the timestamp.
error TicketResultError fields no TicketResultError Information about a possible error during processing.
batch_info BatchInfo fields no BatchInfo Information about batching - batch size is fixed to 100 tickets.

TicketResultState fields

7.4.1.2.1. BatchInfo fields
Parameter Details Required Type Description
actual - yes integer Actual ticket batch size.
total - yes integer Total ticket batch size.

BatchInfo fields

7.4.2. TicketResult flow (cross bets and combo bets)

7.5. Ticket acknowledgement schema

Parameter Details Required Type Description
id - yes string Unique ticket ID from the operator’s system.
timestamp - no Timestamp Timestamp of when the ticket was accepted.
acceptance_status enums schema yes AcceptanceStatus Acceptance status - REJECTED or ACCEPTED.
reason commons schema no Reason Information about the rejection/acceptance reason.

TicketAckRequest fields

7.6. Ticket cancel schema

7.6.1. TicketCancelRequest fields
Parameter Details Required Type Description
id - yes string Unique ticket ID from the operator’s system.
cancel_reason enums schema yes CancelReason Description of the reason for cancelling the ticket.
cancel_reason_detail - yes string Verbose description of the reason for cancelling the ticket.
timestamp - yes timestamp Timestamp of the ticket cancellation in UTC.
cancel_percent* - no integer Cancel percent multiplied by 10000 and rounded to a long value. Only applicable if cancelling the whole ticket.
* currently not supported
cancel_bet_info* CancelBetInfo fields no array of CancelBetInfo Information about the partial bet cancellation. Mutually exclusive with cancel_percent.
* currently not supported

TicketCancelRequest fields

7.6.1.1. CancelBetInfo fields (currently not supported!)
Parameter Details Required Type Description
id - yes string Unique bet ID from the operator’s system.
cancel_percent - no integer Cancel percent multiplied by 10000 and rounded to a long value. Only applicable if cancelling the entire bet.

CancelBetInfo fields

7.6.2. TicketCancelResponse fields
Parameter Details Required Type Description
status enums schema yes AcceptanceStatus Acceptance status - REJECTED or ACCEPTED.
cancel_rejection_reason enums schema yes CancelRejectionReason Description of the reason for cancelling the rejection.
cancel_rejection_message - yes string Verbose description of the reason for rejecting the ticket cancellation.

TicketCancelResponse fields

7.7. Player risk score schema

You can use this method to get more insight on individual player risk score.

7.7.1. PlayerRiskScore request
Parameter Details Required Type Description
id - yes string Unique player ID from the operator’s system.

PlayerRiskScoreRequest fields

7.7.2. PlayerRiskScore response
Parameter Details Required Type Description
bos - yes float Bettor Oddin Score (0-1). Lowered liability factor for the bettor.
oaf - yes float Over Ask Factor (OAF), 1-10. Increased liability factor for the bettor. Also affects the multiplication of max. stake and payout.
live_delay - yes integer Live betting delay in seconds.
prematch_delay - yes integer Prematch betting delay in seconds.

PlayerRiskScoreResponse fields

7.8. Resolve foreign events schema

7.8.1. ResolveForeignEventsInTicket request
Parameter Details Required Type Description
id - yes string Unique ticket ID from the operator’s system.
foreign_stake - yes integer

Stake not handled by Oddin.gg in the same currency as the previous ticket, multiplied by 10000 and rounded to a long value.

  • 0 < WON
  • 0 = LOST
timestamp - yes Timestamp Timestamp of the non Oddin.gg settlement.

ResolveForeignEventsInTicketRequest fields

7.8.2. ResolveForeignEventsInTicket response
Parameter Details Required Type Description
status enums schema yes AcceptanceStatus Acceptance status - REJECTED or ACCEPTED.
reason - no Reason Information about the rejection/acceptance reason.

ResolveForeignEventsInTicketResponse fields

7.9. Health schema

7.9.1. HealthCheck request
Parameter Details Required Type Description
service   yes string Health check for the OTS service.

HealthCheckRequest fields

7.9.2. HealthCheck response
Parameter Details Required Type Description
status enums schema yes ServingStatus Health status of the OTS service.

HealthCheckResponse fields

7.9.2.1. ServingStatus codes
Name Code Description
UNKNOWN 0 OTS service status unknown.
SERVING 1 OTS service is operational.
NOT_SERVING 2 OTS service is not operational.
SERVICE_UNKNOWN 3 Unknown service. Used only by the Watch method.

ServingStatus code descriptions

More details about the implemented gRPC Health Checking Protocol at: https://github.com/grpc/grpc/blob/master/doc/health-checking.md

8. Risk API

8.1. Introduction

Oddin.gg Risk API service API is an extension of the OTS service, offering enhanced functionalities for sending tickets and managing bettor properties. It provides you with robust tools to manage bettor liabilities, leverage valuable customer information, and automate critical processes.

Key Features:

  • Comprehensive Metadata Integration: Each bettor is associated with betting score labels and metadata, which are essential for calculating maximum liabilities and managing risks effectively.
  • Utilise Existing Customer Information: Make the most of your valuable bettor data to optimise your risk management strategies.
  • Streamlined Data Sharing: With API access, you can automate the process of sharing bettor information, eliminating the need for manual processing through trading chats. This ensures faster and more accurate adjustments to risk management settings.
  • Automated Bettor Management: Easily import lists of bettors, and set limitations even before they place their first bet. The API allows bulk adjustments, saving time and reducing manual errors.
  • Real-time Adjustments and Monitoring: The system includes a push feed for each client, ensuring that adjustments to the risk management settings are communicated in a timely fashion. This allows for real-time monitoring and review of the risk management processes.

The Risk API is designed to be flexible and scalable, capable of supporting a wide range of services and automating bettor labelling processes throughout the year.

8.2. Concepts

The Risk API gRPC schema is available on Oddin.gg GitHub repository: https://github.com/oddin-gg/otsschema/pull/10/files. You can generate binding codes from this message schema for your desired development language. A typical request to gRPC is a unary request. You send us a request, and we deliver a response in one RPC call.

  • Extended OTS gRPC API with one unary gRPC stream which pushes updates about Bettor’s risk coefficients to the clients. The stream supports recovery since a given timestamp (max. timestamp threshold is configurable).
  • As Bettor’s risk coefficients we consider bettor information such as: BOS (Bettor’s Oddin Score), OAF (Over Ask Factor), Oddin.gg labels, and Client labels.
  • The API supports authorisation and authentication.

8.3. Endpoints

8.3.1. BettorsRequest
Parameter Type Description
recover_since Timestamp If the timestamp value is null, no updates will be recovered. If it is defined, the system will start to send to the consumer all Bettors since the given timestamp value.

BettorsRequest field

8.3.2. BettorsResponse
Parameter Type Description
bettor Bettor Bettor risk information.
keepalive StreamKeepalive Connection maintaining ticker.

BettorsResponse fields

8.3.2.1. Bettor
Parameter Type Description
id string Unique bettor ID from Oddin.gg system.
ext_id string Unique bettor ID from the operator’s system.
modified_at Timestamp The time of the bettor information modification.
bos float Balance Optimisation Score (BOS). Lowered liability factor for the bettor, representing the multiplier of the liability. Must be between 0 and 1 (inclusive). If provided with a value other than 1, over_ask_factor is automatically set to 1. If not defined, no changes are applied.
over_ask_factor float

Over Ask Factor (OAF). Must be between 1 and 10 (inclusive). If provided with a value other than 1, bos is automatically set to 1. If not defined, no changes are applied.

For VIP bettors with an OAF higher than 3, there is an additional multiplicative reduction factor to the risk limit calculations. It reduces the overall bet liability value and allows VIP bettors to bet more freely without draining away shared liability pools (like market or event liability) from other casual bettors. The value of this new factor is tied to OAF and is divided into 9 ranges:

  • 1st range: OAF 1.000-3.000; factor 1
  • 2nd range: OAF 3.001-5.000; factor 0.75
  • 3rd range: OAF 5.001-7.000; factor 0.5
  • 4th range: OAF 7.001-9.900; factor 0.1
  • 5th range: OAF 9.901-9.931; factor 0.08
  • 6th range; OAF 9.932-9.951; factor 0.06
  • 7th range: OAF 9.952-9.971; factor 0.04
  • 8th range: OAF 9.972-9.991; factor 0.02
  • 9th range: OAF >= 9.992: factor 0.01

This reduction factor is working multiplicatively with the standalone OAF.

oddins_labels string array Bettor label assigned by Oddin.gg.
clients_labels string array Bettor label assigned by the client.

Bettor fields

8.3.2.2. StreamKeepAlive
Parameter Type Description
timestamp Timestamp Timestamp of the keepalive message.

StreamKeepAlive field

8.3.3. BettorUpsertRequest

This request is used to update or create a bettor.

Parameter Type Description
id string Unique bettor ID from the operator's system.
bos float Balance Optimisation Score (BOS). Lowered liability factor for the bettor, representing the multiplier of the liability. Must be between 0 and 1 (inclusive). If provided with a value other than 1, over_ask_factor is automatically set to 1. If not defined, no changes are applied.
over_ask_factor float

Over Ask Factor (OAF). Must be between 1 and 10 (inclusive). If provided with a value other than 1, bos is automatically set to 1. If not defined, no changes are applied.

For VIP bettors with an OAF higher than 3, there is an additional multiplicative reduction factor to the risk limit calculations. It reduces the overall bet liability value and allows VIP bettors to bet more freely without draining away shared liability pools (like market or event liability) from other casual bettors. The value of this new factor is tied to OAF and is divided into 9 ranges:

  • 1st range: OAF 1.000-3.000; factor 1
  • 2nd range: OAF 3.001-5.000; factor 0.75
  • 3rd range: OAF 5.001-7.000; factor 0.5
  • 4th range: OAF 7.001-9.900; factor 0.1
  • 5th range: OAF 9.901-9.931; factor 0.08
  • 6th range; OAF 9.932-9.951; factor 0.06
  • 7th range: OAF 9.952-9.971; factor 0.04
  • 8th range: OAF 9.972-9.991; factor 0.02
  • 9th range: OAF >= 9.992: factor 0.01

This reduction factor is working multiplicatively with the standalone OAF.

labels string array Bettor's labels. If provided, it updates the existing labels; an empty list removes all labels. If not defined, no changes are applied.
nickname string Bettor's nickname. If not defined, no changes are applied.

BettorUpsertRequest fields

ℹ When sending bos and over_ask_factor, only one of these parameters can have their value other than 1.

8.3.4. BettorUpsertResponse

This message contains the updated bettor information.

Parameter Type Description
bettor Bettor Bettor risk information (the updated Bettor object).

BettorUpsertResponse field

8.3.5. AvailableBettorLabelsRequest

This message is used to request the list of available bettor labels.

8.3.6. AvailableBettorLabelsResponse

This message contains the list of available bettor labels.

Parameter Type Description
labels repeated string List of available bettor labels.

AvailableBettorLabelsResponse field

8.4. Logic and workflow

8.4.1. Implement gRPC client
  • Objective: Implement a gRPC client for the Bettor stream.
8.4.2. Initial connection
  • Send initial request: When the client connects for the first time, it must send a request with the timestamp set to a minimum value (e.g., 28/11/2018).
    • Purpose: To trigger a full recovery and receive all available Bettors.
  • Send latest timestamp: For subsequent connections, the client sends the latest timestamp it has received and stored.
    • Purpose: To receive only updates that occurred after the last recorded update, ensuring no data is missed.
  • No recovery mode: If the client sends a request with a null value for the timestamp, it will receive only new updates.
    • Risk: The client may miss updates that occurred while it was disconnected.
8.4.3. Continuous updates and database management
  • Update storage: Upon receiving Bettor updates via the gRPC stream, the client must:
    • Load: Load Bettor for the given id/ext_id from the database.
    • Store: Store received Bettors in the case when no such bettor is stored in DB.
    • Conditionally update: In case when Bettor is already stored in the DB. You are supposed to compare timestamps; if the incoming update’s timestamp is higher or equal to the stored one, update the record in the DB. Ignore the received update if the update has the modified_at timestamp lower than the already stored timestamp for the same id/ext_id.
8.4.4. Keepalive messages
  • Connection maintenance:
    • The OTS service will send keepalive messages every 10 seconds to ensure the connection remains active. If you do not receive a keepalive message within 20 seconds, please restart the connection.

8.5. Risk API integration examples

8.5.1. AvailableBettorLabels

Retrieves a list of all available labels that can be assigned to a bettor.

grpcurl example:

grpcurl --plaintext \
-H "token: XXXXX-XXXXX-XXXXX-XXX-XXXXX" \
api-ots.integration.oddin.gg \
ots.ots/AvailableBettorLabels
8.5.2. BettorUpsert

Creates a new bettor or updates an existing one based on the provided id.

  • Create: If the id does not exist, a new bettor is created.
  • Update: If the id exists, this endpoint performs a partial update. Only the fields provided in the request payload will be modified. Any omitted fields will retain their current values.

grpcurl example:

grpcurl --plaintext \
-H "token: XXXXX-XXXXX-XXXXX-XXX-XXXXX" \
-d @ \
api-ots.integration.oddin.gg \
ots.ots/BettorUpsert < data.json

Request payload parameters:

  • id (string, required): The unique identifier for the bettor.
  • bos (number, optional)
  • over_ask_factor (number, optional)
  • labels (object, optional): An object containing a values array of strings to set or overwrite the bettor's labels.
  • nickname (string, optional)

Here are several examples of data.json payloads for different scenarios:

8.5.2.1. Create or full update

Action: Sets all specified parameters for the bettor.

{
"id": "3257ff3b-b26e-40eb-9ee6-88d3f82f5701",
"bos": 1,
"over_ask_factor": 7.001,
"labels": {
"values": ["VIP"]
},
"nickname": "nickname1"
}
8.5.2.2. Partial update (BOS only)

Action: Updates only the bos value. All other parameters (over_ask_factor, labels, nickname) are unaffected.

{
"id": "3257ff3b-b26e-40eb-9ee6-88d3f82f5701",
"bos": 0.5
}
8.5.2.3. Remove assigned labels

Action: Removes all labels from the bettor by passing an empty values array.

{
"id": "3257ff3b-b26e-40eb-9ee6-88d3f82f5701",
"labels": {
"values": []
}
}
8.5.2.4. Update nickname

Action: Updates only the nickname.

{
"id": "3257ff3b-b26e-40eb-9ee6-88d3f82f5701",
"nickname": "nickname2"
}
8.5.2.5. Update constraints

Action: Updates both bos and over_ask_factor simultaneously.

{
"id": "3257ff3b-b26e-40eb-9ee6-88d3f82f5701",
"bos": 1,
"over_ask_factor": 9.95
}