{
  "openapi": "3.1.0",
  "info": {
    "title": "Run Cebu Events API",
    "version": "1.0.0",
    "description": "Discover public running events and, with a scoped API key, manage calendar entries. Public reads require no credentials. Write credentials are issued by Run Cebu and carry the smallest applicable role.",
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    }
  },
  "externalDocs": {
    "description": "OAuth 2.0 Protected Resource Metadata with supported agent scopes.",
    "url": "https://runcebu.com/.well-known/oauth-protected-resource"
  },
  "servers": [
    {
      "url": "https://runcebu.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/events": {
      "get": {
        "operationId": "listEvents",
        "summary": "List running events",
        "description": "Returns public event records ordered by date and ID.",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" },
          { "$ref": "#/components/parameters/DateFrom" },
          { "$ref": "#/components/parameters/DateTo" },
          { "$ref": "#/components/parameters/Distance" },
          { "$ref": "#/components/parameters/Category" }
        ],
        "responses": {
          "200": {
            "description": "A page of events.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EventList" }
              }
            }
          },
          "502": { "$ref": "#/components/responses/UpstreamError" }
        }
      },
      "post": {
        "operationId": "createEvent",
        "summary": "Create an event",
        "security": [{ "AgentApiKey": [] }],
        "x-required-permission": "events:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/EventInput" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Event created.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Event" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/api/events/{eventId}": {
      "parameters": [{ "$ref": "#/components/parameters/EventId" }],
      "get": {
        "operationId": "getEvent",
        "summary": "Get one running event",
        "security": [],
        "responses": {
          "200": {
            "description": "Event found.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Event" } } }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "operationId": "updateEvent",
        "summary": "Update an event",
        "security": [{ "AgentApiKey": [] }],
        "x-required-permission": "events:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/EventPatch" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Event updated.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Event" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteEvent",
        "summary": "Delete an event",
        "security": [{ "AgentApiKey": [] }],
        "x-required-permission": "events:delete",
        "responses": {
          "200": {
            "description": "Deleted event.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Event" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "AgentApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "A Run Cebu agent API key. Keys are stored as SHA-256 digests and assigned one or more roles.",
        "x-scopes-supported": ["events:read", "events:write", "events:delete"],
        "x-roles": {
          "events.reader": ["events:read"],
          "events.editor": ["events:read", "events:write"],
          "events.admin": ["events:read", "events:write", "events:delete"]
        }
      }
    },
    "parameters": {
      "EventId": { "name": "eventId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
      "Limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } },
      "Offset": { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 } },
      "DateFrom": { "name": "date_from", "in": "query", "schema": { "type": "string", "format": "date" } },
      "DateTo": { "name": "date_to", "in": "query", "schema": { "type": "string", "format": "date" } },
      "Distance": { "name": "distance", "in": "query", "schema": { "type": "string" }, "example": "10K" },
      "Category": { "name": "category", "in": "query", "schema": { "type": "string" }, "example": "Trail" }
    },
    "schemas": {
      "Event": {
        "type": "object",
        "required": ["id", "name", "location", "date", "distances", "categories", "featured"],
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "link": { "type": ["string", "null"], "format": "uri" },
          "location": { "type": "string" },
          "distances": { "type": "array", "items": { "type": "string" } },
          "categories": { "type": "array", "items": { "type": "string" } },
          "date": { "type": "string", "format": "date" },
          "featured": { "type": "boolean" },
          "image_url": { "type": ["string", "null"], "format": "uri" },
          "facebook_url": { "type": ["string", "null"], "format": "uri" },
          "coming_soon": { "type": "boolean" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "EventInput": {
        "type": "object",
        "required": ["name", "location", "date", "distances"],
        "properties": {
          "name": { "type": "string", "minLength": 1 },
          "link": { "type": ["string", "null"], "format": "uri" },
          "location": { "type": "string", "minLength": 1 },
          "distances": { "type": "array", "items": { "type": "string" } },
          "categories": { "type": "array", "items": { "type": "string" }, "default": [] },
          "date": { "type": "string", "format": "date" },
          "featured": { "type": "boolean", "default": false },
          "image_url": { "type": ["string", "null"], "format": "uri" },
          "facebook_url": { "type": ["string", "null"], "format": "uri" },
          "coming_soon": { "type": "boolean", "default": false }
        },
        "additionalProperties": false
      },
      "EventPatch": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "name": { "type": "string", "minLength": 1 },
          "link": { "type": ["string", "null"], "format": "uri" },
          "location": { "type": "string", "minLength": 1 },
          "distances": { "type": "array", "items": { "type": "string" } },
          "categories": { "type": "array", "items": { "type": "string" } },
          "date": { "type": "string", "format": "date" },
          "featured": { "type": "boolean" },
          "image_url": { "type": ["string", "null"], "format": "uri" },
          "facebook_url": { "type": ["string", "null"], "format": "uri" },
          "coming_soon": { "type": "boolean" }
        },
        "additionalProperties": false
      },
      "EventList": {
        "type": "object",
        "required": ["data", "pagination"],
        "properties": {
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Event" } },
          "pagination": {
            "type": "object",
            "required": ["limit", "offset", "total"],
            "properties": {
              "limit": { "type": "integer" },
              "offset": { "type": "integer" },
              "total": { "type": ["integer", "null"] }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" }
            }
          }
        }
      }
    },
    "responses": {
      "Unauthorized": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Forbidden": { "description": "API key lacks the required role.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "NotFound": { "description": "Event not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "ValidationError": { "description": "Invalid event data.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "UpstreamError": { "description": "Events service unavailable.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    }
  }
}
