{"openapi":"3.1.0","info":{"title":"BowlRadar API","version":"1.0","description":"Read-only access to BowlRadar's directory of upcoming youth bowling events: the same search the site runs, as JSON or as a calendar feed.\n\n- The JSON search (`/api/events`) needs an API key, sent as an `X-API-Key` header (or `Authorization: Bearer`). Ask for one on My account; staff approve each request. See /developers.\n- Calendar feeds and the schedule embed need no key.\n- Responses can be called from any website (`Access-Control-Allow-Origin: *`); search results are cached for 5 minutes.\n- Events are listed as their organizers published them: names, dates, times, fees and awards are the hosts'. Confirm details with the tournament director before traveling.\n- An invalid filter is dropped rather than failing the request; `query` in the response shows what was applied.\n- Dates are calendar dates (YYYY-MM-DD). Times are the event's local time, with its zone in `timeZone`."},"servers":[{"url":"https://bowlradar.com"}],"tags":[{"name":"Events","description":"Search the directory."},{"name":"Calendars","description":"Subscribable calendar feeds (iCalendar)."},{"name":"Embedding","description":"A tour's schedule on another site, and tracked entry links."},{"name":"Status","description":"Which build is live, and whether it's healthy."}],"paths":{"/api/events":{"get":{"tags":["Events"],"summary":"Search events","description":"Upcoming published events matching every filter given, a page at a time. Without a date filter, events that haven't ended yet. Needs an API key.","security":[{"ApiKey":[]},{"Bearer":[]}],"parameters":[{"name":"q","in":"query","description":"Words to find in an event's title, summary, details, place, center (or its other names) or tour. Up to 120 characters. For example `Junior Gold`.","schema":{"type":"string","maxLength":120}},{"name":"zip","in":"query","description":"A 5-digit US ZIP code to measure from. With it, only events within `radius` miles are returned, each with `distanceMiles`, and events whose center isn't announced yet are left out (they can't be said to be within reach). An unknown ZIP code returns no origin and no distance filter. For example `22556`.","schema":{"type":"string","pattern":"^\\d{5}$"}},{"name":"radius","in":"query","description":"Miles from `zip`; 100 when not given. 5000 means anywhere, still ordered by distance.","schema":{"type":"integer","minimum":5,"maximum":5000,"default":100}},{"name":"state","in":"query","description":"Two-letter state code: events at a center in that state. For example `VA`.","schema":{"type":"string","enum":["AL","AK","AZ","AR","CA","CO","CT","DE","DC","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"]}},{"name":"when","in":"query","description":"A date window from today: `weekend` (the coming Friday to Sunday, or what's left of this one), the next `30` or `60` days, or a month (`2026-11`). `from` and `to` win over it. For example `30`.","schema":{"type":"string","pattern":"^(weekend|30|60|\\d{4}-(0[1-9]|1[0-2]))$"}},{"name":"from","in":"query","description":"First date (YYYY-MM-DD). An event counts when it ends on or after it, so one already under way is included. Without `from`, `when` or `includePast`, it's today (US Eastern).","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","description":"Last date (YYYY-MM-DD): events starting on or before it.","schema":{"type":"string","format":"date"}},{"name":"kind","in":"query","description":"One kind of event. `QUALIFIER` (Junior Gold qualifier) also matches tournaments that run a Junior Gold qualifier.","schema":{"type":"string","enum":["TOURNAMENT","QUALIFIER","CHAMPIONSHIP","ADULT_YOUTH","VIRTUAL","HIGH_SCHOOL"]}},{"name":"types","in":"query","description":"Several types, comma-separated; an event matching any of them is returned. `TOURNAMENT` (Tournament), `QUALIFIER` (Junior Gold qualifier), `CHAMPIONSHIP` (Championship), `SCHOLARSHIP` (Scholarship), `PBA_JR` (PBA Jr. qualifier), `HIGH_SCHOOL` (High school), `ADULT_YOUTH` (Adult / youth), `VIRTUAL` (Virtual). `SCHOLARSHIP` matches events offering scholarships; `PBA_JR` matches PBA Jr. qualifiers. For example `QUALIFIER,SCHOLARSHIP`.","schema":{"type":"string","pattern":"^[A-Z_]+(,[A-Z_]+)*$"}},{"name":"org","in":"query","description":"One tour or association, by its slug (the last part of its page's address, /tours/<slug>). For example `storm-youth-championships`.","schema":{"type":"string","maxLength":80}},{"name":"orgs","in":"query","description":"Up to ten tours or associations by slug, comma-separated; any matches.","schema":{"type":"string","pattern":"^[a-z0-9-]+(,[a-z0-9-]+){0,9}$"}},{"name":"venue","in":"query","description":"One center, by its slug (from `venue.slug` in a result).","schema":{"type":"string","maxLength":80}},{"name":"division","in":"query","description":"An age division the event lists, or `NONE` for events that don't list divisions yet (most).","schema":{"type":"string","enum":["U10","U12","U14","U15","U16","U18","U20","U22","U23","NONE"]}},{"name":"awards","in":"query","description":"An award the event offers, as published.","schema":{"type":"string","enum":["SCHOLARSHIP","CASH"]}},{"name":"season","in":"query","description":"A season, as `2026-27`.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}},{"name":"includePast","in":"query","description":"`true` (or `1`) to include events that have ended.","schema":{"type":"boolean","default":false}},{"name":"juniorGold","in":"query","description":"Older links: the same as `kind=QUALIFIER`.","schema":{"type":"boolean","default":false},"deprecated":true},{"name":"sort","in":"query","description":"`date` (soonest first), `distance` (nearest first; needs `zip`) or `prize` (largest stated prize fund first, events stating none after).","schema":{"type":"string","enum":["date","distance","prize"],"default":"date"}},{"name":"page","in":"query","description":"Page of results, from 1.","schema":{"type":"integer","minimum":1,"maximum":500,"default":1}},{"name":"perPage","in":"query","description":"Results per page, up to 300.","schema":{"type":"integer","minimum":1,"maximum":300,"default":25}}],"responses":{"200":{"description":"A page of matching events.","headers":{"Cache-Control":{"schema":{"type":"string","example":"public, max-age=300"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventSearch"}}}},"401":{"description":"No API key, or one that isn't valid (deleted, replaced or revoked).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"howToGetOne":{"type":"string"}}}}}}}}},"/api/calendar.ics":{"get":{"tags":["Calendars"],"summary":"A search as a calendar feed","description":"The same filters as `/api/events`, as an iCalendar feed of up to 100 events that calendar apps can subscribe to (use `webcal://` in place of `https://`). Each event's entry link goes through `/go`.","parameters":[{"name":"q","in":"query","description":"Words to find in an event's title, summary, details, place, center (or its other names) or tour. Up to 120 characters. For example `Junior Gold`.","schema":{"type":"string","maxLength":120}},{"name":"zip","in":"query","description":"A 5-digit US ZIP code to measure from. With it, only events within `radius` miles are returned, each with `distanceMiles`, and events whose center isn't announced yet are left out (they can't be said to be within reach). An unknown ZIP code returns no origin and no distance filter. For example `22556`.","schema":{"type":"string","pattern":"^\\d{5}$"}},{"name":"radius","in":"query","description":"Miles from `zip`; 100 when not given. 5000 means anywhere, still ordered by distance.","schema":{"type":"integer","minimum":5,"maximum":5000,"default":100}},{"name":"state","in":"query","description":"Two-letter state code: events at a center in that state. For example `VA`.","schema":{"type":"string","enum":["AL","AK","AZ","AR","CA","CO","CT","DE","DC","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"]}},{"name":"when","in":"query","description":"A date window from today: `weekend` (the coming Friday to Sunday, or what's left of this one), the next `30` or `60` days, or a month (`2026-11`). `from` and `to` win over it. For example `30`.","schema":{"type":"string","pattern":"^(weekend|30|60|\\d{4}-(0[1-9]|1[0-2]))$"}},{"name":"from","in":"query","description":"First date (YYYY-MM-DD). An event counts when it ends on or after it, so one already under way is included. Without `from`, `when` or `includePast`, it's today (US Eastern).","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","description":"Last date (YYYY-MM-DD): events starting on or before it.","schema":{"type":"string","format":"date"}},{"name":"kind","in":"query","description":"One kind of event. `QUALIFIER` (Junior Gold qualifier) also matches tournaments that run a Junior Gold qualifier.","schema":{"type":"string","enum":["TOURNAMENT","QUALIFIER","CHAMPIONSHIP","ADULT_YOUTH","VIRTUAL","HIGH_SCHOOL"]}},{"name":"types","in":"query","description":"Several types, comma-separated; an event matching any of them is returned. `TOURNAMENT` (Tournament), `QUALIFIER` (Junior Gold qualifier), `CHAMPIONSHIP` (Championship), `SCHOLARSHIP` (Scholarship), `PBA_JR` (PBA Jr. qualifier), `HIGH_SCHOOL` (High school), `ADULT_YOUTH` (Adult / youth), `VIRTUAL` (Virtual). `SCHOLARSHIP` matches events offering scholarships; `PBA_JR` matches PBA Jr. qualifiers. For example `QUALIFIER,SCHOLARSHIP`.","schema":{"type":"string","pattern":"^[A-Z_]+(,[A-Z_]+)*$"}},{"name":"org","in":"query","description":"One tour or association, by its slug (the last part of its page's address, /tours/<slug>). For example `storm-youth-championships`.","schema":{"type":"string","maxLength":80}},{"name":"orgs","in":"query","description":"Up to ten tours or associations by slug, comma-separated; any matches.","schema":{"type":"string","pattern":"^[a-z0-9-]+(,[a-z0-9-]+){0,9}$"}},{"name":"venue","in":"query","description":"One center, by its slug (from `venue.slug` in a result).","schema":{"type":"string","maxLength":80}},{"name":"division","in":"query","description":"An age division the event lists, or `NONE` for events that don't list divisions yet (most).","schema":{"type":"string","enum":["U10","U12","U14","U15","U16","U18","U20","U22","U23","NONE"]}},{"name":"awards","in":"query","description":"An award the event offers, as published.","schema":{"type":"string","enum":["SCHOLARSHIP","CASH"]}},{"name":"season","in":"query","description":"A season, as `2026-27`.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}},{"name":"includePast","in":"query","description":"`true` (or `1`) to include events that have ended.","schema":{"type":"boolean","default":false}},{"name":"juniorGold","in":"query","description":"Older links: the same as `kind=QUALIFIER`.","schema":{"type":"boolean","default":false},"deprecated":true}],"responses":{"200":{"description":"An iCalendar feed.","content":{"text/calendar":{"schema":{"type":"string"}}}}}}},"/api/my-events/{token}/calendar.ics":{"get":{"tags":["Calendars"],"summary":"A family's own events as a calendar feed","description":"The events a family marked Interested or Going, and those that ended in the last 60 days. The token is the secret in the link the family makes on My account; resetting it stops the old link.","parameters":[{"name":"token","in":"path","required":true,"description":"The secret from the family's feed link.","schema":{"type":"string","minLength":16}}],"responses":{"200":{"description":"An iCalendar feed.","content":{"text/calendar":{"schema":{"type":"string"}}}},"404":{"description":"No feed has that token."}}}},"/embed.js":{"get":{"tags":["Embedding"],"summary":"A tour's schedule on another website","description":"One script tag puts a list of upcoming events on any page, drawn in its own shadow root so styles never mix (no key needed):\n\n```html\n<script src=\"https://bowlradar.com/embed.js\" data-org=\"storm-youth-championships\" data-limit=\"10\" async></script>\n```\n\nIt reads `/api/embed/events`. Attributes: `data-org`, `data-state`, `data-kind`, `data-zip`, `data-radius` (as the search parameters) and `data-limit` (1 to 50, default 10). /embed builds the tag for a tour.","responses":{"200":{"description":"The script.","content":{"application/javascript":{"schema":{"type":"string"}}}}}}},"/api/embed/events":{"get":{"tags":["Embedding"],"summary":"What the embed draws","description":"The list `/embed.js` shows, with no key (it runs in visitors' browsers, where a key would be public): the first `limit` upcoming events of one search, with only the fields the list shows. For anything more, use `/api/events` with a key.","parameters":[{"name":"zip","in":"query","description":"A 5-digit US ZIP code to measure from. With it, only events within `radius` miles are returned, each with `distanceMiles`, and events whose center isn't announced yet are left out (they can't be said to be within reach). An unknown ZIP code returns no origin and no distance filter. For example `22556`.","schema":{"type":"string","pattern":"^\\d{5}$"}},{"name":"radius","in":"query","description":"Miles from `zip`; 100 when not given. 5000 means anywhere, still ordered by distance.","schema":{"type":"integer","minimum":5,"maximum":5000,"default":100}},{"name":"state","in":"query","description":"Two-letter state code: events at a center in that state. For example `VA`.","schema":{"type":"string","enum":["AL","AK","AZ","AR","CA","CO","CT","DE","DC","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"]}},{"name":"kind","in":"query","description":"One kind of event. `QUALIFIER` (Junior Gold qualifier) also matches tournaments that run a Junior Gold qualifier.","schema":{"type":"string","enum":["TOURNAMENT","QUALIFIER","CHAMPIONSHIP","ADULT_YOUTH","VIRTUAL","HIGH_SCHOOL"]}},{"name":"org","in":"query","description":"One tour or association, by its slug (the last part of its page's address, /tours/<slug>). For example `storm-youth-championships`.","schema":{"type":"string","maxLength":80}},{"name":"limit","in":"query","description":"How many, 1 to 50.","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}}],"responses":{"200":{"description":"The events to list.","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"title":{"type":"string"},"startDate":{"type":"string","format":"date"},"endDate":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]},"hasEntry":{"type":"boolean","description":"Whether `/go/{id}` leads to an entry page."},"venue":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"}}},{"type":"null"}]},"locationLabel":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}}}}}},"/go/{id}":{"get":{"tags":["Embedding"],"summary":"An event's entry link, counted","description":"Redirects to the entry page the organizer published for the event, counting the click toward the organizer's reach report. The destination comes from BowlRadar's own record, never the address, so it can't be pointed elsewhere.","parameters":[{"name":"id","in":"path","required":true,"description":"The event's `id`.","schema":{"type":"string"}},{"name":"from","in":"query","description":"Where the click came from, for the organizer's report; `detail` when not given.","schema":{"type":"string","enum":["detail","list","calendar","map","alert","feed","embed"],"default":"detail"}}],"responses":{"302":{"description":"To the organizer's entry page; to the event's page on BowlRadar when it has no entry link, and to the home page for an unknown id."}}}},"/api/version":{"get":{"tags":["Status"],"summary":"Which build is live","responses":{"200":{"description":"The running build.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Build"}}}}}}},"/api/health":{"get":{"tags":["Status"],"summary":"Whether the site and its database work","responses":{"200":{"description":"Healthy.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Build"},{"type":"object","properties":{"status":{"const":"ok"},"database":{"const":"ok"}}}]}}}},"503":{"description":"Not healthy.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Build"},{"type":"object","properties":{"status":{"const":"error"},"database":{"const":"error"},"error":{"type":"string"}}}]}}}}}}}},"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your key from My account (it starts with `br_`)."},"Bearer":{"type":"http","scheme":"bearer","description":"The same key as `Authorization: Bearer <key>`."}},"schemas":{"EventSearch":{"type":"object","required":["query","origin","total","page","pageCount","events"],"properties":{"query":{"type":"object","description":"The filters as applied, after dropping any that were invalid.","additionalProperties":true},"origin":{"anyOf":[{"type":"object","description":"Where a `zip` search measures from.","properties":{"zip":{"type":"string"},"lat":{"type":"number"},"lng":{"type":"number"},"city":{"type":"string"},"state":{"type":"string"}}},{"type":"null"}]},"total":{"type":"integer","description":"Matching events across all pages."},"page":{"type":"integer"},"pageCount":{"type":"integer"},"events":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}}},"Event":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","description":"The event's page on BowlRadar, relative to the site.","example":"/events/syc-florida-2027-02-13"},"title":{"type":"string","description":"As the organizer published it."},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"kind":{"type":"string","enum":["TOURNAMENT","QUALIFIER","CHAMPIONSHIP","ADULT_YOUTH","VIRTUAL","HIGH_SCHOOL"]},"startDate":{"type":"string","format":"date"},"endDate":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]},"timeLabel":{"anyOf":[{"type":"string","description":"The organizer's times as written.","example":"Check-in 9, bowling 10 am"},{"type":"null"}]},"startTime":{"anyOf":[{"type":"string","pattern":"^\\d{2}:\\d{2}$","description":"The first start time the organizer gave, on a 24-hour clock in `timeZone`; null when none was.","example":"10:00"},{"type":"null"}]},"timeZone":{"anyOf":[{"type":"string","description":"The IANA zone the times are in, from the center's location.","example":"America/New_York"},{"type":"null"}]},"dateConfirmed":{"type":"boolean","description":"False while the date may still move."},"venueConfirmed":{"type":"boolean","description":"False while the center isn't confirmed."},"juniorGoldQualifier":{"type":"boolean","description":"Runs a Junior Gold qualifier (besides events whose `kind` is `QUALIFIER`)."},"entryFeeCents":{"anyOf":[{"type":"integer","description":"Entry fee in cents, when published."},{"type":"null"}]},"feeNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationUrl":{"anyOf":[{"type":"string","description":"The organizer's entry page. Linking through `/go/{id}` counts the click for them."},{"type":"null"}]},"distanceMiles":{"anyOf":[{"type":"number","description":"From `zip`, when searching by one."},{"type":"null"}]},"organization":{"anyOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}}},{"type":"null"}]},"venue":{"anyOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"street":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"type":"string"},"state":{"type":"string"},"postalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"lat":{"anyOf":[{"type":"number"},{"type":"null"}]},"lng":{"anyOf":[{"type":"number"},{"type":"null"}]},"geoPrecision":{"type":"string","description":"`EXACT` for a street address; otherwise approximate.","enum":["EXACT","CITY","REGION","UNKNOWN"]}}},{"type":"null"}]},"locationLabel":{"anyOf":[{"type":"string","description":"A place named without a center (an area, or virtual)."},{"type":"null"}]},"divisions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"feeCents":{"anyOf":[{"type":"integer"},{"type":"null"}]}}}},"awards":{"type":"object","description":"As the organizer published them; empty or null when the flyer doesn't say.","properties":{"types":{"type":"array","items":{"type":"string","enum":["SCHOLARSHIP","CASH","TROPHIES","JUNIOR_GOLD_SPOTS"]}},"prizeFundCents":{"anyOf":[{"type":"integer"},{"type":"null"}]},"payoutOneIn":{"anyOf":[{"type":"integer","description":"Pays one entry in this many."},{"type":"null"}]},"juniorGoldSpotsOneIn":{"anyOf":[{"type":"integer"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}},"Build":{"type":"object","properties":{"commit":{"type":"string","description":"The full commit the build was made from."},"deploymentId":{"type":"string","description":"Its short form."},"builtAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}}}}}}