Tips Feed Integration

Welcome to the LSports Tips Feed Integration Guide !


Overview

LSports Tips Feed is a real-time betting insights distribution service that processes and delivers data-driven tips to customers through RabbitMQ.

It enables sportsbooks, affiliates, and media or analytics platforms to enhance user engagement and betting activity by providing timely, intelligence-backed recommendations that guide users toward the most relevant markets and deepen in-play interaction.

By automating the delivery of statistically validated tips across both PreMatch and InPlay events, the system empowers customers to drive betting volume, strengthen retention, and build user confidence — all while maintaining transparency and full control over the tip generation process.

The system supports:

  • PreMatch Tips — for scheduled fixtures

  • InPlay Tips — for live and ongoing events

Step 1: Access Credentials

Get your Username, Password, and CustomerPackageId from your CSM.

You will receive access to two RabbitMQ virtual hosts:

  • /fixtures – pre-event metadata

  • /tips – real-time tips (added/removed)

Step 2: Queue Provisioning

For each vhost, LSports provisions a queue per customer.

Queue name (both vhosts): _{CustomerPackageId}_

Encoding: UTF-8 JSON

Transport: AMQP 0-9-1 over TLS (port 5671)

Step 3: Establish Connections

Open two AMQP connections (one per vhost) and consume from the same queue name on each vhost:

  • /fixtures_{CustomerPackageId}_

  • /tips_{CustomerPackageId}_

Integration examples in C#, Python, and Java appear under Code Samples below.

Step 4: Data Mapping

Fixtures: subscribe to /fixtures and persist by body.fixtureId.

  • Delta updates only (messages are sent only on change).

  • Use add or update: unknown fixture ⇒ add; known fixture ⇒ update changed fields.

Tips: subscribe to /tips and correlate by body.fixtureId against your fixtures store.

  • Two message kinds: Added (1) and Removed (2).

  • For Added, you get full tip objects; for Removed, you get IDs to remove.


Message Structure

For each message type, fields that are null are omitted from the payload to deliver the lightest possible message.

Common Header

Field
Type
Nullable
Notes

MessageId

string (GUID)

No

Unique per message; UUID v4

Timestamp

ISO-8601 (UTC)

No

UTC

MessageType

int (enum)

No

1 = Fixture, 3 = Tips

Fixtures (shared contract)

{
  "header": {
    "MessageId": "d9e1a4e6-2a44-4a3d-9bbd-0a9a7f5e1c2d",
    "Timestamp": "2025-11-04T19:45:00Z",
    "MessageType": 1
  },
  "body": {
    "fixtureId": 123456,
    "status": 1,
    "startDate": "2025-11-04T19:45:00Z",
    "sport": { "id": 6046, "name": "Football" },
    "league": { "id": 1001, "name": "Premier League" },
    "location":{ "id": 250, "name": "England" },
    "participants": [
      { "id": 9001, "name": "Arsenal", "position": 1 },
      { "id": 9002, "name": "Chelsea", "position": 2 }
    ]
  }
}

Fields (body)

Field
Type
Nullable
Notes

fixtureId

int

No

Join key for tips/incidents

status

int (numeric enum)

No

See Fixture Status (numeric enum)

startDate

ISO-8601 (UTC)

No

Scheduled start

sport.id / sport.name

int / string

No

Sport metadata

league.id / league.name

int / string

No

League metadata

location.id / location.name

int / string

No

Country/venue

participants

array of Participant objects

No

Ordered by position (home/away)

Participant (object)

Field
Type
Nullable
Notes

id

int

No

Participant id

name

string

No

Participant name

position

int (numeric enum)

No

1 = home, 2 = away

Fixture Status (numeric enum)

Value
Name
Description

1

NSY

Fixture is in the pre-match phase (not started yet).

2

InProgress

Fixture is live and currently in play.

3

Finished

Fixture has ended and results are confirmed.

4

Cancelled

Event will not take place or requires recreation under a new Id.

5

Postponed

Fixture is postponed; may later return to NSY with an updated start time.

6

Interrupted

Temporarily stopped (e.g., weather); resumes under the same fixture Id.

7

Abandoned

Permanently stopped and will not resume.

8

LostCoverage

Coverage lost; may later become InProgress/Interrupted/Abandoned/Finished.

9

AboutToStart

Fixture is about to begin shortly.

Tips

Added Tips — Example (tipEventType = 1)

{
  "header": {
    "MessageId": "5f7a9d5a-44c0-4f1e-9d24-2a93d6e7b0a1",
    "Timestamp": "2025-11-04T19:50:00Z",
    "MessageType": 3,
    "tipEventType": 1
  },
  "body": {
    "fixtureId": 123456,
    "status": 2,
    "tips": [
      {
        "id": "TIP_001",
        "marketId": 1,
        "betName": "Match Winner",
        "line": "1.85",
        "text": "Home team to win",
        "playerId": 501,
        "isHomeTeamTip": true,
        "language": "en"
      }
    ]
  }
}

