---
title: "Career statistics"
method: GET
path: "/v1/fighters/{idOrSlug}/stats"
tags: ["Fighters"]
---

# Career statistics

`GET /v1/fighters/{idOrSlug}/stats`

## Request

- Base URL: `https://api.ufcalendar.com`
- URL: `https://api.ufcalendar.com/v1/fighters/{idOrSlug}/stats`
- Auth: HTTP bearer

Raw per-source career rows, plus the readable split in `meta.records` / `meta.stats` (the same objects the fighter profile carries — read those unless you need the per-source rows). `data`: per-scope career stats (`pro-mma`, `amateur-mma`, …): record, strikes landed/absorbed per minute, accuracy/defense, takedown and submission averages, and `updated_at` (this route only). Exactly ONE row per scope; `source` names the publisher it came from: `public-records` (the complete multi-promotion career record) is preferred, then the promotion's own site (`ufc-stats`, `bkfc-official`, `one-official`, …), then `ufcalendar`. A `public-records` record is a point-in-time snapshot advanced by every settled bout UFCalendar tracked after it, so it matches the record on ufcalendar.com. A row's record and its stats cover the same bouts. `pro-mma` = the career record plus striking/grappling averages UFCalendar computes over EVERY settled MMA bout it holds per-fight totals for, in any promotion (Contender Series included); its stats are null when no such bout exists. Bouts of another sport are averaged on that sport's row (`pro-knuckle` for bare-knuckle boxing, `pro-muay-thai`, `pro-kickboxing`, `pro-boxing`; a stats-only row with a null record when the fighter has no such record row) and never enter `pro-mma`. Org-scoped rows (`ufc-only`, `bkfc-only`, `one-only`) are the fighter's record INSIDE that promotion, not a career record: `ufc-only` carries a record AND averages UFCalendar derives from the fighter's tracked UFC bouts only (Contender Series excluded, `W-L-D` plus ` (n NC)`; both null until a UFC bout is settled — a Contender-Series-only fighter has no UFC stats), while `bkfc-only` / `one-only` carry the promotion's own published record. ufcstats', OKTAGON's and ACA's header records are CAREER records and ship under `pro-mma` (the `public-records` row wins the scope when present, unless ufcstats counts more bouts).

## Path parameters

- `idOrSlug` string, required

## Response `200`

Career stat rows

- FighterStatsResponse: Raw rows in `data`; the readable split rides in `meta`.
  - `data` CareerStatRow[], required
    - `scope` string, required: `pro-mma`, `amateur-mma`, `pro-kickboxing`, …, or `ufc-only` / `bkfc-only` / `one-only`.
    - `source` string, required: Who published the record: `ufc-stats` (ufcstats.com), a promotion's own site (`ufc-official`, `bkfc-official`, `one-official`, `oktagon-official`, …), `ufcalendar` (derived by UFCalendar), or `public-records` (the complete multi-promotion career record compiled from public records).
    - `record` string, nullable, required
    - `slpm` string, nullable, required: Significant strikes landed per minute. Display string (`"1.34"`, `"42%"`).
    - `str_acc` string, nullable, required: Significant-strike accuracy. Display string (`"1.34"`, `"42%"`).
    - `sapm` string, nullable, required: Significant strikes absorbed per minute. Display string (`"1.34"`, `"42%"`).
    - `str_def` string, nullable, required: Significant-strike defence. Display string (`"1.34"`, `"42%"`).
    - `td_avg` string, nullable, required: Takedowns landed per 15 minutes. Display string (`"1.34"`, `"42%"`).
    - `td_acc` string, nullable, required: Takedown accuracy. Display string (`"1.34"`, `"42%"`).
    - `td_def` string, nullable, required: Takedown defence. Display string (`"1.34"`, `"42%"`).
    - `sub_avg` string, nullable, required: Submission attempts per 15 minutes. Display string (`"1.34"`, `"42%"`).
    - `updated_at` string, date-time, nullable: Present on `GET /v1/fighters/{idOrSlug}/stats` rows and `/v1/compare` `career_stats` only.
  - `meta` object, required
    - `records` object, required
    - `stats` StatsPanel, required: ONE per-minute panel: the widest sample UFCalendar holds for the fighter.
      - `slpm` string, nullable, required: Significant strikes landed per minute. Display string (`"1.34"`, `"42%"`).
      - `str_acc` string, nullable, required: Significant-strike accuracy. Display string (`"1.34"`, `"42%"`).
      - `sapm` string, nullable, required: Significant strikes absorbed per minute. Display string (`"1.34"`, `"42%"`).
      - `str_def` string, nullable, required: Significant-strike defence. Display string (`"1.34"`, `"42%"`).
      - `td_avg` string, nullable, required: Takedowns landed per 15 minutes. Display string (`"1.34"`, `"42%"`).
      - `td_acc` string, nullable, required: Takedown accuracy. Display string (`"1.34"`, `"42%"`).
      - `td_def` string, nullable, required: Takedown defence. Display string (`"1.34"`, `"42%"`).
      - `sub_avg` string, nullable, required: Submission attempts per 15 minutes. Display string (`"1.34"`, `"42%"`).
      - `values` object, required: Numeric twins of the strings; percentages as 0–1.
        - `slpm` number, nullable, required: Significant strikes landed per minute. Percentages as a 0–1 fraction.
        - `str_acc` number, nullable, required: Significant-strike accuracy. Percentages as a 0–1 fraction.
        - `sapm` number, nullable, required: Significant strikes absorbed per minute. Percentages as a 0–1 fraction.
        - `str_def` number, nullable, required: Significant-strike defence. Percentages as a 0–1 fraction.
        - `td_avg` number, nullable, required: Takedowns landed per 15 minutes. Percentages as a 0–1 fraction.
        - `td_acc` number, nullable, required: Takedown accuracy. Percentages as a 0–1 fraction.
        - `td_def` number, nullable, required: Takedown defence. Percentages as a 0–1 fraction.
        - `sub_avg` number, nullable, required: Submission attempts per 15 minutes. Percentages as a 0–1 fraction.
      - `basis` StatsBasis, required
        - `bouts` integer, required: How many settled bouts the panel averages over.
        - `orgs` string[], required: Org slugs those bouts span.
        - `source` string, required: `ufcalendar` for the every-promotion panel, else the `ufc-only` row's source. Both are computed by UFCalendar from per-fight totals.
        - `scope` string, required: `pro-mma` (every settled bout with per-fight totals, any promotion) or `ufc-only` (UFC bouts only, Contender Series excluded).
    - `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.
- `308`: The slug is a retired alias (the event or fighter was renamed). Follow `Location` to the canonical URL; the numeric-id form never redirects.
- `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)
