Ultimate Fighting Calendar
UFCalendar Fight API

UFC Stats API: per-fight and round-by-round statistics as JSON

The UFCalendar UFC Stats API serves FightMetric-style statistics for 8,819 UFC fights and 41,526 rounds: significant strikes by target and position, total strikes, takedowns, control time, knockdowns and submission attempts — per fight and per round, for both corners, with fighter career rates on top.

Free 1-day trial · 100 requests · no credit card. Paid plans from $19/mo, cancel anytime.

8,819
UFC fights with per-fight stat lines
41,526
rounds with round-by-round statistics
98%
of UFC fights carry statistics

Round-by-round, both corners

GET /v1/fights/{id}/rounds returns one stat line per fighter per round: head/body/leg and distance/clinch/ground splits, plus seconds spent at distance, in the clinch and on the ground where the source publishes them. Per-fight totals live at /v1/fights/{id}/stats.

Career statistics per scope

GET /v1/fighters/{slug}/stats returns strikes landed per minute, striking accuracy and defense, takedown average, accuracy and defense, and submission average per career scope (pro MMA, UFC only), derived from the same fight rows — so a fighter page and a model see identical numbers.

Endpoints for this job

Method and path, linked to the reference. The same key covers every endpoint in the API.

Method & pathWhat it returns
GET /v1/fights/{id}/statsPer-fight totals for both corners: strikes by target and position, takedowns, control time.
GET /v1/fights/{id}/roundsOne bout with its result, per-fight totals for both corners, and round-by-round statistics.
GET /v1/fighters/{slug}/statsCareer statistics per scope: strike and takedown rates, accuracy, defense, submission average.
GET /v1/events/{slug}One event with its full fight card (both corners, results when completed), venue and event-level broadcasts.

Quickstart in curl, Python and JavaScript

Complete requests against the live API. Any HTTP client works, or `pip install ufcalendar` for a typed Python client (source on GitHub); every response is plain JSON in a {"data": ..., "meta": ...} envelope.

curl
$ curl "https://api.ufcalendar.com/v1/fights/61204/rounds" \
    -H "Authorization: Bearer $UFCAL_KEY"

{
  "data": [
    {
      "round_number": 1,
      "fighter_id": 1187, "fighter_position": "a",
      "knockdowns": 0,
      "sig_strikes_landed": 14, "sig_strikes_attempted": 27,
      "total_strikes_landed": 21, "total_strikes_attempted": 35,
      "head_landed": 6, "body_landed": 5, "leg_landed": 3,
      "distance_landed": 9, "clinch_landed": 2, "ground_landed": 3,
      "takedowns_landed": 1, "takedowns_attempted": 2,
      "submission_attempts": 0, "reversals": 0, "control_time_sec": 152,
      ...
Python
import requests, pandas as pd

API = "https://api.ufcalendar.com/v1"
H = {"Authorization": f"Bearer {UFCAL_KEY}"}

# Latest completed UFC card -> every fight's per-round lines -> one DataFrame
event = requests.get(f"{API}/events", params={"org": "ufc", "status": "completed", "limit": 1}, headers=H).json()["data"][0]
card = requests.get(f"{API}/events/{event['slug']}", headers=H).json()["data"]["fights"]

rows = []
for f in card:
    rows += requests.get(f"{API}/fights/{f['id']}/rounds", headers=H).json()["data"]

df = pd.DataFrame(rows)
print(df.groupby("fighter_id")[["sig_strikes_landed", "takedowns_landed", "control_time_sec"]].sum()
        .sort_values("sig_strikes_landed", ascending=False).head(10))
JavaScript
const API = "https://api.ufcalendar.com/v1";
const headers = { Authorization: `Bearer ${process.env.UFCAL_KEY}` };

// Per-fight totals for both corners, then a fighter's career rates
const totals = await fetch(`${API}/fights/61204/stats`, { headers }).then((r) => r.json());
for (const line of totals.data) {
  console.log(line.fighter_position, `${line.sig_strikes_landed}/${line.sig_strikes_attempted} sig. strikes`);
}
const career = await fetch(`${API}/fighters/islam-makhachev/stats`, { headers }).then((r) => r.json());
console.log(career.data.find((s) => s.scope === "pro-mma"));

Questions

How many UFC fights have full statistics?
8,819 of 9,016 UFC fights (98%) carry per-fight stat lines, and 41,526 rounds carry round-by-round lines. Coverage is complete from the FightMetric era onward; early-1990s cards have results but sparse statistics.
Which statistics are included?
Knockdowns, significant strikes landed and attempted by target (head, body, leg) and position (distance, clinch, ground), total strikes, takedowns landed and attempted, submission attempts, reversals and control time — for both corners, per fight and per round.
How fast do statistics land after a fight?
Per-round statistics are written within minutes of the official result during live UFC events; the results pipeline polls every 5 minutes. Pro plans can receive a fight.result webhook instead of polling.
Do PFL, OKTAGON and BKFC have statistics too?
Yes, with per-round lines where the promotion publishes them: 828 PFL and 1,017 OKTAGON fights carry stat lines, and BKFC carries per-round punch statistics. GET /v1/orgs lists each org's stats and rounds capability flags.

UFC API guides by use case

One page per job — schedules, results, per-round statistics and rankings history — each with its own endpoints, sample responses and code.

UFCalendar is an independent publication, not affiliated with UFC/Zuffa/TKO, PFL, OKTAGON MMA or any promotion. Organization names are used to describe the data. Terms of service · Refund Policy