Fields — Added (tipEventType = 1)

Field
Type
Nullable
Notes

fixtureId

int

No

Join to fixtures

status

int (FixtureStatus)

No

Fixture status at update time

tips

array of Tip objects

No

Added/updated tips for this fixture

Tip (object)

Field
Type
Nullable
Notes

id

string

No

Tip id

marketId

int

No

Market identifier

betName

string

No

Market/bet label

line

string

Yes

Odds line or relevant value

text

string

Yes

Tip description

playerId

int

Yes

If applicable

isHomeTeamTip

bool

Yes

true = home, false = away/neutral

language

string

Yes

ISO language code (e.g., "en")

Removed Tips — Example (tipEventType = 2)

{
  "header": {
    "MessageId": "d8a17f3d-0f5b-4d0e-9d2d-2a1f4a8b9c3e",
    "Timestamp": "2025-11-04T19:52:00Z",
    "MessageType": 3,
    "tipEventType": 2
  },
  "body": {
    "fixtureId": 123456,
    "status": 2,
    "tips": ["TIP_001", "TIP_002"]
  }
}

Fields — Removed (tipEventType = 2)

Field
Type
Nullable
Notes

fixtureId

int

No

Join to fixtures

status

int (FixtureStatus)

No

Status at update time

tips

array of string

No

Tip IDs to remove


Code Samples

C# — Two vhosts / Same queue name

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;

var fixturesFactory = new ConnectionFactory {
    HostName = "your-rabbitmq-host",
    Port = 5671,
    UserName = "fixtures-username",
    Password = "fixtures-password",
    VirtualHost = "fixtures",
    Ssl = new SslOption { Enabled = true, ServerName = "your-rabbitmq-host" }
};

using var fxConn = fixturesFactory.CreateConnection();
using var fxCh = fxConn.CreateModel();
string qname = $"_{customerPackageId}_";
fxCh.QueueDeclare(qname, durable: true, exclusive: false, autoDelete: false);

var tipsFactory = new ConnectionFactory {
    HostName = "your-rabbitmq-host",
    Port = 5671,
    UserName = "tips-username",
    Password = "tips-password",
    VirtualHost = "tips",
    Ssl = new SslOption { Enabled = true, ServerName = "your-rabbitmq-host" }
};

using var tpConn = tipsFactory.CreateConnection();
using var tpCh = tpConn.CreateModel();
tpCh.QueueDeclare(qname, durable: true, exclusive: false, autoDelete: false);

void Consume(IModel ch, string queue, Action<string> handle) {
    var consumer = new EventingBasicConsumer(ch);
    consumer.Received += (_, ea) => handle(Encoding.UTF8.GetString(ea.Body.ToArray()));
    ch.BasicConsume(queue: queue, autoAck: true, consumer: consumer);
}

Consume(fxCh, qname, json => {
    // Upsert fixture by body.fixtureId (delta-only)
});

Consume(tpCh, qname, json => {
    // Parse header.tipEventType: 1=Added, 2=Removed
    // Join by body.fixtureId; for Added: body.tips[] (Tip objects); for Removed: body.tips[] (IDs)
});

Python (pika) — Two vhosts / Same queue name

import ssl, pika, json, threading

def mk_conn(vhost, user, pwd):
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    return pika.BlockingConnection(pika.ConnectionParameters(
        host='your-rabbitmq-host', port=5671, virtual_host=vhost,
        credentials=pika.PlainCredentials(user, pwd),
        ssl_options=pika.SSLOptions(ctx, server_hostname='your-rabbitmq-host')
    ))

def run_consumer(vhost, user, pwd, qname, on_message):
    conn = mk_conn(vhost, user, pwd)
    ch = conn.channel()
    ch.queue_declare(queue=qname, durable=True, exclusive=False, auto_delete=False)
    ch.basic_consume(queue=qname, on_message_callback=on_message, auto_ack=True)
    try:
        ch.start_consuming()
    finally:
        try: conn.close()
        except: pass

def on_fixture(ch, method, props, body):
    m = json.loads(body.decode('utf-8'))
    # upsert by m['body']['fixtureId']

def on_tip(ch, method, props, body):
    m = json.loads(body.decode('utf-8'))
    # kind = m['header'].get('tipEventType') # 1=Added, 2=Removed
    # if kind == 1: iterate Tip objects in m['body']['tips']
    # if kind == 2: remove IDs in m['body']['tips']

qname = f"_{customer_package_id}_"
t_fx = threading.Thread(target=run_consumer, args=('fixtures', 'fixtures-username', 'fixtures-password', qname, on_fixture), daemon=True)
t_tp = threading.Thread(target=run_consumer, args=('tips', 'tips-username', 'tips-password', qname, on_tip), daemon=True)
t_fx.start(); t_tp.start(); t_fx.join(); t_tp.join()

