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 WhatsApp Sports Alert System

Automate sports alerts for your friend group: game kickoffs, significant odds shifts, and final scores with settlement results.

What You’ll Use

SDK MethodEndpointPurpose
getEvents()GET /v1/eventsFind upcoming games
getEventOdds()GET /v1/events/{id}/oddsTrack odds changes
getScores()GET /v1/scoresGet live scores
getEventResult()GET /v1/events/{id}/resultGet final result

Prerequisites

  • Twilio account (free trial works)
  • Twilio WhatsApp Sandbox activated
  • Node.js 18+
npm install @fieldfunded/sdk twilio node-cron

Step 1: Initialize

import { FieldFundedSDK } from '@fieldfunded/sdk';
import twilio from 'twilio';
import cron from 'node-cron';

const ff = new FieldFundedSDK({
  apiKey: process.env.FIELDFUNDED_API_KEY!,
  baseUrl: 'https://api.fieldfunded.com/v1',
});

const sms = twilio(process.env.TWILIO_SID!, process.env.TWILIO_AUTH!);
const WHATSAPP_FROM = 'whatsapp:+14155238886'; // Twilio sandbox
const GROUP_NUMBERS = ['whatsapp:+351912345678']; // Your friends

Step 2: Alert Type 1 — Game Starting Soon

async function checkKickoffs() {
  const events = await ff.getEvents({
    sport: 'soccer',
    starts_within: '15m', // Games starting in 15 minutes
    status: 'prematch',
  });

  for (const event of events.events) {
    const odds = await ff.getEventOdds(event.id);
    const main = odds.markets?.[0];

    let message = `⚽ *Starting Soon!*\n`;
    message += `${event.home_team} vs ${event.away_team}\n`;
    message += `🏟️ ${event.league}\n`;
    message += `⏰ ${new Date(event.start_time).toLocaleTimeString()}\n`;

    if (main) {
      const oddsStr = main.selections
        .map((s: any) => `${s.name}: ${s.odds}`)
        .join(' | ');
      message += `📊 ${oddsStr}`;
    }

    await sendToGroup(message);
  }
}

Step 3: Alert Type 2 — Odds Movement

// Store previous odds in memory (or database for persistence)
const previousOdds = new Map<string, number>();

async function checkOddsMovement() {
  const live = await ff.getEvents({ status: 'live', sport: 'soccer' });

  for (const event of live.events.slice(0, 10)) {
    const odds = await ff.getEventOdds(event.id);
    const main = odds.markets?.[0];
    if (!main) continue;

    for (const sel of main.selections) {
      const key = `${event.id}-${sel.name}`;
      const prev = previousOdds.get(key);

      if (prev) {
        const change = Math.abs(sel.odds - prev) / prev;

        if (change > 0.1) { // 10% shift
          const direction = sel.odds > prev ? '📈' : '📉';
          await sendToGroup(
            `${direction} *Odds Alert*\n` +
            `${event.home_team} vs ${event.away_team}\n` +
            `${sel.name}: ${prev.toFixed(2)}${sel.odds.toFixed(2)} (${(change * 100).toFixed(0)}% shift)`
          );
        }
      }

      previousOdds.set(key, sel.odds);
    }
  }
}

Step 4: Alert Type 3 — Final Score

async function checkFinalScores() {
  // Track events we've already alerted
  const alerted = new Set<string>();

  const events = await ff.getEvents({ status: 'ended', sport: 'soccer' });

  for (const event of events.events.slice(0, 5)) {
    if (alerted.has(event.id)) continue;

    const result = await ff.getEventResult(event.id);

    if (result.status === 'ended' && result.score) {
      await sendToGroup(
        `🏁 *Full Time*\n` +
        `${event.home_team} *${result.score.home}* - *${result.score.away}* ${event.away_team}\n` +
        `🏟️ ${event.league}`
      );
      alerted.add(event.id);
    }
  }
}

Step 5: Send to Group

async function sendToGroup(message: string) {
  for (const number of GROUP_NUMBERS) {
    await sms.messages.create({
      from: WHATSAPP_FROM,
      to: number,
      body: message,
    });
  }
}

Step 6: Schedule Everything

// Check for kickoffs every 5 minutes
cron.schedule('*/5 * * * *', checkKickoffs);

// Check odds movement every 2 minutes during live games
cron.schedule('*/2 * * * *', checkOddsMovement);

// Check final scores every 3 minutes
cron.schedule('*/3 * * * *', checkFinalScores);

Rate Limit Math

CheckFrequencyRequests/hourMonthly
KickoffsEvery 5 min24~17,280
Odds movementEvery 2 min60~43,200
Final scoresEvery 3 min40~28,800
Total: ~89,000/month → Pro plan ($59/mo) covers it. To fit in the free tier, reduce to checking only your favorite leagues and extend intervals.

Events API Reference

See event filters (starts_within, status) →

Get Your Free API Key

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