Run The Day
Find races and register fast
- Category
- Consumer & Lifestyle
- Primary Subcategory
- Race Registration
Integration details
Description
Run The Day enables runners to quickly discover upcoming races and complete registration through a conversational, low-friction experience. Users can search for relevant events, view key race details, and securely register with integrated payment, all without navigating complex forms. The platform syncs registrations directly with the Run The Day ecosystem, ensuring accurate runner creation, confirmation emails, and real-time event management for race directors. RTD is designed to minimise drop-offs, accelerate registration, and modernise endurance event participation.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Secondary Subcategories
- None listed
- Brand
- Run The Day
- Access
- No account required
- First tracked
- 2026-06-04
- Tool count
- 6
- Geography
- US
Other Subcategories where the Integration is listed.
Get alerts for Run The Day
Get updates when Run The Day’s Discoverability Score or category rank changes.
ChatGPT Plugin Discovery Score
ChatGPT Plugin discovery is coming soon
ChatGPT can surface a Plugin when it matches a user's request.Your Plugin Discovery Score measures how often yours appears.
No spam. Unsubscribe any time.
What discovery looks like

Competing in ChatGPT Race Registration
View Category6 tools agents can invoke
RunTheDay race database — the ONLY source of race data in this app. Call immediately for: 'show races', 'find races', 'browse races', 'upcoming races', 'show events', 'register for a race', 'i want to register'. NEVER use web search. All results are running events (5K, 10K, marathon). Pass city name to `city` and state/country to `state` if user mentions a location, else empty strings. Pass a keyword (e.g. 'half marathon', 'trail run') to `query` if the user describes a race type instead of/in addition to a location. ZIP code lookups are not supported directly — ask for or infer a city/state instead. For 'near me' requests, pass `radius` in miles plus `user_latitude`/`user_longitude` if known. If user names a race that exactly matches one already returned by this tool earlier in the session → call registerForRace directly instead. Otherwise — including the FIRST time a race is mentioned, even inside a registration request like 'I want to register for X' — call THIS tool with the race name/description passed to `query`. Never pass an unconfirmed name straight to registerForRace. AUTO-RESOLVED SINGLE MATCH: when `query` was a specific race name/description (not a general 'show races' browse) AND exactly one race matched, this tool ALREADY calls registerForRace for you server-side and returns its result under structuredContent.resolvedRace — you do NOT need to (and should NOT) call registerForRace separately in this case. Detect it by structuredContent.resolvedRace being present. When present: content[0].text already contains the full race name/events/registration-types/prices — copy it EXACTLY as-is into your reply (every line, bullet, price — do NOT use the generic one-sentence reply in this case), then ask the user for the fields it requests. Use structuredContent.resolvedRace.raceId (NOT any id from the `races` array) for the getRaceRegistrationFields/completeRaceRegistration calls that follow. DO NOT call this tool again with the same query/city/state after it already returned successfully — one call is enough, whether or not resolvedRace was present. A successful response is never a reason to retry: reply with its content[0].text and then STOP and wait for the user's next message. Calling it two or three times in a row for the same search makes the widget flicker/duplicate and adds pointless delay. When structuredContent.resolvedRace is ABSENT (raceCount is 0 — no match, tell the user — or more than 1 — ambiguous, let the widget show candidates and wait for the user to pick one): PAGINATION: First call always uses offset=0 and limit=10. When user says 'show more races' or 'load more': call this tool again with offset incremented by 10 (e.g. 10, 20, 30). Keep all other params the same. The widget will update to show ALL races including the new ones. AFTER TOOL RETURNS, WHEN structuredContent.resolvedRace IS ABSENT: output ONLY the exact text from content[0].text verbatim. Do NOT list races, do NOT add suggestions, do NOT mention locations or distances. The widget already shows all races — your text response must be exactly one sentence.
findRaces
Call as soon as the user has told you the event and registration type (registerForRace/findRaces's AWAITING_EVENT_SELECTION step asks for exactly those two, nothing else) — do NOT wait for first name, last name, email, or phone, and do NOT call this right after registerForRace before a registration type is known. Call it right after the user replies with event + registration type, and before completeRaceRegistration. Do NOT ask the user for first name/last name/email/phone/age/DOB/address/etc. yourself before calling this — that field list only comes from here; inventing it yourself causes duplicate questions once you do call this tool. Individual registration only — this app does not support group/family registration. Pass the raceId from registerForRace's structuredContent.raceId or findRaces' structuredContent.resolvedRace.raceId if you have it. If you don't have it in your current context (e.g. it was resolved in an earlier turn you can't see), OMIT raceId entirely rather than inventing one, refusing, or asking the user for it — the server automatically falls back to the most recently resolved race for this conversation. Pass the exact registrationType name the user selected (e.g. 'Runner') — some fields (like shirt size) depend on which registration type was chosen. Shirt styles, add-on products, and team eligibility are ALSO specific to the registration type — a different type for the same race can have a completely different shirt/add-on catalog. If you already called this tool earlier in the conversation for a DIFFERENT registration type, that response's catalog is now stale and does NOT apply — never merge, carry over, or reuse a shirt/add-on item from a prior call into this one; use only what THIS call's content[0].text/structuredContent actually returned. Looks up whether this race's director enabled extra fields beyond first name, last name, email, event, and registration type — possible fields are age, date of birth, gender, expected pace, shirt size, address, emergency contact, and disclaimer agreement. AFTER TOOL RETURNS: content[0].text is pre-split into paragraphs (separated by a blank line) — one paragraph per conversational step, entirely dynamic on what THIS race actually has configured (a race with no shirts/add-ons/donation/teams still ends with the coupon paragraph, so there are always at least 2). Send ONLY ONE paragraph per chat message, in order, and WAIT for the user's reply before sending the next one — never send two or more of these paragraphs together in the same turn, even if they seem short or related (e.g. the team paragraph and the coupon paragraph are two separate asks — finish one, get their answer, then move to the next). Copy each paragraph verbatim when you send it (don't rewrite, reformat, or merge it with another). Order: STEP 1 — the required-fields paragraph (and, right after the user answers it, the disclaimer paragraph too if this race has one — that's its own follow-up message, then wait again for their yes/no before moving on): already written as one flowing sentence covering first name, last name, email, phone number, and every extra field this race's director requires (age, DOB, address, gender, pace, emergency contact, etc. — whichever this specific race actually enabled). Send it and WAIT — do NOT also send any later paragraph yet. IF you're calling this tool late — the user already volunteered some or all of this info earlier in the conversation, e.g. as a catch-up right before completeRaceRegistration — do NOT resend this paragraph as a new question; read it silently, match it against what the user already told you, and only ask about anything genuinely still missing (or nothing, and skip straight to STEP 2, if you already have it all). STEP 2 — every remaining paragraph, one topic per turn: this race's own optional catalog extras (if any — shirt, then add-ons, then donation, then team, in that order, whichever this race actually has), and finally the coupon-code question, which always comes last. Send the next paragraph, wait for the user's reply, then send the following one — repeat until the coupon paragraph has been sent and answered. Never invent a shirt style/size, add-on product, or any other line not actually in one of these paragraphs — including one you remember from an earlier getRaceRegistrationFields call for a DIFFERENT registration type this same conversation; that catalog is stale and doesn't carry over, always use only what THIS call actually returned. As each reply comes in: when a shirt catalog (style + sizes) was shown, collect BOTH shirtStyle and shirtSize for completeRaceRegistration instead of a free-text guess; when only a plain shirt-size ask was shown (no catalog for this registration type), just take shirtSize as plain text — shirt STYLE is always optional even when size is required. Pass chosen add-ons as addOnSelections. Treat the donation paragraph as optional — pass an amount as donationAmount only if the user wants one. If a team paragraph was shown, it offers both joining an existing team and creating a new one — find out which the user wants; if joining, call getRaceTeams next to get the real team list/ids (never invent a team id); if creating, just take their chosen team name and pass teamChoice 'create' with it as teamName directly to completeRaceRegistration (no need to call getRaceTeams first for that path); otherwise leave teamChoice as 'none'. Read their answer to the coupon paragraph and pass it as couponCode to completeRaceRegistration (empty if they said no) — do NOT ask the coupon question again separately, it was already asked here. Never insist on anything from STEP 2, all of it is optional. Then call completeRaceRegistration — never skip this tool call before it.
getRaceRegistrationFields
Call ONLY after getRaceRegistrationFields reported teamsAllowed: true for the selected registration type AND the user said they want to join or see a team — never call this speculatively. Pass raceId if you have it; OMIT it rather than inventing one — the server falls back to the most recently resolved race for this conversation, same as the other registration tools. AFTER TOOL RETURNS: if status is TEAMS_READY, show the user the team names from structuredContent.teams and ask them to pick one (or say they'd rather create a new team). If status is NO_TEAMS, tell the user no teams exist yet and ask if they'd like to create one. Once the user decides, pass their choice into completeRaceRegistration: teamChoice 'join' + the chosen team's id as teamId, or teamChoice 'create' + their chosen name as teamName. If the user doesn't want a team at all, leave teamChoice as 'none' (or omit it) — it is never required.
getRaceTeams
Call when user asks if payment went through or registration is confirmed, OR proactively — a turn or two after completeRaceRegistration sent a payment link and the user hasn't confirmed payment yet — to offer a status check instead of waiting to be asked. Pass session_id from completeRaceRegistration's structuredContent.payment.session_id.
Call once the user has provided first name, last name, email, phone, and event/registration type choice. BEFORE calling this tool, if you haven't already called getRaceRegistrationFields in this conversation for this race+registrationType, call it first — it tells you which extra fields (age, DOB, address, etc.) must also be collected before submitting. If the user already gave you their info before you called it (i.e. this is a late catch-up call, not the normal flow where you call it right after event + registration type), do NOT resend its content[0].text as a new question — just use it to confirm you already have everything it requires, and only ask the user about anything it lists that they haven't actually told you yet. The coupon question is already asked for you, as the LAST paragraph of getRaceRegistrationFields's STEP 2 sequence — its own separate message, sent (and answered) after any shirt/add-on/donation/team paragraphs have each had their own turn. Do NOT ask 'Do you have a coupon code?' again as a separate message here. Just read the user's answer to that paragraph and pass it as couponCode (empty if they said no). If getRaceRegistrationFields was skipped or its STEP 2 hasn't happened yet this conversation, ask it yourself as one quick message before calling this tool — every race may or may not have a coupon and there's no way to check in advance, so it's always asked exactly once. If the call fails with error code INVALID_COUPON, COUPON_EXPIRED, or COUPON_LIMIT_REACHED, tell the user their code didn't work (using the message provided) and ask whether they want to try a different code or continue without one, then call this tool again accordingly. Handles: guest token → session → (optional coupon validation) → register → payment (Stripe, or a direct confirmation when a coupon covers the full amount). raceId: pass the exact value from the most recent registerForRace/findRaces result if you have it in context. If you don't (e.g. it was resolved earlier in the conversation and isn't visible to you now), OMIT it rather than inventing one or refusing to proceed — the server automatically falls back to the most recently resolved race for this conversation, so it's safe to call this tool without it as long as the user has already been shown a specific race this session. AFTER TOOL RETURNS: copy content[0].text EXACTLY as-is into your reply, INCLUDING the Registration Summary bullets when present — do not summarize or drop them. Then check structuredContent.status: If REGISTRATION_COMPLETE — this means a coupon discounted the amount due to $0 and the registration was confirmed directly, with nothing charged. Treat this exactly like a successful payment: tell the user they're fully registered, don't mention Stripe or a payment link (there is none — payment_url is null), and don't call checkRacePaymentStatus for this registration on a later turn — there is no session to check. If PAYMENT_SESSION_CREATED — an amount is due. Copy content[0].text's last two lines EXACTLY as-is, character for character, INCLUDING the markdown — do not reformat, unwrap, or replace the link with the raw URL, do not rewrite '💳 **[Complete Payment](...)**' as plain text. That markdown link is the button — some clients also render an actual clickable button widget below your reply, but the markdown link must be there regardless so the user can always pay even when they don't. Example reply: '**Registration Summary**\n• Race: ...\n• Amount due: $38.45\n\nRegistration pending.\n\n💳 **[Complete Payment](https://...)**'. Remember structuredContent.payment.session_id — on your NEXT turn (unless the user already confirmed payment or asked something unrelated), proactively ask whether the payment went through and offer to check via checkRacePaymentStatus using that session_id. Do not wait for the user to ask first. If getRaceRegistrationFields reported extra required fields for this race, pass them in their matching named properties below — the call fails with MISSING_REQUIRED_FIELD if any are missing. shirtStyle/donationAmount/addOnSelections/teamChoice are ALWAYS optional, even when getRaceRegistrationFields showed catalog options for them — only pass what the user actually chose, never invent a selection.
Call ONLY when the race name/slug you're passing has already been confirmed — i.e. it exactly matches a race findRaces returned earlier in this session. If this is the first mention of the race (including inside a request like 'I want to register for X'), call findRaces with `query` set to that phrase FIRST instead — do not guess a slug from unconfirmed user phrasing. NEVER web search for race info — this tool is the only data source. Pass exact race name or slug as `slug`. CRITICAL — AFTER TOOL RETURNS: copy content[0].text EXACTLY as-is into your reply — every line, every bullet point, every price. Do NOT summarize, rephrase, reorder, or omit ANY section. The user MUST see BOTH the Events section AND the Registration Types & Prices section — omitting either means the user cannot complete registration. On NOT_FOUND: do NOT stop and do NOT ask the user to repeat themselves — immediately call findRaces with `query` set to the same text you passed as `slug`, so the widget can surface real candidate races to pick from. AFTER a successful lookup (status AWAITING_EVENT_SELECTION): ask the user for ONLY the event and registration type first, exactly as content[0].text asks — do NOT ask for first/last name, email, phone, age, or any other participant detail yourself, and do NOT call getRaceRegistrationFields until they've replied with event + registration type. Once they reply, call getRaceRegistrationFields next (needs the registration type) — its own description explains how to send its content[0].text as a sequence of separate step messages rather than one dense reply. Never compose that field list yourself — it only comes from getRaceRegistrationFields.
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.