Java — Two vhosts / Same queue name

import com.rabbitmq.client.*;

String q = "_" + customerPackageId + "_";

// /fixtures
ConnectionFactory f1 = new ConnectionFactory();
f1.setHost("your-rabbitmq-host");
f1.setPort(5671);
f1.setUsername("fixtures-username");
f1.setPassword("fixtures-password");
f1.setVirtualHost("fixtures");
f1.useSslProtocol();

Connection fxConn = f1.newConnection();
Channel fxCh = fxConn.createChannel();
fxCh.queueDeclare(q, true, false, false, null);

// /tips
ConnectionFactory f2 = new ConnectionFactory();
f2.setHost("your-rabbitmq-host");
f2.setPort(5671);
f2.setUsername("tips-username");
f2.setPassword("tips-password");
f2.setVirtualHost("tips");
f2.useSslProtocol();

Connection tpConn = f2.newConnection();
Channel tpCh = tpConn.createChannel();
tpCh.queueDeclare(q, true, false, false, null);

DeliverCallback fxCb = (tag, d) -> {
    String json = new String(d.getBody(), "UTF-8");
    // upsert by body.fixtureId (delta-only)
};

DeliverCallback tpCb = (tag, d) -> {
    String json = new String(d.getBody(), "UTF-8");
    // parse header.tipEventType (1=Added, 2=Removed)
    // join by body.fixtureId
};

fxCh.basicConsume(q, true, fxCb, tag -> {});
tpCh.basicConsume(q, true, tpCb, tag -> {});

Tips Text Placeholder Replacement Rules

This page describes how placeholders inside Tip Text are dynamically replaced with fixture participant names based on the isHomeTeamTip flag.

1. {participant} Placeholder

The {participant} placeholder is dynamically replaced with one of the fixture teams. The selected team depends on the isHomeTeamTip property.

Replacement Logic

  • If isHomeTeamTip = true{participant} = Home team

  • If isHomeTeamTip = false{participant} = Away team

Received Tip

The sum of runs during the 9th inning was less than 2.5, in all of the last 10 away matches that {participant} trailed by the end of the 8th inning.

Example Resolution

  • Home Team: Boston Red Sox

  • Away Team: New York Yankees

  • isHomeTeamTip: false

Resolved Tip

The sum of runs during the 9th inning was less than 2.5, in all of the last 10 away matches that New York Yankees trailed by the end of the 8th inning.

2. {participant} and {opponent} Placeholders

Some tips contain both placeholders:

3 of the last 5 away meetings by {participant} against {opponent} ended with less than 14.5 runs.

Replacement Logic

  • Resolve {participant} using the same rule as before

  • Resolve {opponent} as the opposite team:

    • If {participant} = Home → {opponent} = Away

    • If {participant} = Away → {opponent} = Home

Example Resolution

  • Home Team: Los Angeles Dodgers

  • Away Team: San Diego Padres

  • isHomeTeamTip: true

Replacements:

  • {participant} → Los Angeles Dodgers

  • {opponent} → San Diego Padres

Resolved Tip

3 of the last 5 away meetings by Los Angeles Dodgers against San Diego Padres ended with less than 14.5 runs.

3. {league} Placeholder

The {league} placeholder is used in tips that reference historical performance within a specific competition or league. It should be replaced with the league name associated with the fixture (e.g., MLB, NFL, NBA, Premier League, etc.).

Replacement Logic

Replace {league} with the competition name of the current fixture. This field is taken directly from the fixture's metadata.

Example Tip

{participant} didn't lose in 3 of their last 10 matches played in {league}

Example Resolution

  • Home Team: Atlanta Braves

  • Away Team: Philadelphia Phillies

  • isHomeTeamTip: true

  • Fixture League: MLB

Replacements:

  • {participant} → Atlanta Braves

  • {league} → MLB

Resolved Tip

Atlanta Braves didn't lose in 3 of their last 10 matches played in MLB

4. {player} Placeholder

The {player} placeholder is used in tips that reference individual player performance. It must be replaced with the player name provided by the tip data model.

Replacement Logic

Replace {player} with the player's full name supplied in the tip payload.

{opponent} is replaced according to the existing team logic:

  • If isHomeTeamTip = true, {opponent} = Away team

  • If isHomeTeamTip = false, {opponent} = Home team

Example Tip

{player} scored a goal in 3 of his last 5 matches against {opponent}

Example Resolution

  • Home Team: Liverpool FC

  • Away Team: West Ham United

  • isHomeTeamTip: true

  • Player: Cody Gakpo

Replacements:

  • {player} → Cody Gakpo

  • {opponent} → West Ham United

Resolved Tip

Cody Gakpo scored a goal in 3 of his last 5 matches against West Ham United

Last updated

Was this helpful?