{
  "openapi": "3.1.0",
  "info": {
    "title": "C-US Cultural Events API",
    "version": "1.0.0",
    "summary": "Public cultural events and venue data for the Euregio Maas-Rijn.",
    "description": "This OpenAPI document describes the public data-discovery operations for the current curated C-US event and venue records in the Euregio Maas-Rijn. These read operations are public and require no API key. Event records with publish=false are excluded from all event lists, venue event lists, and event detail responses; records without a publish field remain visible. Mobile analytics, event-view tracking, and redirect operations are outside this discovery contract because they record usage and are not needed for read-only integrations. GET /events is the recommended event search endpoint. Event times are local to the venue; date filters use YYYY-MM-DD.",
    "externalDocs": {
      "description": "Human and LLM integration guide",
      "url": "https://c-us.eu/developers.html"
    }
  },
  "servers": [
    {
      "url": "https://c-us.eu/api",
      "description": "Production API"
    }
  ],
  "tags": [
    { "name": "Events", "description": "Read upcoming cultural events." },
    { "name": "Venues", "description": "Browse venues and their future events." }
  ],
  "paths": {
    "/events": {
      "get": {
        "operationId": "listEvents",
        "tags": ["Events"],
        "summary": "List upcoming events, optionally for one date",
        "description": "Read-only and does not record analytics. Events with publish=false are excluded; records without a publish field remain visible. Without date, returns events in the API's default upcoming window (currently 14 days). With date, returns events on that calendar date. Results are sorted by fullDate and paginated with from and limit.",
        "parameters": [
          { "$ref": "#/components/parameters/Date" },
          { "$ref": "#/components/parameters/From" },
          { "$ref": "#/components/parameters/Limit" }
        ],
        "responses": {
          "200": {
            "description": "A page of matching event records.",
            "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Event" } } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/events/{from}": {
      "get": {
        "operationId": "listEventsFromOffset",
        "tags": ["Events"],
        "summary": "List the default upcoming event window from an offset",
        "description": "Returns the configured default page size (currently 100) from the default upcoming window (currently 14 days). Use GET /events for an explicit date filter and page size.",
        "parameters": [
          { "$ref": "#/components/parameters/PathFrom" }
        ],
        "responses": {
          "200": { "description": "A page of events.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Event" } } } } },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/events/{from}/{number}": {
      "get": {
        "operationId": "listEventsPage",
        "tags": ["Events"],
        "summary": "List an event page from the default upcoming window",
        "parameters": [
          { "$ref": "#/components/parameters/PathFrom" },
          { "name": "number", "in": "path", "required": true, "description": "Number of records to return.", "schema": { "type": "integer", "minimum": 1 } }
        ],
        "responses": {
          "200": { "description": "A page of events.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Event" } } } } },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/event/{eventId}": {
      "get": {
        "operationId": "getEvent",
        "tags": ["Events"],
        "summary": "Get one event without recording a view",
        "parameters": [
          { "name": "eventId", "in": "path", "required": true, "schema": { "type": "string" }, "description": "The event _id, for example collector-96a7c756." }
        ],
        "responses": {
          "200": { "description": "The event record.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Event" } } } },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/venues": {
      "get": {
        "operationId": "listVenues",
        "tags": ["Venues"],
        "summary": "List C-US venues",
        "description": "Returns the current venue records. Each venue _id may be MongoDB Extended JSON ({\"$oid\": \"...\"}); use its hexadecimal value as venueId in venue detail paths.",
        "responses": {
          "200": { "description": "Venue records.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Venue" } } } } },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/venue/{venueId}": {
      "get": {
        "operationId": "getVenue",
        "tags": ["Venues"],
        "summary": "Get a venue and its upcoming events",
        "description": "Returns venue details and events for that organization from today onward, excluding events with publish=false. The default page size is configured by the API (currently 100).",
        "parameters": [ { "$ref": "#/components/parameters/VenueId" } ],
        "responses": {
          "200": { "description": "Venue with a page of future events.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VenueDetail" } } } },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/venue/{venueId}/{from}": {
      "get": {
        "operationId": "getVenueFromOffset",
        "tags": ["Venues"],
        "summary": "Get a venue and future events from an offset",
        "parameters": [ { "$ref": "#/components/parameters/VenueId" }, { "$ref": "#/components/parameters/PathFrom" } ],
        "responses": {
          "200": { "description": "Venue with a page of future events.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VenueDetail" } } } },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/venue/{venueId}/{from}/{number}": {
      "get": {
        "operationId": "getVenuePage",
        "tags": ["Venues"],
        "summary": "Get a venue and a page of future events",
        "parameters": [ { "$ref": "#/components/parameters/VenueId" }, { "$ref": "#/components/parameters/PathFrom" }, { "name": "number", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1 } } ],
        "responses": {
          "200": { "description": "Venue with a page of future events.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VenueDetail" } } } },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Date": { "name": "date", "in": "query", "required": false, "description": "Exact calendar date, YYYY-MM-DD. Invalid calendar dates return 400.", "schema": { "type": "string", "format": "date", "example": "2026-11-15" } },
      "From": { "name": "from", "in": "query", "required": false, "description": "Zero-based offset into the matching sorted results.", "schema": { "type": "integer", "minimum": 0, "default": 0 } },
      "Limit": { "name": "limit", "in": "query", "required": false, "description": "Page size; maximum 1000. Defaults to the server setting (currently 100).", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 100 } },
      "PathFrom": { "name": "from", "in": "path", "required": true, "description": "Zero-based result offset.", "schema": { "type": "integer", "minimum": 0 } },
      "VenueId": { "name": "venueId", "in": "path", "required": true, "description": "The 24-character hexadecimal venue ID from venue._id.$oid.", "schema": { "type": "string", "pattern": "^[0-9a-fA-F]{24}$", "example": "69ce5aff39c469ff3b3d88b3" } }
    },
    "responses": {
      "BadRequest": { "description": "Invalid date or page size.", "content": { "text/plain": { "schema": { "type": "string" }, "example": "date must be a valid calendar date formatted as YYYY-MM-DD" } } },
      "NotFound": { "description": "The requested event or venue was not found.", "content": { "text/plain": { "schema": { "type": "string" } } } },
      "ServerError": { "description": "Database query failed.", "content": { "text/plain": { "schema": { "type": "string" } } } }
    },
    "schemas": {
      "LocalizedText": {
        "type": "object",
        "description": "Text localized for Dutch, English, German, and French.",
        "properties": { "nl": { "type": "string" }, "en": { "type": "string" }, "de": { "type": "string" }, "fr": { "type": "string" } },
        "additionalProperties": { "type": "string" }
      },
      "EventDate": {
        "type": "object",
        "properties": { "day": { "type": ["string", "integer"] }, "month": { "type": ["string", "integer"] }, "year": { "type": ["string", "integer"] }, "startTime": { "type": ["string", "null"], "description": "Local start time, HH:mm, when supplied." }, "endTime": { "type": ["string", "null"], "description": "Local end time, HH:mm, when supplied." } },
        "required": ["day", "month", "year"]
      },
      "EventLocation": {
        "type": "object",
        "properties": { "name": { "type": ["string", "null"] }, "street": { "type": ["string", "null"] }, "housenumber": { "type": ["string", "null"] }, "postalCode": { "type": ["string", "null"] }, "city": { "type": ["string", "null"] }, "country": { "type": ["string", "null"] }, "latitude": { "type": ["number", "null"] }, "longitude": { "type": ["number", "null"] }, "phone": { "type": ["string", "null"] }, "email": { "type": ["string", "null"] }, "website": { "type": ["string", "null"], "format": "uri" } }
      },
      "Event": {
        "type": "object",
        "properties": { "_id": { "type": "string", "example": "collector-96a7c756" }, "organizationId": { "type": "string", "description": "Hexadecimal venue ID; use with GET /venue/{venueId}." }, "title": { "$ref": "#/components/schemas/LocalizedText" }, "description": { "$ref": "#/components/schemas/LocalizedText" }, "date": { "$ref": "#/components/schemas/EventDate" }, "fullDate": { "type": "integer", "description": "Calendar date as YYYYMMDD." }, "location": { "$ref": "#/components/schemas/EventLocation" }, "image": { "type": ["string", "null"], "format": "uri" }, "website": { "type": ["string", "null"], "format": "uri", "description": "Original event page, when available." }, "tags": { "type": "object", "properties": { "nl": { "type": "array", "items": { "type": "string" } }, "en": { "type": "array", "items": { "type": "string" } }, "de": { "type": "array", "items": { "type": "string" } }, "fr": { "type": "array", "items": { "type": "string" } } } }, "tickets": { "type": "object", "properties": { "price": { "type": ["string", "null"] }, "url": { "type": ["string", "null"], "format": "uri" } } }, "publish": { "type": "boolean" }, "tagsUpdatedFromOrganizationAt": { "type": ["string", "null"], "format": "date-time" } },
        "required": ["_id", "title", "description", "date", "fullDate", "location"]
      },
      "ObjectId": {
        "oneOf": [ { "type": "string", "pattern": "^[0-9a-fA-F]{24}$" }, { "type": "object", "properties": { "$oid": { "type": "string", "pattern": "^[0-9a-fA-F]{24}$" } }, "required": ["$oid"] } ]
      },
      "Venue": {
        "type": "object",
        "properties": { "_id": { "$ref": "#/components/schemas/ObjectId" }, "type": { "type": ["string", "null"] }, "name": { "type": "string" }, "street": { "type": ["string", "null"] }, "housenumber": { "type": ["string", "null"] }, "postalCode": { "type": ["string", "null"] }, "city": { "type": ["string", "null"] }, "countryCode": { "type": ["string", "null"] }, "country": { "type": ["string", "null"] }, "latitude": { "type": ["number", "null"] }, "longitude": { "type": ["number", "null"] }, "phone": { "type": ["string", "null"] }, "email": { "type": ["string", "null"] }, "website": { "type": ["string", "null"], "format": "uri" }, "logoUrl": { "type": ["string", "null"], "format": "uri" }, "defaultImageUrl": { "type": ["string", "null"], "format": "uri" }, "agendaUrl": { "type": ["string", "null"], "format": "uri" }, "tags": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } } }, "parentId": { "$ref": "#/components/schemas/ObjectId" } },
        "required": ["_id", "name"]
      },
      "VenueDetail": {
        "type": "object",
        "properties": { "venue": { "$ref": "#/components/schemas/Venue" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/Event" } } },
        "required": ["venue", "events"]
      }
    }
  }
}
