Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.fieldfunded.com/llms.txt

Use this file to discover all available pages before exploring further.

Build a Discord Odds Bot Your Community Will Actually Use

A bot that serves live sports odds directly in your Discord server. Users type /odds Lakers and get real-time lines with team logos.

What You’ll Use

SDK MethodEndpointPurpose
search()GET /v1/searchFind events by team name
getEventOdds()GET /v1/events/{id}/oddsGet odds for a specific event
getScores()GET /v1/scoresGet live scores
getLive()GET /v1/liveList all live events

Prerequisites

npm init -y
npm install discord.js @fieldfunded/sdk

Step 1: Initialize Both SDKs

import { Client, GatewayIntentBits, EmbedBuilder, SlashCommandBuilder, REST, Routes } from 'discord.js';
import { FieldFundedSDK } from '@fieldfunded/sdk';

const discord = new Client({ intents: [GatewayIntentBits.Guilds] });
const ff = new FieldFundedSDK({
  apiKey: process.env.FIELDFUNDED_API_KEY!,
  baseUrl: 'https://api.fieldfunded.com/v1',
});

Step 2: Register Slash Commands

const commands = [
  new SlashCommandBuilder()
    .setName('odds')
    .setDescription('Get live odds for a team')
    .addStringOption(opt =>
      opt.setName('team').setDescription('Team name').setRequired(true)
    ),
  new SlashCommandBuilder()
    .setName('scores')
    .setDescription('Show all live scores')
    .addStringOption(opt =>
      opt.setName('sport').setDescription('Filter by sport (e.g. soccer)')
    ),
];

// Register commands on bot startup
const rest = new REST().setToken(process.env.DISCORD_TOKEN!);
await rest.put(
  Routes.applicationCommands(process.env.DISCORD_CLIENT_ID!),
  { body: commands.map(c => c.toJSON()) }
);

Step 3: Handle /odds Command

Uses search() to find the team, then getEventOdds() for market data:
discord.on('interactionCreate', async (interaction) => {
  if (!interaction.isChatInputCommand()) return;

  if (interaction.commandName === 'odds') {
    await interaction.deferReply();
    const team = interaction.options.getString('team', true);

    // Search for the team using the SDK
    const results = await ff.search(team, { limit: 3 });

    if (!results.events || results.events.length === 0) {
      await interaction.editReply(`No upcoming events found for "${team}"`);
      return;
    }

    const event = results.events[0];

    // Get odds for main markets
    const odds = await ff.getEventOdds(event.id);

    const embed = new EmbedBuilder()
      .setTitle(`${event.home_team} vs ${event.away_team}`)
      .setDescription(`${event.league}${event.sport}`)
      .setColor(0x53FC18)
      .addFields(
        { name: 'Status', value: event.status, inline: true },
        { name: 'Start', value: new Date(event.start_time).toLocaleString(), inline: true },
      );

    // Add main market odds
    if (odds.markets && odds.markets.length > 0) {
      const mainMarket = odds.markets[0]; // Usually 1x2 or Winner
      const oddsStr = mainMarket.selections
        .map((s: any) => `**${s.name}**: ${s.odds}`)
        .join(' | ');
      embed.addFields({ name: mainMarket.name, value: oddsStr });
    }

    await interaction.editReply({ embeds: [embed] });
  }
});

Step 4: Handle /scores Command

Uses getScores() — the lightweight endpoint optimized for frequent polling:
if (interaction.commandName === 'scores') {
  await interaction.deferReply();
  const sport = interaction.options.getString('sport') || undefined;

  const data = await ff.getScores({ sport });

  if (!data.scores || data.scores.length === 0) {
    await interaction.editReply('No live games right now.');
    return;
  }

  const embed = new EmbedBuilder()
    .setTitle('🔴 Live Scores')
    .setColor(0xFF0000);

  // Show up to 10 games
  for (const game of data.scores.slice(0, 10)) {
    embed.addFields({
      name: `${game.home_team} vs ${game.away_team}`,
      value: `**${game.score.home} - ${game.score.away}** • ${game.league}`,
    });
  }

  await interaction.editReply({ embeds: [embed] });
}

Step 5: Deploy

discord.login(process.env.DISCORD_TOKEN!);
Deploy to Railway (free tier) or any Node.js host. Set environment variables: DISCORD_TOKEN, DISCORD_CLIENT_ID, FIELDFUNDED_API_KEY.

Rate Limit Awareness

The free tier gives you 10,000 req/month. With a Discord bot:
  • Each /odds command = 2 requests (search + odds)
  • Each /scores command = 1 request
  • 10,000 / 2 = ~5,000 /odds commands per month on the free tier
That’s more than enough for a community server.

Search API Reference

See search endpoint docs →

Live Scores Reference

See scores endpoint docs →

Get Your Free API Key

Start building in 5 minutes — 10,000 free requests/month