---
title: "Search completed bouts (filtered)"
method: GET
path: "/v1/fights/search"
tags: ["Fights"]
---

# Search completed bouts (filtered)

`GET /v1/fights/search`

## Request

- Base URL: `https://api.ufcalendar.com`
- URL: `https://api.ufcalendar.com/v1/fights/search`
- Auth: HTTP bearer

Completed bouts with a winner across the launch promotions, filtered — the one-call answer to "the last title fight to end by knockout" or "every submission win for this fighter". **At least one narrowing filter is required** (`title_only`, `method`, `division`, `fighter`, `winner`, `from`, `to`, `main_events_only`; `org`, `order`, `limit` and `cursor` do not count) — a bare call 400s `filter_required`, because the whole table is not sold as a list or a bulk export on any plan. Newest first by default (`order=oldest` reverses it); inside one card the main event comes first, then card order. Up to 25 rows per page and at most 10 pages deep (`page_depth_exceeded` past that — narrow the filters). Each row is the bout (same shape as `/v1/fights/{id}`) plus its `event` (`id`, `slug`, `title`, `org`, `starts_at`); `meta.filters` echoes the filters applied. `fighter`/`winner` take a slug or id (404 when not on the roster).

## Query parameters

- `org` 'ufc' | 'pfl' | 'oktagon' | 'bkfc' | 'rizin'
- `title_only` boolean
- `method` 'ko' | 'sub' | 'dec' | 'finish' | 'any'
- `division` string
- `fighter` string
- `winner` string
- `from` string, date
- `to` string, date
- `main_events_only` boolean
- `order` 'newest' | 'oldest'
- `cursor` string
- `limit` integer

## Response `200`

Matching bouts

