How do I get the upcoming UFC schedule in Python?
Call GET /v1/events?org=ufc on the MMA Fight Data API, or api.events("ufc") with the ufcalendar Python package. It returns every upcoming UFC card, soonest first, with the first-bell, main-card and prelims times in UTC, the venue's time zone and a PPV flag. Pass a card's slug to the event endpoint for the full fight card.
Free plan: 1,000 requests a month, no card. Paid plans from $19/mo.
Endpoints used
| Method & path | What it returns | Plan |
|---|---|---|
GET /v1/events?org=ufc | MMA schedule + results API: full fight cards, venues, broadcasts, and a card-change diff log for late reshuffles. | All plans |
GET /v1/events/{slug} | One event with its full fight card (both corners, results when completed), venue and event-level broadcasts. | All plans |
GET /v1/events/{slug}/changes | The card-change diff log: fight added or removed, opponent swapped, date or order moved. | All plans |
GET /v1/calendar/ufc.ics | ICS calendar feeds per organization · subscribe any calendar app to every event, auto-updating as cards change. | All plans |
The code
curl lists the next three cards. The Python block prints the next five in your own time zone, then the next card's bouts in running order; the JavaScript block adds each card's main event.
Every block runs as shown with your API key in the UFCAL_API_KEY environment variable. Python uses pip install ufcalendar and JavaScript or TypeScript uses npm install @ufcalendar/sdk; any HTTP client works too.
curl "https://api.ufcalendar.com/v1/events?org=ufc&limit=3" \
-H "Authorization: Bearer $UFCAL_API_KEY"# pip install ufcalendar
from datetime import datetime
from zoneinfo import ZoneInfo
from ufcalendar import FightAPI
api = FightAPI() # reads UFCAL_API_KEY from the environment
here = ZoneInfo("America/New_York") # the time zone you want to show
def parse(ts):
return datetime.fromisoformat(ts.replace("Z", "+00:00"))
# A bare listing is the upcoming calendar, soonest first
for ev in api.events("ufc", limit=5):
main = parse(ev["main_card_at"] or ev["starts_at"])
ppv = " (PPV)" if ev["is_ppv"] else ""
print(f"{main.astimezone(here):%a %d %b %H:%M} {ev['title']}{ppv}")
# The full card of the next event, in running order
nxt = next(api.events("ufc", limit=1))
for f in api.event(nxt["slug"])["card"]:
if f["status"] != "cancelled":
section = f["card_section"] or "-"
print(f"{section:<14}{f['fighter_a']['name']} vs {f['fighter_b']['name']} ({f['weight_class']})")// npm install @ufcalendar/sdk
import { FightAPI } from "@ufcalendar/sdk";
const api = new FightAPI(); // reads UFCAL_API_KEY from the environment
const when = new Intl.DateTimeFormat("en-GB", {
timeZone: "Europe/London",
weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit",
});
// Upcoming UFC cards, soonest first, with each card's main event
for await (const ev of api.events({ org: "ufc", limit: 5, include: ["headline"] })) {
const main = new Date(ev.main_card_at ?? ev.starts_at);
const bout = ev.headline ? `${ev.headline.fighter_a.name} vs ${ev.headline.fighter_b.name}` : "TBA";
console.log(when.format(main), "|", ev.title, "|", bout, ev.is_ppv ? "(PPV)" : "");
}Sample response
A real response from the live API, trimmed for length. … marks removed fields.
{
"data": [
{
"id": 2805,
"slug": "ufc-fight-night-2026-10-31",
"title": "UFC Fight Night: Moicano vs Nolan",
"short_title": "Fight Night",
"numbering": "Fight Night",
"org": "ufc",
"sport": "mma",
"starts_at": "2026-10-31T21:00:00.000Z",
"main_card_at": "2026-11-01T00:00:00.000Z",
"prelims_at": "2026-10-31T21:00:00.000Z",
"early_prelims_at": null,
"tz": "America/Los_Angeles",
"status": "announced",
"is_ppv": false,
"is_title_card": false
},
{
"id": 2549,
"slug": "ufc-fight-night-2026-11-07",
"title": "UFC Fight Night: Bonfim vs Brady",
"short_title": "Fight Night",
"numbering": "Fight Night",
"org": "ufc",
"sport": "mma",
"starts_at": "2026-11-07T22:00:00.000Z",
"main_card_at": "2026-11-08T01:00:00.000Z",
"prelims_at": "2026-11-07T22:00:00.000Z",
"early_prelims_at": null,
"tz": "America/Los_Angeles",
"status": "announced",
"is_ppv": false,
"is_title_card": false
},
…
],
"meta": {
"pagination": { "next_cursor": "eyJpZCI6MjU2M30", "has_more": true, "limit": 3 }
}
}Notes and pitfalls
- starts_at is the first bell of the night, usually the earliest prelims. main_card_at, prelims_at and early_prelims_at are the section times, and they are null when a promotion publishes no split. Every time is UTC; tz is the venue's IANA time zone.
- A bare listing is the calendar: cards not yet over, including one that started a few hours ago, soonest first. Pass status=completed for past cards, or from and to (YYYY-MM-DD) for a date range.
- Results come in pages. The Python and JavaScript clients follow meta.pagination.next_cursor for you; with plain HTTP, send it back as the cursor parameter.
- Cards change late. Poll the card-change feed at GET /v1/changes, subscribe to the card.changed webhook on Pro, or give a calendar app the ICS feed at /v1/calendar/ufc.ics.
Related pages
More code guides
UFCalendar is an independent publication, not affiliated with UFC/Zuffa/TKO, PFL, OKTAGON MMA, BKFC, RIZIN FF or any promotion. Organization names are used to describe the data. Terms of service · Refund Policy