{
  "openapi": "3.1.0",
  "info": {
    "title": "EmbedSE API",
    "version": "1.0.0",
    "description": "Read-only JSON API for live sports matches, embed servers and stream status. No key required. 60 requests per minute per IP."
  },
  "servers": [{ "url": "https://api.embedse.com" }],
  "paths": {
    "/v1/matches": {
      "get": {
        "summary": "List matches",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["live", "upcoming", "ended"] } },
          { "name": "sport", "in": "query", "schema": { "type": "string" } },
          { "name": "category", "in": "query", "schema": { "type": "string" } },
          { "name": "embeddable", "in": "query", "schema": { "type": "string", "enum": ["1"] } },
          { "$ref": "#/components/parameters/Source" }
        ],
        "responses": {
          "200": {
            "description": "Match list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["ok", "updated_at", "count", "matches"],
                  "properties": {
                    "ok": { "type": "boolean" },
                    "updated_at": { "type": "integer" },
                    "count": { "type": "integer" },
                    "matches": { "type": "array", "items": { "$ref": "#/components/schemas/Match" } }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "503": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/matches/{id}": {
      "get": {
        "summary": "Get a match with its streams",
        "parameters": [{ "$ref": "#/components/parameters/Id" }, { "$ref": "#/components/parameters/Source" }],
        "responses": {
          "200": {
            "description": "Match",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["ok", "updated_at", "match"],
                  "properties": {
                    "ok": { "type": "boolean" },
                    "updated_at": { "type": "integer" },
                    "match": {
                      "allOf": [
                        { "$ref": "#/components/schemas/Match" },
                        {
                          "type": "object",
                          "properties": { "streams": { "type": "array", "items": { "$ref": "#/components/schemas/Stream" } } }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/matches/{id}/streams": {
      "get": {
        "summary": "List streams for a match",
        "parameters": [{ "$ref": "#/components/parameters/Id" }, { "$ref": "#/components/parameters/Source" }],
        "responses": {
          "200": {
            "description": "Streams",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["ok", "updated_at", "match_id", "count", "streams"],
                  "properties": {
                    "ok": { "type": "boolean" },
                    "updated_at": { "type": "integer" },
                    "match_id": { "type": "string" },
                    "count": { "type": "integer" },
                    "streams": { "type": "array", "items": { "$ref": "#/components/schemas/Stream" } }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/sources": {
      "get": {
        "summary": "List sources",
        "responses": {
          "200": {
            "description": "Sources with current counts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["ok", "updated_at", "count", "sources"],
                  "properties": {
                    "ok": { "type": "boolean" },
                    "updated_at": { "type": "integer" },
                    "count": { "type": "integer" },
                    "sources": { "type": "array", "items": { "$ref": "#/components/schemas/Source" } }
                  }
                }
              }
            }
          },
          "429": { "$ref": "#/components/responses/Error" },
          "503": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/categories": {
      "get": {
        "summary": "List categories",
        "responses": {
          "200": {
            "description": "Categories that have matches, most live matches first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["ok", "updated_at", "count", "categories"],
                  "properties": {
                    "ok": { "type": "boolean" },
                    "updated_at": { "type": "integer" },
                    "count": { "type": "integer" },
                    "categories": { "type": "array", "items": { "$ref": "#/components/schemas/Category" } }
                  }
                }
              }
            }
          },
          "429": { "$ref": "#/components/responses/Error" },
          "503": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/streams/{id}/status": {
      "get": {
        "summary": "Get stream status",
        "parameters": [{ "$ref": "#/components/parameters/Id" }],
        "responses": {
          "200": {
            "description": "Stream status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["ok", "updated_at", "stream", "match_id", "match_status"],
                  "properties": {
                    "ok": { "type": "boolean" },
                    "updated_at": { "type": "integer" },
                    "stream": { "$ref": "#/components/schemas/Stream" },
                    "match_id": { "type": "string" },
                    "match_status": { "type": "string", "enum": ["live", "upcoming", "ended"] }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Id": { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^[2-9A-HJ-NP-Za-km-z]{8}$" } },
      "Source": { "name": "source", "in": "query", "description": "One source ID or a comma separated list, for example alpha,bravo", "schema": { "type": "string" } }
    },
    "responses": {
      "Error": {
        "description": "Error",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": ["ok", "error"],
              "properties": { "ok": { "type": "boolean", "const": false }, "error": { "type": "string" } }
            }
          }
        }
      }
    },
    "schemas": {
      "Match": {
        "type": "object",
        "required": ["id", "title", "category", "category_slug", "start", "end", "status", "streams_count", "online_streams"],
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "category": { "type": "string" },
          "category_slug": { "type": "string" },
          "sport": { "type": ["string", "null"], "examples": ["soccer", "basketball", "american-football", "hockey", "baseball", "combat", "racing", "tennis", "golf"] },
          "league": { "type": ["string", "null"] },
          "home": { "type": ["string", "null"] },
          "away": { "type": ["string", "null"] },
          "home_logo": { "type": ["string", "null"], "format": "uri" },
          "away_logo": { "type": ["string", "null"], "format": "uri" },
          "start": { "type": "integer" },
          "end": { "type": "integer" },
          "status": { "type": "string", "enum": ["live", "upcoming", "ended"] },
          "streams_count": { "type": "integer" },
          "online_streams": { "type": "integer" },
          "embed_url": { "type": ["string", "null"] }
        }
      },
      "Stream": {
        "type": "object",
        "required": ["id", "server", "name", "status", "embed_url"],
        "properties": {
          "id": { "type": "string" },
          "server": { "type": "integer" },
          "name": { "type": "string" },
          "source": { "type": ["string", "null"], "enum": ["alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", null] },
          "language": { "type": ["string", "null"] },
          "status": { "type": "string", "enum": ["online", "idle", "offline"] },
          "embed_url": { "type": "string" }
        }
      },
      "Source": {
        "type": "object",
        "required": ["id", "name", "matches", "live_matches", "streams", "online_streams"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "matches": { "type": "integer" },
          "live_matches": { "type": "integer" },
          "streams": { "type": "integer" },
          "online_streams": { "type": "integer" }
        }
      },
      "Category": {
        "type": "object",
        "required": ["slug", "name", "sport", "matches", "live_matches", "embeddable_matches"],
        "properties": {
          "slug": { "type": "string" },
          "name": { "type": "string" },
          "sport": { "type": ["string", "null"] },
          "matches": { "type": "integer" },
          "live_matches": { "type": "integer" },
          "embeddable_matches": { "type": "integer" }
        }
      }
    }
  }
}