- FightSearchResponse: `meta.note` explains an empty page or the 10-page depth cap.
  - `data` FightDetail[], required
    - `id` integer, required
    - `ordering` integer, nullable, required: 1 = the headliner; ascends down the card.
    - `card_section` 'main' | 'prelims' | 'early_prelims', required: Which part of the card the bout sits on.
    - `sport` string, required: Sport slug — `mma`, `bare-knuckle-boxing`. Open: a new sport lands as a new value.
    - `weight_class` string, nullable, required: Source spelling (`Featherweight`, `Catchweight 150 lbs`).
    - `division_slug` string, nullable, required: Slug twin in the rankings vocabulary (`womens-strawweight`, `catchweight`); null when the text matches no division.
    - `is_title` boolean, required
    - `is_main` boolean, required
    - `scheduled_rounds` integer, nullable, required
    - `status` 'announced' | 'confirmed' | 'cancelled' | 'completed' | 'no_contest', required: Bout lifecycle. `no_contest` is a settled bout with no winner.
    - `fighter_a` FighterRef, required: The one fighter-reference shape every card, fight and search row carries.
      - `id` integer, required
      - `slug` string, required
      - `name` string, required
      - `nickname` string, nullable, required
      - `nationality` string, nullable, required: Country NAME as the source spells it (e.g. `United States`).
      - `country_code` string, nullable, required: ISO 3166-1 alpha-2 derived from `nationality`; null when the name is unknown to our table.
    - `fighter_b` FighterRef, required: The one fighter-reference shape every card, fight and search row carries.
      - `id` integer, required
      - `slug` string, required
      - `name` string, required
      - `nickname` string, nullable, required
      - `nationality` string, nullable, required: Country NAME as the source spells it (e.g. `United States`).
      - `country_code` string, nullable, required: ISO 3166-1 alpha-2 derived from `nationality`; null when the name is unknown to our table.
    - `result` FightResult, required
      - `winner_fighter_id` integer, nullable, required: Null on a draw or no-contest.
      - `method` string, nullable, required: Source spelling (`Decision - Split`, `KO/TKO`, `Submission (Rear-Naked Choke)`).
      - `method_normalized` 'ko_tko' | 'submission' | 'technical_submission' | 'decision_unanimous' | 'decision_split' | 'decision_majority' | 'decision' | 'draw' | 'no_contest' | 'dq' | 'other', required: Closed vocabulary over every source spelling of a result method (`normalize.ts`). `other` = a non-empty method nothing matched.
      - `finish_detail` string, nullable, required: The parenthesised / trailing detail of `method`, cleaned (`Rear-Naked Choke`, `Doctor's Stoppage`).
      - `round` integer, nullable, required
      - `time` string, nullable, required: `m:ss` into the round.
      - `time_seconds` integer, nullable, required: `time` in seconds.
      - `details` string, nullable, required: Free text from the source — judges' totals on a decision, the strike on a KO.
    - `referee` string, nullable, required
    - `bonus` string, nullable, required: Post-fight bonus label when awarded (`Performance of the Night`, `Fight of the Night`).
    - `event` object, required
      - `id` integer, required
      - `slug` string, required
      - `title` string, required
      - `org` string, required
      - `starts_at` string, date-time, nullable, required
    - `odds` OddsPair: One UFCalendar consensus point: the mean, in decimal space, across the sportsbooks we track, converted back to American. Information only, not betting advice.
      - `a` OddsLine, required: One corner's side of a consensus point.
        - `american` integer, required: American moneyline (`-152`, `+131`).
        - `decimal` number, required: Decimal odds, 3 places.
        - `implied_probability` number, required: Raw implied probability (market margin included), 4 places.
      - `b` OddsLine, required: One corner's side of a consensus point.
        - `american` integer, required: American moneyline (`-152`, `+131`).
        - `decimal` number, required: Decimal odds, 3 places.
        - `implied_probability` number, required: Raw implied probability (market margin included), 4 places.
      - `favourite` 'a' | 'b' | 'null', nullable, required: The corner the market prices as more likely; null on an even pair.
      - `fair_probability_a` number, required: Probability of corner a with the market margin removed (pA / (pA + pB)), 4 places.
      - `sources` integer, required: How many sportsbooks backed this consensus point. Book identities are never exposed.
      - `recorded_at` string, date-time, required: When this consensus point was recorded.
  - `meta` object, required
    - `order` 'newest' | 'oldest', required
    - `filters` FightSearchFilters, required: Echo of the filters applied.
      - `org` string, nullable, required
      - `title_only` boolean, required
      - `method` 'ko' | 'sub' | 'dec' | 'finish' | 'any', required: `ko` = KO/TKO, `sub` = submission, `dec` = any decision, `finish` = KO/TKO or submission, `any` = no filter.
      - `division` string, nullable, required: The canonical name (slug input) or the fragment, as applied.
      - `fighter` string, nullable, required: As passed.
      - `winner` string, nullable, required: As passed.
      - `from` string, date, nullable, required
      - `to` string, date, nullable, required
      - `main_events_only` boolean, required
    - `pagination` CursorPagination, required: Cursor pagination WITHOUT the applied `limit` (the newer list routes — changes, fight search, splits, venues, articles — do not echo it).
      - `next_cursor` string, nullable, required: Opaque; pass as `?cursor=`. Null on the last page.
      - `has_more` boolean, required
    - `note` string
    - `ignored_params` string[]: Present only when the request carried query parameters this endpoint does not take — they were ignored. Same list as the `X-UFCalendar-Ignored-Params` header. Sorted, unique.

## Other responses

- `304`: Not Modified — `If-None-Match` matched the current weak `ETag`. Empty body.
- `400`: Invalid input (`filter_required`, `invalid_org`, `invalid_boolean`, `invalid_method`, `invalid_division`, `invalid_date`, `invalid_order`, `page_depth_exceeded`). Dates must be real calendar days (`2026-02-30` is `invalid_date`).
- `401`: Missing/invalid API key (`unauthorized`).
- `403`: No active plan on the key's account (`subscription_required`) — choose a plan or start the free 1-day trial at https://www.ufcalendar.com/account/api.
- `404`: Not found (`not_found`; staged-org data 404s until the org is promoted).
- `429`: Rate limited (`rate_limited`) or monthly quota reached (`quota_exceeded`). Honor `Retry-After`.
- `500`: Something broke on our side (`internal_error`). It has been logged under the `request_id`.

---

[API](https://skmtc.dev/ufcalendar/apis/ufcalendar-fight-api.md) · [All operations](https://skmtc.dev/ufcalendar/apis/ufcalendar-fight-api/llms.txt) · [OpenAPI document](https://skmtc.dev/ufcalendar/apis/ufcalendar-fight-api/revisions/9623cc8fb70b?raw)
