Skip to content

Race

Object type

A single race within a meeting. Child of Meeting; parent container for Runner. Carries the race’s classification (type, surface, distance, class/pattern, handicap), eligibility, prize money, conditions overrides, and full lifecycle status. The auto-classified header-decomposition fields (jockeyCondition, experienceCondition, etc.) summarise the race’s conditions of entry in a queryable form.

FieldArgsTypeDescription
id—ID! requiredStable Podium identifier (UUID).
raceNumber—Int! required1-indexed position of the race on the meeting card. Values at or above 1000 are NOT card positions: they are reconciliation slots, where ingestion parks a race it could not place on the real card. No field returning a COLLECTION of races (racesForMeeting, upcomingRaces, Meeting.races) returns one, so every raceNumber reached that way is a real card position. The single exception is Meeting.reconciliationSlots, the operator surface that exists to return exactly those rows and nothing else; it is internal-tier, so it is not in your schema unless you are reading the operator one. Several routes still reach a parked race, and are meant to — each resolves ONE race, so it returns what was asked for: - race(id:), if you already hold the id. - Runner.race on an entry collection such as entriesForParticipant. A horse’s history includes its entry on the parked row. - Tip.race on tipsForDate, which is date-scoped rather than race-scoped. Editorial tier only — if tipsForDate is not in your schema, this route does not apply to you. Through any of those raceNumber may be >= 1000: check the value before treating it as a card position. Treat these as the routes worth naming rather than a closed set — the rule to rely on is the one above, that no field returning a COLLECTION OF RACES yields a parked row, bar the one field named there whose whole purpose is to. The two rules meet where a parked race points back at its own meeting, and the result looks inconsistent unless you are expecting it: from a parked Race, meeting.races does NOT contain the race you started from, and meeting.raceCount does not count it. That is the rule working, not a gap — the collection is the card, and a parked row is not on it. On the operator schema it is on meeting.reconciliationSlots instead. Ordering by raceNumber is safe; assuming it is CONTIGUOUS is not. Gaps are ordinary — a race deleted from a card, or moved to another meeting, leaves its number unused — so read it as a stable ordinal, never as an index into the returned list, and never infer the card size from its maximum (use Meeting.raceCount).
division—IntDivision number (1, 2, …) when a race is split into divisions because the field is oversubscribed; null for an undivided race. Each division is its own race with its own id, runners and result. Symmetric across UK (Weatherbys) and Irish (IHRB) racing.
scheduledTime—DateTime! requiredAdvertised off-time (with timezone). May change pre-race-day if the card is reshuffled; on race day this value is fixed even if the race starts late — the actual start time is captured on offTime.
offTime—DateTimeActual time the race went off. Populated post-race; null until then.
status—RaceStatus! required—
title—StringRace title from a titled feed (ED/OD/PD/IHRB/Calendar XML/RP-Calendar). Null until one lands — clients should render Race ${raceNumber} as the placeholder. On a reconciliation slot (see raceNumber) that placeholder reads as a card position the meeting does not have — “Race 1004” on an eight-race card. Worth knowing if you render a race reached by id, but treat it as a caveat rather than a rule you must already satisfy. The label problem is solved by CONTEXT rather than by this field — on the internal operator surface that lists these rows, they are labelled by the surface they appear on — so title stays the race’s own title and nothing else.
titleAbbreviated—StringShort title for compact displays (mobile, navigation). Null if the source did not provide one.
header—StringConditions-of-race header — the structured eligibility/penalty text that governs the race (distinct from title). Operationally important: gets decomposed into the jockeyCondition / experienceCondition / commerceCondition / handicapOption fields by the auto-classifier.
raceType—RaceType! required—
surface—SurfaceTypeRacing surface for this race. Null until a surface-bearing feed lands.
distance—DistanceRace distance. Null until a distance-bearing feed lands.
class—StringRace class as the CLASS_1–CLASS_7 enum form. Class and pattern are distinct elements, but a pattern race is always CLASS_1 (see pattern). Null until a class-bearing feed lands.
pattern—PatternTypePattern designation for prestige races: Group 1–3, Grade 1–3, or Listed (Group = flat, Grade = jumps — one field). Null for ordinary races. When set, class is always CLASS_1.
handicap—Boolean! requiredTrue when weights are assigned by official rating rather than race conditions.
eligibility—RaceEligibility—
goingOfficial—GoingTypeRace-level going override. When null, the race inherits meeting.conditions.going.official.
prizeMoney—PrizeMoney—
declarationStage—DeclarationStage! required—
sourceDeclarationType—StringProvider-specific declaration file type that produced the current declarationStage (e.g. WEATHERBYS_OD, IHRB_OVERNIGHT). Use for traceability back to the upstream feed; for lifecycle logic prefer the canonical declarationStage enum.
televised—Boolean! requiredTrue when the race is scheduled to be televised.
broadcasters—[Broadcaster!]! requiredBroadcasters (TV channels) that broadcast this race, ordered by name.
maxRunners—IntSafety factor — the maximum declared runners the course/feed allows for this race. Sourced from Weatherbys RP-Calendar or the XML calendar feed; null until either lands. Use as the denominator for “active / max” displays.
activeRunnerCount—Int! requiredActive declared runner count — excludes NON_DECLARED, NON_RUNNER, WITHDRAWN, and DISQUALIFIED entries. Use as a cheap “active runners” badge on race lists / tables where the full runners[] array would be over-fetch.
winningTimeSeconds—FloatWinning time in seconds. Populated once the race result has been settled.
stewardsInquiry—StringStatus of any stewards’ inquiry (NO_INQUIRY, STEWARDS_MAY_AFFECT, STEWARDS_NOT_AFFECT). Null when no inquiry has been called.
stewardsObjection—StringStatus of any objection raised. Null when no objection has been lodged.
stewardsResolution—StringResolution of an inquiry or objection (RESULT_STANDS, AMENDED_RESULT). Null until the matter is resolved.
jockeyCondition—JockeyConditionJockey-condition component of the race header (e.g. LADIES, APPRENTICE). Derived by auto-classification, editor-reviewable.
experienceCondition—ExperienceConditionExperience-condition component of the race header (NOVICE, MAIDEN).
commerceCondition—CommerceConditionCommerce-condition component of the race header (SELLER, CLAIMER, AUCTION).
handicapOption—HandicapOptionGranular handicap classification that supplements the boolean handicap field — distinguishes handicaps, conditional handicaps, conditions races, and stakes races.
headerConfidence—HeaderConfidenceAuto-classification confidence (HIGH, MEDIUM, LOW, MANUAL). MANUAL indicates an editor set the classification directly.
headerStatus—HeaderStatusEditorial workflow status for the header classification (auto-classified, editor-confirmed, editor-corrected, pending review).
headerClassifiedAt—DateTimeWhen the auto-classification pipeline last ran for this race.
headerReviewedBy—StringEditor who confirmed or corrected the classification, if any.
headerReviewedAt—DateTimeWhen the editor review took place.
headerClassificationDetail—HeaderClassificationDetailPer-field provenance and plausibility-rule diagnostics for the classification. Drives UI cues for uncertain fields.
abandonedReason—StringReason if the race has been abandoned (e.g. 'Course inspection failed'). Null otherwise.
abandonedAt—DateTimeTimestamp the race was abandoned. Null otherwise.
meeting—Meeting! requiredThe parent meeting this race belongs to.
runners—[Runner!]! requiredAll runner entries for this race — declared, reserve, non-runner, and withdrawn alike. Filter on Runner.status for the active field.
pendingNonRunners—[PendingNonRunner!]! requiredEntries held in PENDING_NON_RUNNER awaiting BHA verification. Empty when none are pending.
source—String! requiredOrigin of the race row. 'manual' for races created via createRace; otherwise the ingestion provider tag (commonly 'ingested'). Drives destructive-action gating: only source = 'manual' races may be deleted; ingested races use abandonRace.
version—Int! requiredOptimistic-locking version counter — increments on every write.
createdAt—DateTime! required—
updatedAt—DateTime! required—
provenance—RaceProvenance! requiredAggregate freshness derived from change_log — the most recent change across the race row and its runners, verdicts, tips and comments. Prefer this over updatedAt for “last updated” provenance UI: updatedAt only tracks writes to the race row itself and goes stale when only a child entity changes.