{
  "openapi": "3.0.3",
  "info": {
    "title": "SportsEvents24 API",
    "version": "1.2.0-beta",
    "description": "Free open beta. No registration, email, approval or key needed. Each data request selects country + sport_id, or one tournament_id. Per observed IP: 100 data requests/UTC day, 10 requests/minute, 100 rows/page and 5,000 returned rows/UTC month. Filters share one allowance; repeated rows count. External source URLs are excluded. No automatic payments. Terms and usage logging: https://sportsevents24.com/api . Existing valid keys retain their approved scope and account quotas."
  },
  "servers": [
    {
      "url": "https://sportsevents24.com"
    }
  ],
  "security": [
    {},
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/api/v1/events": {
      "get": {
        "operationId": "listEvents",
        "summary": "Read published events without signup",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "description": "Two-letter country code. Required together with sport_id unless tournament_id is supplied.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{2}$"
            }
          },
          {
            "name": "sport_id",
            "in": "query",
            "description": "Public sport ID, e.g. 1 for football. Required together with country unless tournament_id is supplied. IDs are listed on the documentation page.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "tournament_id",
            "in": "query",
            "description": "One public tournament ID. Obtain IDs from /api/v1/tournaments?country=GB&sport_id=1. May replace country + sport_id.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum records; allowance may reduce the page size.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque nextCursor from the previous response. Keep all filters unchanged. Expires after 24 hours.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "UTC date, inclusive. At least today minus 7 days; defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "UTC date, exclusive. At most today plus 30 days; defaults to today plus 7 days.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "UTC timestamp within last 7 days. Narrows changed records inside the event-date window; not a deletion feed.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of data. Repeated rows count towards 5,000 monthly records.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    },
                    "usage": {
                      "$ref": "#/components/schemas/Usage"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid filters or date window",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "An explicitly supplied Authorization header is invalid or revoked. Omit it for the anonymous beta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A legacy key is awaiting approval or the filters exceed its approved scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API rate or quota limit reached. Respect Retry-After. The feedback object contains an optional survey URL to share with the project owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Temporary unavailability; retry later",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "description": "No Authorization header needed. Provide country AND sport_id, OR one tournament_id. Requests without either selection return 400 scope_required. Choose different selections within the same IP allowance. Existing keys restrict results to their approved scope."
      }
    },
    "/api/v1/tournaments": {
      "get": {
        "operationId": "listTournaments",
        "summary": "Read published tournaments without signup",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "description": "Two-letter country code. Required together with sport_id unless tournament_id is supplied.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{2}$"
            }
          },
          {
            "name": "sport_id",
            "in": "query",
            "description": "Public sport ID, e.g. 1 for football. Required together with country unless tournament_id is supplied. IDs are listed on the documentation page.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "tournament_id",
            "in": "query",
            "description": "One public tournament ID. Obtain IDs from /api/v1/tournaments?country=GB&sport_id=1. May replace country + sport_id.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum records; allowance may reduce the page size.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque nextCursor from the previous response. Keep all filters unchanged. Expires after 24 hours.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of data. Repeated rows count towards 5,000 monthly records.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Tournament"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    },
                    "usage": {
                      "$ref": "#/components/schemas/Usage"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid filters or date window",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "An explicitly supplied Authorization header is invalid or revoked. Omit it for the anonymous beta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A legacy key is awaiting approval or the filters exceed its approved scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API rate or quota limit reached. Respect Retry-After. The feedback object contains an optional survey URL to share with the project owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Temporary unavailability; retry later",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "description": "No Authorization header needed. Provide country AND sport_id, OR one tournament_id. Requests without either selection return 400 scope_required. Choose different selections within the same IP allowance. Existing keys restrict results to their approved scope."
      }
    },
    "/api/v1/account": {
      "get": {
        "operationId": "getAccount",
        "summary": "Read remaining IP allowance without an account or key",
        "responses": {
          "200": {
            "description": "Anonymous usage, limits and quotaBasis; legacy keys return their existing account details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "project": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "pending",
                        "active"
                      ]
                    },
                    "scope": {
                      "nullable": true,
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Scope"
                        }
                      ]
                    },
                    "usage": {
                      "$ref": "#/components/schemas/Usage"
                    },
                    "limits": {
                      "type": "object"
                    },
                    "billing": {
                      "type": "string"
                    },
                    "access": {
                      "type": "string",
                      "enum": [
                        "anonymous"
                      ]
                    },
                    "quotaBasis": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid filters or date window",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "An explicitly supplied Authorization header is invalid or revoked. Omit it for the anonymous beta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A legacy key is awaiting approval or the filters exceed its approved scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API rate or quota limit reached. Respect Retry-After. The feedback object contains an optional survey URL to share with the project owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until retry."
              }
            }
          },
          "503": {
            "description": "Temporary unavailability; retry later",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "description": "No query parameters. Does not consume the daily data-request or monthly row quota; shares the 10/minute rate limit. Explicit valid legacy keys return account details instead."
      }
    },
    "/api/v1/feedback": {
      "post": {
        "operationId": "submitApiFeedback",
        "summary": "Submit voluntary feedback from the person responsible for an integration",
        "description": "No key or contact details required. Submit only actual human answers, not inferred payment preferences. Available even when data quota is exhausted; does not change data allowance. At most five submissions per observed IP per UTC day. A willingness-to-pay answer is interest only. Responses are kept for seven days.",
        "security": [
          {}
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "submissionId",
                  "usefulness",
                  "paidInterest"
                ],
                "properties": {
                  "submissionId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "UUID v4. Reuse the same ID and body when retrying a submission."
                  },
                  "usefulness": {
                    "type": "string",
                    "enum": [
                      "yes",
                      "partly",
                      "no"
                    ]
                  },
                  "paidInterest": {
                    "type": "string",
                    "enum": [
                      "yes",
                      "maybe",
                      "no"
                    ]
                  },
                  "message": {
                    "type": "string",
                    "maxLength": 1000
                  },
                  "context": {
                    "type": "object",
                    "properties": {
                      "reason": {
                        "type": "string",
                        "enum": [
                          "rate_limit",
                          "daily_quota",
                          "monthly_quota"
                        ]
                      },
                      "endpoint": {
                        "type": "string",
                        "enum": [
                          "events",
                          "tournaments",
                          "account"
                        ]
                      },
                      "country": {
                        "type": "string",
                        "pattern": "^[A-Z]{2}$"
                      },
                      "sport_id": {
                        "type": "string"
                      },
                      "tournament_id": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Feedback saved"
          },
          "200": {
            "description": "Identical submission already saved"
          },
          "400": {
            "description": "Invalid feedback"
          },
          "403": {
            "description": "Invalid browser origin"
          },
          "409": {
            "description": "Submission ID was already used for different answers"
          },
          "413": {
            "description": "Body exceeds 8 KiB"
          },
          "415": {
            "description": "Use application/json"
          },
          "429": {
            "description": "Feedback submission limit; respect Retry-After"
          },
          "503": {
            "description": "Feedback could not be saved; retry later"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Optional existing beta key. Omit Authorization for the free anonymous trial. Never send keys in URLs."
      }
    },
    "schemas": {
      "Scope": {
        "oneOf": [
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "country",
              "sportId"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "country"
                ]
              },
              "country": {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              "sportId": {
                "type": "integer",
                "minimum": 1
              }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "tournamentIds"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "tournaments"
                ]
              },
              "tournamentIds": {
                "type": "array",
                "minItems": 1,
                "maxItems": 5,
                "uniqueItems": true,
                "items": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          }
        ]
      },
      "Usage": {
        "type": "object",
        "properties": {
          "requests": {
            "type": "integer",
            "minimum": 0
          },
          "rows": {
            "type": "integer",
            "minimum": 0
          },
          "requestsRemaining": {
            "type": "integer",
            "minimum": 0
          },
          "rowsRemaining": {
            "type": "integer",
            "minimum": 0
          },
          "day": {
            "type": "string"
          },
          "month": {
            "type": "string"
          }
        }
      },
      "Event": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "integer"
          },
          "tournamentId": {
            "type": "integer"
          },
          "sportId": {
            "type": "integer"
          },
          "tournament": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "teamHome": {
            "type": "string",
            "nullable": true
          },
          "teamAway": {
            "type": "string",
            "nullable": true
          },
          "startsAt": {
            "type": "string",
            "nullable": true,
            "description": "UTC scheduled time, using the website fallback Europe/Riga if source timezone and UTC are unavailable; inspect timeZoneConfidence. Not proof of exact source time."
          },
          "localStartsAt": {
            "type": "string",
            "nullable": true
          },
          "timeZone": {
            "type": "string",
            "nullable": true
          },
          "timeZoneConfidence": {
            "type": "string",
            "nullable": true
          },
          "location": {
            "type": "string",
            "nullable": true
          },
          "result": {
            "type": "string",
            "nullable": true
          },
          "updatedAt": {
            "type": "string",
            "nullable": true,
            "description": "Record update time in UTC. Sync delay may apply."
          },
          "category": {
            "type": "string",
            "enum": [
              "upcoming",
              "result"
            ],
            "description": "Website grouping based on elapsed time, not confirmation of completion."
          }
        }
      },
      "Tournament": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "sportId": {
            "type": "integer"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "documentation": {
            "type": "string"
          },
          "retryAfterSeconds": {
            "type": "integer",
            "minimum": 1,
            "description": "Present on API rate/quota limits. Honor the Retry-After header."
          },
          "retryAt": {
            "type": "string",
            "format": "date-time"
          },
          "feedback": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri"
              },
              "message": {
                "type": "string"
              },
              "forAutomatedClients": {
                "type": "string"
              },
              "questions": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  }
}
