FanDuel API endpoint
Returns one race in full: its conditions, every entry with morning-line and current odds (fractional and decimal), recent price history, runners (jockey, trainer, owner, pedigree, weight, age, scratch and jockey-change flags, win probability), pool totals, probable payouts, will-pays for multi-race bets, the wagers it accepts with their limits, and, once it is official, the finish order and payoffs. Pools, probables and will-pays appear only when the track reports them (mostly official and Up Next races). Pass `include` to add optional groups: `handicapping` (speed, class, pace, jockey-trainer record, power rating, career record and the favorite rank of every runner), `timeform` (Timeform analyst and production comments, tissue price, flags and, once official, how each finisher was beaten, its starting price and a post-race report) and `pool_grids` (the money bet on each entry's pairings in every pool, mostly once the race is official). A race that is not on today's card returns 404.
/fanduel/racing/racetrack (required): track code from the tracks route, such as LRL. Malformed codes return 400.number (required): race number, 1 to 99. Other values return 400. A race that is not on today's card returns 404.include (optional, repeat the parameter or comma-separate): optional groups to add. Allowed values: handicapping, timeform, pool_grids. Any other value returns 400. Values are case-insensitive and repeats are ignored. The response's included lists the groups that were applied (canonical order), so an absent group is never mistaken for missing data.include)handicapping adds, to every runner, handicapping and favorite_rank. handicapping holds up to six groups: speed_and_class (avg_class_rating, high_speed, normalised_speed_rating, high_speed_ranking, avg_speed, last_class_rating, avg_distance), average_pace (early, middle, finish, races), jockey_trainer (names, entity ids, starts, wins, places, shows of that pairing), snapshot (power_rating, normalised_power_rating, power_rating_ranking, days_off, horse_wins, horse_starts), free_pick (number, info) and past_results (starts, first, second, third, win_percentage, top3_percentage and their rankings such as 2nd). The service sends a group with every figure at zero for a runner with no history (a first-time starter); such a group is left out, so an absent group means no history, never zero. favorite_rank ranks the runner within the race, 1 being the favorite, by current_odds, morning_line, high_speed and power_rating.timeform adds, to every runner, timeform with analyst_comment, production_comment, tissue_price (Timeform's own decimal price, omitted when 0), free_pick and flags, the list of Timeform flags that are true. Flags: horse_in_focus, warning_horse, jockey_uplift, trainer_uplift, horse_for_course_positive, horse_for_course_negative, hot_trainer, cold_trainer, sectional_flag, significant_improver, jockey_in_form, clear_top_rated, interesting_jockey_booking, first_time_blinkers, highest_last_speed_rating. For an official race it also adds to every entry of results.finishers an entry number and timeform: beaten_lengths and beaten_text (for example 4.25 and 4ΒΌ), total_beaten_lengths and total_beaten_text (the margin to the winner), starting_price (decimal) and post_race_report. Many tracks send none of this and many runners have no analyst comment; those fields are simply omitted. rating_stars and form_figures on a runner are always present when the service has them, with or without this group.pool_grids adds, to every entry, pool_grids: one grid per pool with wager_type and cells, each {target, amount, status}. The entry is the grid's owner. For an exacta or a quinella target is the other entry, for a daily double it is the entry in the next race, and for win, place and show pools there is no target and the single cell is the money on the entry itself. Cells with no money and no status are left out. The service fills grids mostly once a race is official; an early open race returns none.entries are the numbers a bet names. current_odds and morning_line are given as fractional (3/2; a bare numerator such as 6 is 6/1) and decimal (2.5); recent_odds is the price history, newest first, with the service's trending flag.pools, probables and will_pays are filled only when the track reports them. On 2026-10-23, 100 of 494 races had pools: 59 official, 34 Up Next, 4 Race Off and 4 open; will-pays appeared on 12. Otherwise they are empty lists, so an open race early in the card usually has none.results is present for an official race. A race the service reports as refunded has no finishers and one payoff whose selection is Refund (a French race on 2026-10-23, among 9 of 64 official races).wagers lists the wager types the race accepts with their minimum and maximum; decode a code with the wager-types route.track_condition is shown when the service knows it (for example Fast), and omitted when it reports Unknown.Data is read from FanDuel Racing's own public service and is shown as published at the time of the request; it is not a betting recommendation, and prices, pools and statuses change by the minute. 503 on upstream failure.
{
"included": ["handicapping", "timeform", "pool_grids"],
"entries": [
{
"number": 1,
"runners": [
{
"name": "Glory Run",
"form_figures": "114",
"rating_stars": 3,
"handicapping": {
"speed_and_class": { "avg_class_rating": 76, "high_speed": 80, "normalised_speed_rating": 61, "avg_speed": 69, "last_class_rating": 85, "avg_distance": 80 },
"average_pace": { "early": 3.2, "middle": 1.6, "finish": 2.3, "races": 3 },
"jockey_trainer": { "jockey_name": "Achard Alex", "trainer_name": "Ennis John", "starts": 82, "wins": 12, "places": 6, "shows": 13 },
"snapshot": { "power_rating": 77, "normalised_power_rating": 59.23, "days_off": 74, "horse_wins": 2, "horse_starts": 3 },
"past_results": { "starts": 3, "first": 2, "second": 0, "third": 0, "win_percentage": 66.67, "top3_percentage": 66.67, "win_percentage_ranking": "2nd" }
},
"favorite_rank": { "current_odds": 6, "morning_line": 6, "high_speed": 4, "power_rating": 5 },
"timeform": { "analyst_comment": "Began career with two wins. ...", "tissue_price": 34, "flags": [] }
}
],
"pool_grids": [
{ "wager_type": { "code": "EX", "name": "Exacta" }, "cells": [ { "target": 2, "amount": 431 }, { "target": 3, "amount": 374 } ] },
{ "wager_type": { "code": "WN", "name": "Win" }, "cells": [ { "amount": 2821 } ] }
]
}
],
"results": {
"finishers": [
{ "position": 2, "number": "7", "entry": 7, "timeform": { "beaten_lengths": 4.25, "beaten_text": "4ΒΌ", "total_beaten_lengths": 4.25, "total_beaten_text": "4Β½ lengths", "starting_price": 5.24, "post_race_report": "out,4p turn,earned2nd" } }
]
}
}
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| track | string | Yes | Track code from the `tracks` route, such as `LRL` | BOL | |
| number | string | Yes | Race number, 1 to 99, such as `2` | 2 | |
| include | string | No | Optional groups to add (repeat the parameter or comma-separate): `handicapping` per-runner handicapping figures and favorite rank, `timeform` Timeform comments, tissue price, flags and finisher timing, `pool_grids` per-entry pool pairings. Other values return `400` Allowed values: handicapping, timeform, pool_grids. | ||
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/fanduel/racing/race?track=BOL&number=2&include=handicapping" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"data": {
"id": "BOL-2",
"track_code": "BOL",
"track_name": "SE - Bollnas",
"country": "SWE",
"number": "2",
"race_date": "2026-10-23",
"mtp": 40,
"post_time": "2026-10-23T16:42:00Z",
"status": {
"code": "IC",
"name": "Up Next"
},
"race_type": {
"code": "H",
"name": "Harness"
},
"surface": {
"code": "D",
"name": "Dirt"
},
"race_class": {
"code": "T",
"name": "Trot"
},
"distance": "2140mtr",
"purse": 7372,
"runner_count": 11,
"live_streaming": true,
"tvg_race_id": 4062845,
"claiming_price": 0,
"wagerable_runner_count": 10,
"has_replay": true,
"entries": [
{
"number": 1,
"number_color": "#FFFFFF",
"saddle_color": "#AF0000",
"favorite": false,
"morning_line": {
"fractional": "99/1",
"decimal": 100
},
"current_odds": {
"fractional": "20/1",
"decimal": 21
},
"recent_odds": [
{
"odds": "20",
"trending": false
}
],
"runners": [
{
"runner_id": "1",
"name": "Frozen Assets",
"jockey": "Zeb Jonasson",
"trainer": "Mikael Cedergren",
"owner": "Croon Per-Anders & Cedergren Mikael",
"sire": "S.J.'s Caviar",
"dam": "Jalna Boko",
"sex": "G",
"age": 3,
"weight": 0,
"scratched": false,
"jockey_changed": false,
"win_probability": 0.1
}
]
}
],
"pools": [
{
"wager_type": {
"code": "EX",
"name": "Exacta"
},
"amount": 15322
}
],
"probables": [
{
"wager_type": {
"code": "EX",
"name": "Exacta"
},
"amount": 15322,
"pool_amount_total": 15426.39,
"min_wager": 1,
"combos": [
{
"runner1": "1",
"runner2": "1",
"payout": "0.0"
}
]
}
],
"will_pays": [],
"wagers": [
{
"wager_type": {
"code": "WN",
"name": "Win"
},
"min_wager": 1,
"max_wager": 10000
}
],
"included": [],
"last_updated_ms": 1792771361463,
"fetched_at": "2026-10-23T16:09:31Z"
},
"msg": "OK"
}Request schema
No body schema
Response schema
#/definitions/fanduel.racingRaceResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| code | integer | No | 200 | |||
| data | fanduel.RacingRaceResponse | No | ||||
| data.age_restriction | string | No | ||||
| data.analyst_verdict | string | No | ||||
| data.claiming_price | number | No | ||||
| data.country | string | No | ||||
| data.description | string | No | ||||
| data.distance | string | No | ||||
| data.entries | array | No | ||||
| data.entries[].current_odds | fanduel.RacingOdds | No | ||||
| data.entries[].current_odds.decimal | number | No | ||||
| data.entries[].current_odds.fractional | string | No | ||||
| data.entries[].favorite | boolean | No | ||||
| data.entries[].morning_line | fanduel.RacingOdds | No | ||||
| data.entries[].morning_line.decimal | number | No | ||||
| data.entries[].morning_line.fractional | string | No | ||||
| data.entries[].number | integer | No | ||||
| data.entries[].number_color | string | No | ||||
| data.entries[].pool_grids | array | No | include=pool_grids | |||
| data.entries[].pool_grids[].cells | array | No | ||||
| data.entries[].pool_grids[].cells[].amount | number | No | ||||
| data.entries[].pool_grids[].cells[].status | string | No | ||||
| data.entries[].pool_grids[].cells[].target | integer | No | ||||
| data.entries[].pool_grids[].wager_type | fanduel.RacingCodeName | No | ||||
| data.entries[].pool_grids[].wager_type.code | string | No | ||||
| data.entries[].pool_grids[].wager_type.name | string | No | ||||
| data.entries[].recent_odds | array | No | ||||
| data.entries[].recent_odds[].odds | string | No | ||||
| data.entries[].recent_odds[].trending | boolean | No | ||||
| data.entries[].runners | array | No | ||||
| data.entries[].runners[].age | integer | No | ||||
| data.entries[].runners[].dam | string | No | ||||
| data.entries[].runners[].dam_sire | string | No | ||||
| data.entries[].runners[].favorite_rank | fanduel.RacingFavoriteRank | No | ||||
| data.entries[].runners[].favorite_rank.current_odds | integer | No | ||||
| data.entries[].runners[].favorite_rank.high_speed | integer | No | ||||
| data.entries[].runners[].favorite_rank.morning_line | integer | No | ||||
| data.entries[].runners[].favorite_rank.power_rating | integer | No | ||||
| data.entries[].runners[].form_figures | string | No | ||||
| data.entries[].runners[].handicapping | fanduel.RacingHandicapping | No | ||||
| data.entries[].runners[].handicapping.average_pace | fanduel.RacingAveragePace | No | ||||
| data.entries[].runners[].handicapping.average_pace.early | number | No | ||||
| data.entries[].runners[].handicapping.average_pace.finish | number | No | ||||
| data.entries[].runners[].handicapping.average_pace.middle | number | No | ||||
| data.entries[].runners[].handicapping.average_pace.races | integer | No | ||||
| data.entries[].runners[].handicapping.free_pick | fanduel.RacingFreePick | No | ||||
| data.entries[].runners[].handicapping.free_pick.info | string | No | ||||
| data.entries[].runners[].handicapping.free_pick.number | integer | No | ||||
| data.entries[].runners[].handicapping.jockey_trainer | fanduel.RacingJockeyTrainer | No | ||||
| data.entries[].runners[].handicapping.jockey_trainer.jockey_entity_id | integer | No | ||||
| data.entries[].runners[].handicapping.jockey_trainer.jockey_name | string | No | ||||
| data.entries[].runners[].handicapping.jockey_trainer.places | integer | No | ||||
| data.entries[].runners[].handicapping.jockey_trainer.shows | integer | No | ||||
| data.entries[].runners[].handicapping.jockey_trainer.starts | integer | No | ||||
| data.entries[].runners[].handicapping.jockey_trainer.trainer_entity_id | integer | No | ||||
| data.entries[].runners[].handicapping.jockey_trainer.trainer_name | string | No | ||||
| data.entries[].runners[].handicapping.jockey_trainer.wins | integer | No | ||||
| data.entries[].runners[].handicapping.past_results | fanduel.RacingPastResults | No | ||||
| data.entries[].runners[].handicapping.past_results.first | integer | No | ||||
| data.entries[].runners[].handicapping.past_results.second | integer | No | ||||
| data.entries[].runners[].handicapping.past_results.starts | integer | No | ||||
| data.entries[].runners[].handicapping.past_results.third | integer | No | ||||
| data.entries[].runners[].handicapping.past_results.top3_percentage | number | No | ||||
| data.entries[].runners[].handicapping.past_results.top3_percentage_ranking | string | No | ||||
| data.entries[].runners[].handicapping.past_results.win_percentage | number | No | ||||
| data.entries[].runners[].handicapping.past_results.win_percentage_ranking | string | No | ||||
| data.entries[].runners[].handicapping.snapshot | fanduel.RacingSnapshot | No | ||||
| data.entries[].runners[].handicapping.snapshot.days_off | integer | No | ||||
| data.entries[].runners[].handicapping.snapshot.horse_starts | integer | No | ||||
| data.entries[].runners[].handicapping.snapshot.horse_wins | integer | No | ||||
| data.entries[].runners[].handicapping.snapshot.normalised_power_rating | number | No | ||||
| data.entries[].runners[].handicapping.snapshot.power_rating | number | No | ||||
| data.entries[].runners[].handicapping.snapshot.power_rating_ranking | string | No | ||||
| data.entries[].runners[].handicapping.speed_and_class | fanduel.RacingSpeedAndClass | No | ||||
| data.entries[].runners[].handicapping.speed_and_class.avg_class_rating | number | No | ||||
| data.entries[].runners[].handicapping.speed_and_class.avg_distance | number | No | ||||
| data.entries[].runners[].handicapping.speed_and_class.avg_speed | number | No | ||||
| data.entries[].runners[].handicapping.speed_and_class.high_speed | number | No | ||||
| data.entries[].runners[].handicapping.speed_and_class.high_speed_ranking | string | No | ||||
| data.entries[].runners[].handicapping.speed_and_class.last_class_rating | number | No | ||||
| data.entries[].runners[].handicapping.speed_and_class.normalised_speed_rating | number | No | ||||
| data.entries[].runners[].jockey | string | No | ||||
| data.entries[].runners[].jockey_changed | boolean | No | ||||
| data.entries[].runners[].medication | string | No | ||||
| data.entries[].runners[].name | string | No | ||||
| data.entries[].runners[].owner | string | No | ||||
| data.entries[].runners[].rating_stars | integer | No | ||||
| data.entries[].runners[].runner_id | string | No | ||||
| data.entries[].runners[].scratched | boolean | No | ||||
| data.entries[].runners[].sex | string | No | ||||
| data.entries[].runners[].sire | string | No | ||||
| data.entries[].runners[].timeform | object | No | Set only with include=timeform and include=handicapping. | |||
| data.entries[].runners[].timeform.analyst_comment | string | No | ||||
| data.entries[].runners[].timeform.flags | array | No | ||||
| data.entries[].runners[].timeform.free_pick | fanduel.RacingFreePick | No | ||||
| data.entries[].runners[].timeform.free_pick.info | string | No | ||||
| data.entries[].runners[].timeform.free_pick.number | integer | No | ||||
| data.entries[].runners[].timeform.production_comment | string | No | ||||
| data.entries[].runners[].timeform.tissue_price | number | No | ||||
| data.entries[].runners[].trainer | string | No | ||||
| data.entries[].runners[].weight | integer | No | ||||
| data.entries[].runners[].win_probability | number | No | ||||
| data.entries[].saddle_color | string | No | ||||
| data.fetched_at | string | No | ||||
| data.has_replay | boolean | No | ||||
| data.id | string | No | ||||
| data.included | array | No | ||||
| data.last_updated_ms | integer | No | ||||
| data.live_streaming | boolean | No | ||||
| data.mtp | integer | No | ||||
| data.number | string | No | ||||
| data.pools | array | No | ||||
| data.pools[].amount | number | No | ||||
| data.pools[].wager_type | fanduel.RacingCodeName | No | ||||
| data.pools[].wager_type.code | string | No | ||||
| data.pools[].wager_type.name | string | No | ||||
| data.post_time | string | No | ||||
| data.probables | array | No | ||||
| data.probables[].amount | number | No | ||||
| data.probables[].combos | array | No | ||||
| data.probables[].combos[].payout | string | No | ||||
| data.probables[].combos[].runner1 | string | No | ||||
| data.probables[].combos[].runner2 | string | No | ||||
| data.probables[].min_wager | number | No | ||||
| data.probables[].pool_amount_total | number | No | ||||
| data.probables[].wager_type | fanduel.RacingCodeName | No | ||||
| data.probables[].wager_type.code | string | No | ||||
| data.probables[].wager_type.name | string | No | ||||
| data.purse | number | No | ||||
| data.race_class | fanduel.RacingCodeName | No | ||||
| data.race_class.code | string | No | ||||
| data.race_class.name | string | No | ||||
| data.race_date | string | No | ||||
| data.race_type | fanduel.RacingCodeName | No | ||||
| data.race_type.code | string | No | ||||
| data.race_type.name | string | No | ||||
| data.results | fanduel.RacingResults | No | ||||
| data.results.finishers | array | No | ||||
| data.results.finishers[].entry | integer | No | Set only with include=timeform. | |||
| data.results.finishers[].finish_status | string | No | ||||
| data.results.finishers[].number | string | No | ||||
| data.results.finishers[].place_payoff | number | No | ||||
| data.results.finishers[].position | integer | No | ||||
| data.results.finishers[].runner | string | No | ||||
| data.results.finishers[].show_payoff | number | No | ||||
| data.results.finishers[].silk_url | string | No | ||||
| data.results.finishers[].timeform | fanduel.RacingFinisherTimeform | No | ||||
| data.results.finishers[].timeform.beaten_lengths | number | No | ||||
| data.results.finishers[].timeform.beaten_text | string | No | ||||
| data.results.finishers[].timeform.post_race_report | string | No | ||||
| data.results.finishers[].timeform.starting_price | number | No | ||||
| data.results.finishers[].timeform.total_beaten_lengths | number | No | ||||
| data.results.finishers[].timeform.total_beaten_text | string | No | ||||
| data.results.finishers[].win_payoff | number | No | ||||
| data.results.payoffs | array | No | ||||
| data.results.payoffs[].selections | array | No | ||||
| data.results.payoffs[].selections[].payout | number | No | ||||
| data.results.payoffs[].selections[].qualifier | string | No | ||||
| data.results.payoffs[].selections[].selection | string | No | ||||
| data.results.payoffs[].wager_amount | number | No | ||||
| data.results.payoffs[].wager_type | fanduel.RacingCodeName | No | ||||
| data.results.payoffs[].wager_type.code | string | No | ||||
| data.results.payoffs[].wager_type.name | string | No | ||||
| data.results.winning_time | number | No | ||||
| data.runner_count | integer | No | ||||
| data.status | fanduel.RacingCodeName | No | ||||
| data.status.code | string | No | ||||
| data.status.name | string | No | ||||
| data.surface | fanduel.RacingCodeName | No | ||||
| data.surface.code | string | No | ||||
| data.surface.name | string | No | ||||
| data.track_code | string | No | ||||
| data.track_condition | string | No | ||||
| data.track_name | string | No | ||||
| data.tvg_race_id | integer | No | ||||
| data.wagerable_runner_count | integer | No | ||||
| data.wagers | array | No | ||||
| data.wagers[].max_wager | number | No | ||||
| data.wagers[].min_wager | number | No | ||||
| data.wagers[].wager_type | fanduel.RacingCodeName | No | ||||
| data.wagers[].wager_type.code | string | No | ||||
| data.wagers[].wager_type.name | string | No | ||||
| data.will_pays | array | No | ||||
| data.will_pays[].leg_results | array | No | ||||
| data.will_pays[].leg_results[].leg | integer | No | ||||
| data.will_pays[].leg_results[].winning_entry | integer | No | ||||
| data.will_pays[].payoff_type | string | No | ||||
| data.will_pays[].payouts | array | No | ||||
| data.will_pays[].payouts[].entry | integer | No | ||||
| data.will_pays[].payouts[].payout | number | No | ||||
| data.will_pays[].payouts[].required | number | No | ||||
| data.will_pays[].wager_amount | number | No | ||||
| data.will_pays[].wager_type | fanduel.RacingCodeName | No | ||||
| data.will_pays[].wager_type.code | string | No | ||||
| data.will_pays[].wager_type.name | string | No | ||||
| msg | string | No | OK |
| Status | Description | Schema |
|---|---|---|
| 400 | Bad Request | #/definitions/app.Response |
| 404 | Not Found | #/definitions/app.Response |
| 503 | Service Unavailable | #/definitions/app.Response |
Use environment variables for secrets and keep Crawlora API keys server-side.
curl -X GET "https://api.crawlora.net/api/v1/fanduel/racing/race?track=BOL&number=2&include=handicapping" \
-H "x-api-key: $CRAWLORA_API_KEY"