{
  "openapi": "3.0.1",
  "info": {
    "title": "UFC & MMA Stats Scraper for espn.com — $0.50/1k",
    "description": "Scrape espn.com for MMA fights, fighters, rankings and events at $0.50 per 1,000 rows — the lowest price of any comparable UFC scraper. 42 measured stats per fighter per bout · reach, stance, gym & referee · career defence & closing sportsbook odds.",
    "version": "0.3",
    "x-build-id": "hgFIgQyKZaHb7wrOb"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/blackfalcondata~espn-mma-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-blackfalcondata-espn-mma-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/blackfalcondata~espn-mma-scraper/runs": {
      "post": {
        "operationId": "runs-sync-blackfalcondata-espn-mma-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/blackfalcondata~espn-mma-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-blackfalcondata-espn-mma-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "title": "🥊 Promotion / Search Term(s)",
            "type": "string",
            "description": "Promotion slug to scrape: \"ufc\", \"pfl\", \"bellator\", and 45 more that ESPN carries. Use a JSON array for several, e.g. [\"ufc\",\"pfl\"]. This is NOT a free-text search — to find a fighter or an event by name, leave this as the promotion and use Name Search, or paste an ESPN URL into Start URLs."
          },
          "mode": {
            "title": "🎛️ What to scrape",
            "enum": [
              "fights",
              "fighters",
              "rankings",
              "events"
            ],
            "type": "string",
            "description": "fights = one row per fighter per bout with the full 42-stat line. fighters = roster profiles with career rates and a W-L-D breakdown. rankings = divisional + pound-for-pound boards. events = one row per card.",
            "default": "fights"
          },
          "season": {
            "title": "📅 Season / Year",
            "type": "string",
            "description": "Scope to one or more seasons, e.g. \"2024\". Accepts a JSON array like [\"2023\",\"2024\"]. Applies to fights and events only — a roster and a ranking board are current, not historical, so fighters and rankings mode ignore it and say so in the log. Leave empty for ESPN’s current season."
          },
          "startUrls": {
            "title": "🔗 Start URLs",
            "type": "array",
            "description": "Paste espn.com URLs. What each one returns depends on the Record type: in fights mode a fighter page gives that fighter’s whole bout log and a fightcenter page gives the card, while in fighters mode a fighter page gives that one profile and in events mode a fightcenter page gives that one event. A fightcenter link that names a bout (…/fightId/…) gives exactly that bout. Each URL becomes its own search and results are merged and deduplicated. A URL that does not match the selected mode is skipped with a message. Rankings are selected by promotion and cannot be addressed by URL.",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "maxResults": {
            "title": "💯 Max Results",
            "minimum": 0,
            "maximum": 10000,
            "type": "integer",
            "description": "Maximum rows to deliver (0 = unlimited). A row is whatever the selected mode produces: one fighter’s statline in a bout, a fighter, a ranking entry, or an event. In fights mode each bout yields two rows, one per corner.",
            "default": 50
          },
          "fromDate": {
            "title": "📆 From Date",
            "type": "string",
            "description": "Only events on or after this date (YYYY-MM-DD). Narrowing by date marks the run coverage incomplete, so incremental mode will not mark unseen records as expired."
          },
          "toDate": {
            "title": "📆 To Date",
            "type": "string",
            "description": "Only events on or before this date (YYYY-MM-DD)."
          },
          "weightClass": {
            "title": "⚖️ Weight Class",
            "type": "string",
            "description": "Substring match, e.g. \"Lightweight\", \"Women's Strawweight\". In rankings mode it matches the board name."
          },
          "gender": {
            "title": "🚻 Gender",
            "enum": [
              "",
              "MALE",
              "FEMALE"
            ],
            "type": "string",
            "description": "Restrict to one gender. Applies to fighters and rankings.",
            "default": ""
          },
          "fighterCountry": {
            "title": "🌍 Fighter Country",
            "type": "string",
            "description": "Substring match on the fighter's citizenship, e.g. \"Brazil\"."
          },
          "stance": {
            "title": "🦶 Stance",
            "type": "string",
            "description": "Orthodox, Southpaw or Switch."
          },
          "gym": {
            "title": "🏟️ Gym / Team",
            "type": "string",
            "description": "Substring match on the fighter’s gym, e.g. \"American Top Team\", \"Pitbull\"."
          },
          "minWins": {
            "title": "✅ Minimum Wins",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Drop fighters whose career record shows fewer wins than this. A fighter with no record on file is dropped, not kept."
          },
          "minLosses": {
            "title": "❌ Minimum Losses",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Drop fighters with fewer career losses than this."
          },
          "titleFightsOnly": {
            "title": "🏅 Title Fights Only",
            "type": "boolean",
            "description": "Keep only championship-length (five-round) bouts. ESPN ships no title flag, so a five-round main event without a belt is included too.",
            "default": false
          },
          "methodFilter": {
            "title": "🥋 Method",
            "enum": [
              "any",
              "ko-tko",
              "submission",
              "decision"
            ],
            "type": "string",
            "description": "Keep only bouts that ended this way.",
            "default": "any"
          },
          "resultFilter": {
            "title": "🏁 Result",
            "enum": [
              "any",
              "win",
              "loss",
              "draw"
            ],
            "type": "string",
            "description": "Keep only rows where this fighter won, lost, or drew.",
            "default": "any"
          },
          "searchQuery": {
            "title": "🔎 Name Search",
            "type": "string",
            "description": "Substring match on fighter name (or event name in events mode)."
          },
          "activeOnly": {
            "title": "🟢 Active Fighters Only",
            "type": "boolean",
            "description": "Fighters mode only: drop fighters ESPN marks inactive.",
            "default": false
          },
          "includeCareerDefense": {
            "title": "🛡️ Career Defence Stats",
            "type": "boolean",
            "description": "Fighters mode only. Adds strikes absorbed per minute, striking defence and takedown defence — computed from the opponent side of every bout in the fighter’s log, because the source publishes no defensive career stat. Several times slower per fighter, so it is off by default. Each row reports `measuredBouts` and `measuredMinutes`, the basis the figures rest on.",
            "default": false
          },
          "includeOdds": {
            "title": "💰 Sportsbook Odds",
            "type": "boolean",
            "description": "Adds the money line for each fighter (open, close and current), the implied win probability with and without the bookmaker margin, line movement, the best price across the books, and the scheduled-rounds over/under. This is a HISTORICAL archive, not a live feed, and it is not complete: sampled 2026-09-01, 2020-2025 priced 20-24 of every 21-24 bouts checked, 2019 about half, 2018 and 2026 none at all. Closing lines exist only for 2024-2025. Bouts the books did not price, or that fall outside that window, come back with the odds columns empty.",
            "default": false
          },
          "includeDetails": {
            "title": "📋 Include Career Rates",
            "type": "boolean",
            "description": "Adds each fighter’s career averages to their fight rows: strikes landed per minute, striking and takedown accuracy, KO/TKO and decision shares. Slower per row. The 42-stat line for the bout itself is always included and is not affected by this.",
            "default": true
          },
          "compact": {
            "title": "📦 Compact Output",
            "type": "boolean",
            "description": "Core fields only (for AI-agent/MCP workflows).",
            "default": false
          },
          "excludeEmptyFields": {
            "title": "🧹 Exclude empty fields from output",
            "type": "boolean",
            "description": "Drop null, empty-string, and empty-array fields from each record before push. Smaller payloads for AI agents and dashboards.",
            "default": false
          },
          "incrementalMode": {
            "title": "♻️ Incremental Mode",
            "type": "boolean",
            "description": "Compare against the previous run and label each row NEW, UPDATED, REAPPEARED, UNCHANGED or EXPIRED. By default you get NEW, UPDATED and REAPPEARED; the other two are opt-in below. stateKey is optional — leave it empty and the actor derives a stable key from the search inputs, so different filter sets never share state.",
            "default": false
          },
          "stateKey": {
            "title": "🔑 State Key",
            "type": "string",
            "description": "Optional. Stable identifier for the tracked universe. Leave empty to auto-generate from search inputs."
          },
          "emitUnchanged": {
            "title": "📤 Emit Unchanged Records",
            "type": "boolean",
            "description": "Incremental mode only. Off by default: rows that have not changed since the previous run are skipped, so you are not billed for them again. Turn on to receive the full universe every run.",
            "default": false
          },
          "emitExpired": {
            "title": "🪦 Emit Expired Records",
            "type": "boolean",
            "description": "Incremental mode only. When a record a previous run delivered is gone from the source, emit a row for it marked EXPIRED, carrying its listingId so you can reconcile. Knowing something is gone requires seeing the whole set, so turning this on makes the run read the full universe for your search even when Max Results is small — the extra reading is not charged, and expired rows still count against Max Results. Suppressed automatically when the run used a date window or when part of the source failed to respond, because neither run saw the whole universe.",
            "default": false
          },
          "skipReposts": {
            "title": "🚫 Skip Duplicates",
            "type": "boolean",
            "description": "When incremental, skip records whose content matches an expired record from a prior run (cross-run duplicate detection).",
            "default": false
          },
          "telegramToken": {
            "title": "🔑 Telegram Bot Token",
            "type": "string",
            "description": "Telegram bot token (from @BotFather). Required for Telegram notifications."
          },
          "telegramChatId": {
            "title": "💬 Telegram Chat ID",
            "type": "string",
            "description": "Telegram chat or channel ID (e.g. \"-100123456789\"). Required when telegramToken is set."
          },
          "discordWebhookUrl": {
            "title": "🎮 Discord Webhook URL",
            "type": "string",
            "description": "Discord incoming webhook URL. Server Settings → Integrations → Webhooks → New Webhook."
          },
          "slackWebhookUrl": {
            "title": "💼 Slack Webhook URL",
            "type": "string",
            "description": "Slack incoming webhook URL. api.slack.com/messaging/webhooks."
          },
          "notificationLimit": {
            "title": "📊 Max Records Per Notification",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Maximum number of records included in each notification message (1–20).",
            "default": 5
          },
          "notifyOnlyChanges": {
            "title": "🔔 Notify only on new, updated or returning records",
            "type": "boolean",
            "description": "When Incremental Mode is on, only send notifications for records marked NEW, UPDATED or REAPPEARED. Has no effect outside incremental mode.",
            "default": false
          },
          "whatsappAccessToken": {
            "title": "📱 WhatsApp Access Token",
            "type": "string",
            "description": "WhatsApp Cloud API permanent access token (System User token from Meta Business). Recipient must have messaged the business number within the last 24h (service-conversation window — free since Nov 2024)."
          },
          "whatsappPhoneNumberId": {
            "title": "📞 WhatsApp Phone Number ID",
            "type": "string",
            "description": "Your WhatsApp Business phone-number ID (numeric, from Meta dashboard). Required when whatsappAccessToken is set."
          },
          "whatsappTo": {
            "title": "📲 WhatsApp Recipient",
            "type": "string",
            "description": "Recipient phone in E.164 format without + (e.g. \"436641234567\"). Recipient must have messaged your business number within last 24h."
          },
          "webhookUrl": {
            "title": "🪝 Generic Webhook URL",
            "type": "string",
            "description": "Receives a JSON POST with {metadata, items} after each run. Universal escape hatch for n8n / Make / Zapier / custom backends."
          },
          "webhookHeaders": {
            "title": "📋 Webhook Headers",
            "type": "object",
            "description": "Optional JSON object of custom headers (e.g. {\"Authorization\":\"Bearer ...\"})."
          },
          "appConnector": {
            "title": "Send results to a connected app",
            "type": "string",
            "description": "Optional. Pick a connected app under Settings → API & Integrations to receive your results. The app receives up to the first 500 rows of the run and only rows that carry data — records marked EXPIRED are not sent, so an app-side copy will keep a record the source has dropped. The full run is always in the dataset. Best-effort across MCP connectors as Apify expands its catalog."
          },
          "mcpIssueTeam": {
            "title": "Issue tracker team",
            "type": "string",
            "description": "Only when the connected app is an issue tracker: the team (name or ID) the summary issue is created under, if that app requires one."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}