---
title: "Card-change feed across events"
method: GET
path: "/v1/changes"
tags: ["Events"]
---

# Card-change feed across events

`GET /v1/changes`

## Request

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

Every card change across the launch promotions (or one of them), newest first — the same audit trail the `card.changed` webhook delivers, for callers that poll instead. Kinds: `fight-added`, `fight-cancelled`, `fight-reinstated`, `opponent-changed`, `time-changed`, `venue-changed`, `fighter-merged`. Each entry carries `id`, `kind`, `before`, `after`, `observed_at` and its `event` (`id`, `slug`, `title`, `org`, `starts_at`). No-op rows and flaps (a bout scratched and reinstated within 48 h, a start time moved and moved back within 72 h) are filtered out, exactly as on the per-event log and the webhook. `since` defaults to 90 days ago. Unknown `kind` 400s `invalid_kind`; a bad `since` 400s `invalid_date`.

## Query parameters

- `org` 'ufc' | 'pfl' | 'oktagon' | 'bkfc' | 'rizin'
- `since` string
- `kind` 'fight-added' | 'fight-cancelled' | 'fight-reinstated' | 'opponent-changed' | 'time-changed' | 'venue-changed' | 'fighter-merged'
- `cursor` string
- `limit` integer

## Response `200`

Change entries, newest first

- ChangesFeedResponse: Newest first across every launch promotion.
  - `data` ChangeFeedEntry[], required
    - `id` integer, required
    - `kind` 'fight-added' | 'fight-cancelled' | 'fight-reinstated' | 'opponent-changed' | 'time-changed' | 'venue-changed' | 'fighter-merged', required: What a card-change entry describes.
    - `before` object, nullable, required
    - `after` object, nullable, required
    - `observed_at` string, date-time, required
    - `event` object, required
      - `id` integer, required
      - `slug` string, required
      - `title` string, required
      - `org` string, required
      - `starts_at` string, date-time, required
  - `meta` object, required
    - `since` string, date-time, required: The window start applied (default: 90 days ago).
    - `kinds` ChangeKind[], required: The kinds included.
    - `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
    - `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 (`invalid_org`, `invalid_date`, `invalid_kind`).
- `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)
