Using FormFav with AI Agents

    Connect the FormFav horse racing API to Claude, GPT, Gemini, and other AI assistants for automated race analysis, prediction models, and data-driven betting tools. A free key covers race form, meetings and career stats; Pro adds predictions and statistics.

    OpenAPI Spec for Auto-Configuration

    FormFav publishes a machine-readable OpenAPI 3.x specification. Agent frameworks like LangChain, CrewAI, and custom tool-use implementations can ingest this URL to auto-generate tool definitions for every endpoint, parameter, and response shape.

    OpenAPI Spec URL
    https://api.formfav.com/v1/openapi.json

    Interactive documentation is also available at https://api.formfav.com/v1/docs (Swagger UI).

    Passing Your API Key Securely

    No key yet? Get a free one at formfav.com/get-api-key. Always load your API key from an environment variable. Never paste it directly into prompts, chat windows, or source code.

    python
    import os
    
    api_key = os.environ["FORMFAV_API_KEY"]
    
    # Use in requests
    headers = {"X-API-Key": api_key}

    Calling from a Browser App

    Apps built in the browser, such as Google AI Studio, Lovable, Bolt, v0 or Replit Agent previews, can call the read-only data endpoints (GET /v1/form, /v1/results, /v1/predictions, /v1/stats, /v1/prices) directly from the page. Send the key in the X-API-Key header. Cookies and credentials are not used.

    Giving Context to Your AI (System Prompts)

    AI assistants perform significantly better when given explicit context about an API's domain and constraints. Include a snippet like this in your agent's system message or tool description:

    Recommended system prompt context
    You have access to the FormFav horse racing API.
    
    Base URL: https://api.formfav.com/v1
    Auth: X-API-Key header (key is in the FORMFAV_API_KEY environment variable)
    
    Key endpoints:
    - GET /form/meetings?date=YYYY-MM-DD&race_code=gallops  — list race meetings for a date
    - GET /form?date=YYYY-MM-DD&track=SLUG&race=N  — full race form with runners and stats
    - GET /predictions?date=YYYY-MM-DD&track=SLUG&race=N  — win/place probabilities (Pro tier)
    - GET /stats/jockey/{name}  — jockey performance statistics (Pro tier)
    - GET /stats/trainer/{name}  — trainer performance statistics (Pro tier)
    - GET /stats/track-bias/{track}  — barrier bias analysis, per distance band or scoped with ?distance=1200 / ?distance=1200-1600 (Pro tier)
    - GET /stats/runner/{name}  — runner career stats and form analysis (Pro tier)
    - GET /form/venues  — look up track names and slugs
    
    Parameters:
    - date: YYYY-MM-DD format (default timezone: Australian Eastern time, configurable via timezone param)
    - track: lowercase slug (e.g. "randwick", "flemington") — use /form/venues to look up
    - race_code: "gallops" (default), "harness", or "greyhounds"
    - country: "au" (default), "nz", "hk", "gb", "us", "eu"
    - timezone: IANA timezone (e.g. "Australia/Sydney") for date interpretation

    Known Limitations to Tell Your Agent

    Including these constraints in your system prompt prevents the agent from hallucinating capabilities the API doesn't have.

    • •Stats data window: Jockey, trainer, and runner statistics cover a rolling period from approximately 2019 onwards, not all-time career data.
    • •Prediction scores are probabilities: winProb values across runners in a race sum to approximately 1.0. They are model probabilities, not arbitrary confidence scores.
    • •Coverage: thoroughbred, harness, and greyhound racing across 24+ countries.
    • •Rate limits: Free tier allows 1,000 requests/day. Pro allows 20,000/day. See Rate Limiting.
    • •Live data is tier-dependent: On Free and Pro the API provides pre-race form and predictions, plus results for completed races batch-ingested every 2–3 hours rather than streamed — no live odds or real-time results. Premium and Enterprise add live bookmaker prices, results as races settle, and live scratchings, track condition and weather. No tier provides in-running positions.

    Example Prompts That Work Well

    These prompts work across Claude, GPT, Gemini, and other AI assistants. They reference specific endpoints and parameters, which helps the agent make accurate API calls.

    Race analysis

    text
    Get the form for Race 7 at Flemington on 2026-03-29. Summarise each runner's recent form, highlight anyone with a track win rate above 30%, and flag first-up runners.

    Prediction comparison

    text
    Pull predictions for all races at Randwick tomorrow. For each race, compare the model's top pick with the likely favourite based on form and explain where they differ.

    Jockey research

    text
    Get jockey stats for James McDonald at Rosehill. What is his strike rate at this track compared to his overall strike rate? How does he perform on heavy tracks?

    Multi-meeting scan

    text
    List all meetings tomorrow. For each gallops meeting, get race 1 and find any runner with 3 or more wins from their last 5 starts.

    Python Agent Example

    A complete Python example that fetches today's meetings, picks the first gallops meeting, and retrieves the race form for race 1.

    formfav_agent.py
    import os
    import requests
    from datetime import date
    
    API_KEY = os.environ["FORMFAV_API_KEY"]
    BASE = "https://api.formfav.com/v1"
    HEADERS = {"X-API-Key": API_KEY}
    
    def get(endpoint, params=None):
        """Make a GET request with retry on rate limit."""
        resp = requests.get(f"{BASE}{endpoint}", headers=HEADERS, params=params)
        if resp.status_code == 429:
            wait = int(resp.headers.get("Retry-After", 60))
            print(f"Rate limited — waiting {wait}s")
            import time; time.sleep(wait)
            resp = requests.get(f"{BASE}{endpoint}", headers=HEADERS, params=params)
        resp.raise_for_status()
        return resp.json()
    
    # 1. Get today's meetings
    today = date.today().isoformat()
    meetings = get("/form/meetings", {"date": today, "race_code": "gallops"})
    
    if not meetings.get("meetings"):
        print("No gallops meetings today")
        exit()
    
    # 2. Pick the first meeting
    track = meetings["meetings"][0]["slug"]
    print(f"Fetching Race 1 at {track} on {today}")
    
    # 3. Get race form
    card = get("/form", {"date": today, "track": track, "race": 1})
    
    # 4. Print runner summary
    for runner in card.get("runners", []):
        name = runner.get("name", "Unknown")
        jockey = runner.get("jockey", "—")
        form = runner.get("last10Starts", "—")
        print(f"  {runner.get('number', '?')}. {name} (J: {jockey}) — Form: {form}")

    JavaScript / Node.js Example

    The same flow in Node.js using the built-in fetch API.

    formfav_agent.mjs
    const API_KEY = process.env.FORMFAV_API_KEY;
    const BASE = "https://api.formfav.com/v1";
    
    async function get(endpoint, params = {}) {
      const url = new URL(BASE + endpoint);
      Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
      const resp = await fetch(url, { headers: { "X-API-Key": API_KEY } });
      if (!resp.ok) throw new Error(`${resp.status} ${resp.statusText}`);
      return resp.json();
    }
    
    // 1. Get today's meetings
    const today = new Date().toISOString().slice(0, 10);
    const meetings = await get("/form/meetings", { date: today, race_code: "gallops" });
    
    if (!meetings.meetings?.length) {
      console.log("No gallops meetings today");
      process.exit();
    }
    
    // 2. Pick the first meeting and fetch race 1
    const track = meetings.meetings[0].slug;
    console.log(`Fetching Race 1 at ${track} on ${today}`);
    
    const card = await get("/form", { date: today, track, race: "1" });
    
    // 3. Print runner summary
    for (const r of card.runners ?? []) {
      console.log(`  ${r.number}. ${r.name} (J: ${r.jockey}) — Form: ${r.last10Starts ?? "—"}`);
    }

    Next Steps