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.
Using ChatGPT, Claude or Gemini? You don't need any of this
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.
https://api.formfav.com/v1/openapi.jsonInteractive documentation is also available at https://api.formfav.com/v1/docs (Swagger UI).
Fastest setup
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.
import os
api_key = os.environ["FORMFAV_API_KEY"]
# Use in requests
headers = {"X-API-Key": api_key}Never hardcode API keys
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.
A key in browser code is public
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:
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 interpretationKnown 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:
winProbvalues 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.
Reduce hallucinations
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
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
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
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
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.
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}")Works with any LLM framework
get() function as a tool and any agent framework (LangChain, CrewAI, Claude tool_use, OpenAI function calling) can invoke it autonomously.JavaScript / Node.js Example
The same flow in Node.js using the built-in fetch API.
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
- Quickstart guide — full walkthrough of your first API call
- Race Form endpoint — complete field reference for form data
- Predictions endpoint — win/place probability model (Pro)
- Subscription Tiers — compare Free, Pro, and Enterprise features