{
    "schemes": [],
    "swagger": "2.0",
    "info": {
        "description": "Read API for the curated Münsterland business and technology event catalogue. Public, anonymous and read-only: there is no key to obtain and no account to create. Every response carries a weak ETag over the catalogue's own version, so sending it back as If-None-Match answers 304 without a query and is the cheapest way to watch for changes; an ingestion pass moves the version and retires the tag. Attribution is expected — see docs/public-api.md for the licence, how fresh the data is, and what is and is not ours to license.",
        "title": "Münsterland Hub API",
        "contact": {},
        "license": {
            "name": "CC BY 4.0",
            "url": "https://creativecommons.org/licenses/by/4.0/"
        },
        "version": "1.0"
    },
    "host": "",
    "basePath": "/",
    "paths": {
        "/api/v1/events": {
            "get": {
                "description": "The one filtered read behind /events, the homepage and every region hub. Every filter is optional and every repeated one accepts either a repeated parameter or a comma-separated list. Facet values are the catalogue's own enum members, not the URL slugs the public site uses — the slug vocabulary is the site's contract, not the API's. With no time window given the listing is the upcoming one, measured from now.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "catalogue"
                ],
                "summary": "List published events",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Free-text search over title, summary, venue and city",
                        "name": "search",
                        "in": "query"
                    },
                    {
                        "type": "array",
                        "items": {
                            "enum": [
                                "WESTMUENSTERLAND",
                                "MUENSTERLAND",
                                "TWENTE_EUREGIO",
                                "OSNABRUECK",
                                "RUHR"
                            ],
                            "type": "string"
                        },
                        "collectionFormat": "csv",
                        "description": "Region clusters",
                        "name": "region",
                        "in": "query"
                    },
                    {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "collectionFormat": "csv",
                        "description": "Topics",
                        "name": "category",
                        "in": "query"
                    },
                    {
                        "type": "array",
                        "items": {
                            "enum": [
                                "IN_PERSON",
                                "ONLINE",
                                "HYBRID"
                            ],
                            "type": "string"
                        },
                        "collectionFormat": "csv",
                        "description": "Where the event happens",
                        "name": "attendance_mode",
                        "in": "query"
                    },
                    {
                        "enum": [
                            "FREE",
                            "PAID"
                        ],
                        "type": "string",
                        "description": "Price state",
                        "name": "price",
                        "in": "query"
                    },
                    {
                        "enum": [
                            "relevance"
                        ],
                        "type": "string",
                        "description": "Named ordering. Omitted, the listing reads soonest-first; `relevance` reads the catalogue's relevance score first, then soonest.",
                        "name": "order",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "description": "Only events starting at or after this RFC 3339 instant",
                        "name": "starts_from",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "description": "Only events starting strictly before this RFC 3339 instant",
                        "name": "starts_before",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "default": 1,
                        "description": "1-based page number",
                        "name": "page",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "default": 24,
                        "description": "Events per page",
                        "name": "page_size",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EventPage"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    }
                }
            }
        },
        "/api/v1/events/facets": {
            "get": {
                "description": "Which values the /events filter controls may offer: the region clusters, topics, attendance modes, price states and city spellings carried by published events still to come. Read over the unfiltered upcoming catalogue rather than over the reader's own query — a reader who filtered to Münster still has to be able to pick Twente — so the answer is the same for everyone and caches on its own terms. Values are the catalogue's own enum members, not the URL slugs the public site uses; the words for them, and the order they are offered in, belong to the site.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "catalogue"
                ],
                "summary": "List the facet values the catalogue holds",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EventFacets"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    }
                }
            }
        },
        "/api/v1/events/{slug}": {
            "get": {
                "description": "Everything the event's own page renders: the facts, the editorial body, who runs it, where to register, and when a source last confirmed the entry. A cancelled or postponed event still answers 200 and says so in `status` — whoever holds the link has to learn what happened to it — and a past event likewise keeps the URL it was shared under.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "catalogue"
                ],
                "summary": "Read one event",
                "parameters": [
                    {
                        "type": "string",
                        "example": "mittelstand-digital-forum-bocholt",
                        "description": "The event's catalogue slug",
                        "name": "slug",
                        "in": "path",
                        "required": true
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EventDetail"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    }
                }
            }
        },
        "/api/v1/events/{slug}/similar": {
            "get": {
                "description": "The \"Ähnliche Events\" row the detail page closes with. Similar means one of three things, not all of them: the same region cluster, the same organizing organization, or an overlapping topic. The event itself is never in the list, only published upcoming events are, and an event with no region, no organizer and no topic has no axis to be similar along and answers with an empty list. The order is soonest first and is stable across requests.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "catalogue"
                ],
                "summary": "List events similar to one event",
                "parameters": [
                    {
                        "type": "string",
                        "example": "mittelstand-digital-forum-bocholt",
                        "description": "The event's catalogue slug",
                        "name": "slug",
                        "in": "path",
                        "required": true
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EventList"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    }
                }
            }
        },
        "/api/v1/organizations": {
            "get": {
                "description": "The *Veranstalter* index. An organization is listed once at least one published event credits it — a row reconciliation created but that nothing points at is not a public entity. The catalogue's sources are a different table and never appear here: an aggregator that carried a listing is not its organizer. Each entry carries the topics its published events cover and how many of them are still to come.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "catalogue"
                ],
                "summary": "List organizations",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Free-text search over the organization's name",
                        "name": "search",
                        "in": "query"
                    },
                    {
                        "type": "array",
                        "items": {
                            "enum": [
                                "WESTMUENSTERLAND",
                                "MUENSTERLAND",
                                "TWENTE_EUREGIO",
                                "OSNABRUECK",
                                "RUHR"
                            ],
                            "type": "string"
                        },
                        "collectionFormat": "csv",
                        "description": "Region clusters",
                        "name": "region",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "default": 1,
                        "description": "1-based page number",
                        "name": "page",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "default": 24,
                        "description": "Organizations per page",
                        "name": "page_size",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.OrganizationPage"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    }
                }
            }
        },
        "/api/v1/organizations/{slug}": {
            "get": {
                "description": "The organization's profile and a page of its events that are still to come. What it has already run is a filtered listing (`/events?org=…\u0026when=past`) rather than a second list here. A body nothing published credits has no page, because it is a reconciliation artefact rather than a public entity.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "catalogue"
                ],
                "summary": "Read one organization",
                "parameters": [
                    {
                        "type": "string",
                        "example": "ihk-nord-westfalen",
                        "description": "The organization's catalogue slug",
                        "name": "slug",
                        "in": "path",
                        "required": true
                    },
                    {
                        "type": "integer",
                        "default": 1,
                        "description": "1-based page number of the upcoming events",
                        "name": "page",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "default": 24,
                        "description": "Upcoming events per page",
                        "name": "page_size",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.OrganizationDetail"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    }
                }
            }
        },
        "/api/v1/regions/{region}": {
            "get": {
                "description": "What a region hub renders beyond the filtered event list it can already ask for: how many published events are still to come there, the cities they are happening in, and the topics they are about. All three are derived from the catalogue rather than editorial — the region's name, colour and copy belong to the site. The path segment is the cluster the catalogue stores, not the slug the public site puts in its own URLs.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "catalogue"
                ],
                "summary": "Read one region's summary",
                "parameters": [
                    {
                        "enum": [
                            "WESTMUENSTERLAND",
                            "MUENSTERLAND",
                            "TWENTE_EUREGIO",
                            "OSNABRUECK",
                            "RUHR"
                        ],
                        "type": "string",
                        "description": "Region cluster",
                        "name": "region",
                        "in": "path",
                        "required": true
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.RegionSummary"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    }
                }
            }
        },
        "/api/v1/venues": {
            "get": {
                "description": "The venue index. Only published venues are readable — a draft venue is editorial work in progress, and no public read links to one. Each entry carries the address, the amenity row and how many events are still to come there.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "catalogue"
                ],
                "summary": "List venues",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Free-text search over the venue's name and city",
                        "name": "search",
                        "in": "query"
                    },
                    {
                        "type": "array",
                        "items": {
                            "enum": [
                                "WESTMUENSTERLAND",
                                "MUENSTERLAND",
                                "TWENTE_EUREGIO",
                                "OSNABRUECK",
                                "RUHR"
                            ],
                            "type": "string"
                        },
                        "collectionFormat": "csv",
                        "description": "Region clusters",
                        "name": "region",
                        "in": "query"
                    },
                    {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "collectionFormat": "csv",
                        "description": "Venue types",
                        "name": "type",
                        "in": "query"
                    },
                    {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "collectionFormat": "csv",
                        "description": "Amenities the venue must have all of",
                        "name": "amenity",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "description": "Only venues whose advertised capacity reaches this party size",
                        "name": "fits_at_least",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "default": 1,
                        "description": "1-based page number",
                        "name": "page",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "default": 24,
                        "description": "Venues per page",
                        "name": "page_size",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.VenuePage"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    }
                }
            }
        },
        "/api/v1/venues/{slug}": {
            "get": {
                "description": "The venue's own page: where it is, what it offers, who runs it, and a page of the events still to come there. Whoever runs it is an organization and is linked only when that body has a public page of its own.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "catalogue"
                ],
                "summary": "Read one venue",
                "parameters": [
                    {
                        "type": "string",
                        "example": "digital-hub-campus-muenster",
                        "description": "The venue's catalogue slug",
                        "name": "slug",
                        "in": "path",
                        "required": true
                    },
                    {
                        "type": "integer",
                        "default": 1,
                        "description": "1-based page number of the upcoming events",
                        "name": "page",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "default": 24,
                        "description": "Upcoming events per page",
                        "name": "page_size",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.VenueDetail"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/middleware.ErrorResponse"
                        }
                    }
                }
            }
        },
        "/healthz": {
            "get": {
                "description": "Reports that the process is up. It never inspects a dependency: a failing database must not make Kubernetes restart an otherwise healthy pod.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "health"
                ],
                "summary": "Liveness probe",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/server.HealthResponse"
                        }
                    }
                }
            }
        },
        "/readyz": {
            "get": {
                "description": "Reports whether the process should receive traffic. It answers 503 once a shutdown signal has arrived, so the load balancer stops sending requests before the listener closes.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "health"
                ],
                "summary": "Readiness probe",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/server.HealthResponse"
                        }
                    },
                    "503": {
                        "description": "Service Unavailable",
                        "schema": {
                            "$ref": "#/definitions/server.HealthResponse"
                        }
                    }
                }
            }
        }
    },
    "definitions": {
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.EntityRef": {
            "type": "object",
            "properties": {
                "name": {
                    "type": "string",
                    "example": "Stadthalle Bocholt"
                },
                "slug": {
                    "type": "string",
                    "example": "stadthalle-bocholt"
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.EventDetail": {
            "type": "object",
            "properties": {
                "all_day": {
                    "type": "boolean"
                },
                "attendance_mode": {
                    "type": "string",
                    "example": "IN_PERSON"
                },
                "audiences": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "categories": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "city": {
                    "type": "string"
                },
                "country": {
                    "type": "string",
                    "example": "DE"
                },
                "currency": {
                    "type": "string",
                    "example": "EUR"
                },
                "description": {
                    "type": "string"
                },
                "display_title": {
                    "description": "DisplayTitle is the editorial title. Absent means the original is what we\npublish (docs/ux-contract.md §4).",
                    "type": "string"
                },
                "editorial_language": {
                    "description": "EditorialLanguage is the language the summary and why_attend are written\nin, which is not always the source's.",
                    "type": "string",
                    "example": "DE"
                },
                "ends_at": {
                    "type": "string"
                },
                "format": {
                    "type": "string",
                    "example": "CONFERENCE"
                },
                "image_url": {
                    "type": "string"
                },
                "latitude": {
                    "type": "number"
                },
                "longitude": {
                    "type": "number"
                },
                "official_url": {
                    "type": "string"
                },
                "online_url": {
                    "type": "string"
                },
                "organizations": {
                    "description": "Organizations are who runs the event, never the source it was found in:\nan aggregator that carried a listing is not its organizer, and the two are\ndifferent tables that stay different on the wire (docs/ux-contract.md §3).",
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EventOrganization"
                    }
                },
                "original_title": {
                    "type": "string",
                    "example": "Mittelstand Digital Forum Bocholt"
                },
                "postal_code": {
                    "type": "string"
                },
                "price_max": {
                    "type": "number"
                },
                "price_min": {
                    "type": "number"
                },
                "price_state": {
                    "type": "string",
                    "example": "PAID"
                },
                "region": {
                    "type": "string"
                },
                "region_cluster": {
                    "type": "string",
                    "example": "WESTMUENSTERLAND"
                },
                "registration_url": {
                    "description": "RegistrationURL is where a reader signs up; OfficialURL is the event's own\npage. Either can be absent, and they are frequently the same link.",
                    "type": "string"
                },
                "series": {
                    "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EntityRef"
                },
                "slug": {
                    "type": "string",
                    "example": "mittelstand-digital-forum-bocholt"
                },
                "source_checked_at": {
                    "description": "SourceCheckedAt is the provenance footnote's one fact: when a source last\nconfirmed this entry still exists.",
                    "type": "string",
                    "example": "2026-08-18T03:12:00Z"
                },
                "source_language": {
                    "description": "SourceLanguage is the language the original title is written in, which the\npage puts on its `lang` attribute so it is pronounced correctly.",
                    "type": "string",
                    "example": "DE"
                },
                "starts_at": {
                    "type": "string",
                    "example": "2026-08-27T07:00:00Z"
                },
                "status": {
                    "description": "Status is SCHEDULED unless something happened to the event. A cancelled\nevent still resolves and still renders: whoever holds the link has to\nlearn it was cancelled (docs/ux-contract.md §5).",
                    "type": "string",
                    "example": "SCHEDULED"
                },
                "street_address": {
                    "type": "string"
                },
                "summary": {
                    "description": "The editorial body. All three are absent until enrichment has written\nthem; description is the source's own prose, the other two are ours.",
                    "type": "string"
                },
                "timezone": {
                    "description": "Timezone is the event's own zone, so a client renders local time rather\nthan the reader's (`Europe/Berlin`, `Europe/Amsterdam`).",
                    "type": "string",
                    "example": "Europe/Berlin"
                },
                "venue": {
                    "description": "Where it happens. Venue is the catalogue's own venue record when the event\nwas reconciled onto one; VenueName is the string the source carried and is\nwhat renders when it was not.",
                    "allOf": [
                        {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EntityRef"
                        }
                    ]
                },
                "venue_name": {
                    "type": "string"
                },
                "why_attend": {
                    "type": "string"
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.EventFacets": {
            "type": "object",
            "properties": {
                "attendance_modes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "ONLINE"
                    ]
                },
                "categories": {
                    "description": "Categories is flattened across events: a topic is offered when any one\nupcoming event carries it.",
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "AI_DATA"
                    ]
                },
                "cities": {
                    "description": "Cities are the catalogue's own spellings. There is no city dropdown by\ndecision (docs/ux-contract.md §6); an applied `?city=` still has to wear a\nchip reading `Münster` rather than the folded value the URL carries.",
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "Münster"
                    ]
                },
                "price_states": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "FREE"
                    ]
                },
                "regions": {
                    "description": "Regions omits OTHER by construction — no published event carries it as a\nplace a reader can pick.",
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "MUENSTERLAND"
                    ]
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.EventList": {
            "type": "object",
            "properties": {
                "items": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EventSummary"
                    }
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.EventOrganization": {
            "type": "object",
            "properties": {
                "kind": {
                    "type": "string",
                    "example": "PUBLIC_BODY"
                },
                "logo_url": {
                    "type": "string"
                },
                "name": {
                    "description": "Name is the display name when the catalogue has one, so the detail page\nand a card cannot name one body two things.",
                    "type": "string",
                    "example": "IHK Nord Westfalen"
                },
                "role": {
                    "type": "string",
                    "example": "ORGANIZER"
                },
                "slug": {
                    "type": "string",
                    "example": "ihk-nord-westfalen"
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.EventPage": {
            "type": "object",
            "properties": {
                "items": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EventSummary"
                    }
                },
                "page": {
                    "type": "integer",
                    "example": 1
                },
                "page_size": {
                    "type": "integer",
                    "example": 24
                },
                "total": {
                    "type": "integer",
                    "example": 42
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.EventSummary": {
            "type": "object",
            "properties": {
                "all_day": {
                    "type": "boolean"
                },
                "attendance_mode": {
                    "type": "string",
                    "example": "IN_PERSON"
                },
                "categories": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "city": {
                    "type": "string"
                },
                "country": {
                    "type": "string"
                },
                "display_title": {
                    "description": "DisplayTitle is the editorial title. Absent means the original is what we\npublish (docs/ux-contract.md §4).",
                    "type": "string"
                },
                "ends_at": {
                    "type": "string"
                },
                "image_url": {
                    "type": "string"
                },
                "organizer": {
                    "description": "Organizer is the organizing organization, never the source the event was\nfound in (docs/ux-contract.md §3).",
                    "type": "string"
                },
                "original_title": {
                    "type": "string",
                    "example": "Mittelstand Digital Forum Bocholt"
                },
                "price_state": {
                    "type": "string",
                    "example": "PAID"
                },
                "region_cluster": {
                    "type": "string",
                    "example": "WESTMUENSTERLAND"
                },
                "slug": {
                    "type": "string",
                    "example": "mittelstand-digital-forum-bocholt"
                },
                "source_language": {
                    "description": "SourceLanguage is the language the original title is written in, which the\npage puts on its `lang` attribute so it is pronounced correctly.",
                    "type": "string",
                    "example": "DE"
                },
                "starts_at": {
                    "type": "string",
                    "example": "2026-08-27T07:00:00Z"
                },
                "status": {
                    "type": "string",
                    "example": "SCHEDULED"
                },
                "summary": {
                    "description": "Summary is editorial prose, absent until it has been written.",
                    "type": "string"
                },
                "timezone": {
                    "description": "Timezone is the event's own zone, so a client renders local time rather\nthan the reader's (`Europe/Berlin`, `Europe/Amsterdam`).",
                    "type": "string",
                    "example": "Europe/Berlin"
                },
                "updated_at": {
                    "description": "UpdatedAt is when the catalogue last changed this record, maintained by a\ndatabase trigger rather than by a writer. It is what `sitemap.xml` states\nas `lastmod`, so a crawler can tell a changed entry from an unchanged one\ninstead of being told \"now\" on every URL (#207).",
                    "type": "string",
                    "example": "2026-08-18T09:12:00Z"
                },
                "venue_name": {
                    "type": "string"
                },
                "why_attend": {
                    "description": "WhyAttend is the one editorial sentence that says why this event is worth\nthe trip. The cross-border card draws it under its own accent rule, which\nis most of why that section is two cards abreast rather than three; every\nother variant is handed it and draws nothing. Absent as often as Summary,\nand for the same reason (#370).",
                    "type": "string"
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.OrganizationDetail": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string"
                },
                "country": {
                    "type": "string",
                    "example": "DE"
                },
                "description": {
                    "type": "string"
                },
                "kind": {
                    "type": "string",
                    "example": "PUBLIC_BODY"
                },
                "legal_name": {
                    "description": "LegalName is the name the source carries, and is present only when a\npinned display name is what Name holds — the profile prints the one under\nthe other, and a body whose two names are the same string would otherwise\nrender it twice. A card never carries it: a card names a body once.",
                    "type": "string",
                    "example": "Industrie- und Handelskammer Nord Westfalen"
                },
                "logo_url": {
                    "type": "string"
                },
                "name": {
                    "type": "string",
                    "example": "IHK Nord Westfalen"
                },
                "region": {
                    "description": "Region is the administrative area the body sits in; RegionCluster is the\ncatalogue's own grouping, and the two are not the same claim.",
                    "type": "string"
                },
                "region_cluster": {
                    "type": "string",
                    "example": "WESTMUENSTERLAND"
                },
                "slug": {
                    "type": "string",
                    "example": "ihk-nord-westfalen"
                },
                "upcoming_events": {
                    "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EventPage"
                },
                "website_url": {
                    "type": "string"
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.OrganizationPage": {
            "type": "object",
            "properties": {
                "items": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.OrganizationSummary"
                    }
                },
                "page": {
                    "type": "integer",
                    "example": 1
                },
                "page_size": {
                    "type": "integer",
                    "example": 24
                },
                "total": {
                    "type": "integer",
                    "example": 42
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.OrganizationSummary": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string"
                },
                "country": {
                    "type": "string",
                    "example": "DE"
                },
                "description": {
                    "type": "string"
                },
                "kind": {
                    "description": "Kind is the catalogue's own word (`PUBLIC_BODY`, `NETWORK`), never a\ntranslated label: the label belongs to a locale and this payload outlives\nevery one of them.",
                    "type": "string",
                    "example": "PUBLIC_BODY"
                },
                "logo_url": {
                    "type": "string"
                },
                "name": {
                    "description": "Name is the display name where the catalogue has one, decided here so a\ncard and a profile cannot name one body two things.",
                    "type": "string",
                    "example": "IHK Nord Westfalen"
                },
                "region_cluster": {
                    "type": "string",
                    "example": "WESTMUENSTERLAND"
                },
                "slug": {
                    "type": "string",
                    "example": "ihk-nord-westfalen"
                },
                "topics": {
                    "description": "Topics are the categories this organization's published events carry, so\na card can say what it is about without reading its events.",
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "upcoming_event_count": {
                    "description": "UpcomingEventCount is published events still to come. Zero is a number the\ncard states rather than a gap, so it is never omitted.",
                    "type": "integer",
                    "example": 3
                },
                "updated_at": {
                    "description": "UpdatedAt is when the catalogue last changed this record, maintained by a\ndatabase trigger rather than by a writer. It is what `sitemap.xml` states\nas `lastmod`, so a crawler can tell a changed entry from an unchanged one\ninstead of being told \"now\" on every URL (#207).",
                    "type": "string",
                    "example": "2026-08-18T09:12:00Z"
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.RegionCity": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "example": "Bocholt"
                },
                "upcoming_event_count": {
                    "type": "integer",
                    "example": 5
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.RegionSummary": {
            "type": "object",
            "properties": {
                "cities": {
                    "description": "Cities are the places events are actually happening in, busiest first.",
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.RegionCity"
                    }
                },
                "region_cluster": {
                    "type": "string",
                    "example": "WESTMUENSTERLAND"
                },
                "topics": {
                    "description": "Topics are what those events are about, busiest first. An event with three\ntopics counts once under each, which is the claim a badge row makes.",
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.RegionTopic"
                    }
                },
                "upcoming_event_count": {
                    "description": "UpcomingEventCount counts every published event still to come in the\nregion, including the online ones no city chip can carry.",
                    "type": "integer",
                    "example": 12
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.RegionTopic": {
            "type": "object",
            "properties": {
                "category": {
                    "type": "string",
                    "example": "STARTUP"
                },
                "upcoming_event_count": {
                    "type": "integer",
                    "example": 4
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.VenueDetail": {
            "type": "object",
            "properties": {
                "amenities": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "capacity_max": {
                    "type": "integer"
                },
                "capacity_min": {
                    "type": "integer"
                },
                "city": {
                    "type": "string",
                    "example": "Münster"
                },
                "country": {
                    "type": "string",
                    "example": "DE"
                },
                "description": {
                    "type": "string"
                },
                "image_url": {
                    "type": "string"
                },
                "latitude": {
                    "type": "number"
                },
                "longitude": {
                    "type": "number"
                },
                "name": {
                    "type": "string",
                    "example": "Digital Hub Campus Münster"
                },
                "organization": {
                    "description": "Organization is whoever runs the venue, and only when that body has a\npublic page of its own — a link to a profile the catalogue will not serve\nis worse than no link.",
                    "allOf": [
                        {
                            "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EntityRef"
                        }
                    ]
                },
                "other_amenities": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "postal_code": {
                    "type": "string"
                },
                "region": {
                    "type": "string"
                },
                "region_cluster": {
                    "type": "string",
                    "example": "MUENSTERLAND"
                },
                "slug": {
                    "type": "string",
                    "example": "digital-hub-campus-muenster"
                },
                "street_address": {
                    "type": "string"
                },
                "type": {
                    "type": "string",
                    "example": "CONGRESS_CENTRE"
                },
                "upcoming_events": {
                    "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.EventPage"
                },
                "website_url": {
                    "type": "string"
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.VenuePage": {
            "type": "object",
            "properties": {
                "items": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/github_com_appetizers-io_muensterland-hub_backend_server_dto.VenueSummary"
                    }
                },
                "page": {
                    "type": "integer",
                    "example": 1
                },
                "page_size": {
                    "type": "integer",
                    "example": 24
                },
                "total": {
                    "type": "integer",
                    "example": 42
                }
            }
        },
        "github_com_appetizers-io_muensterland-hub_backend_server_dto.VenueSummary": {
            "type": "object",
            "properties": {
                "amenities": {
                    "description": "Amenities is the controlled vocabulary; OtherAmenities is what the source\nnamed that the vocabulary does not cover, kept verbatim rather than guessed\ninto an enum.",
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "capacity_max": {
                    "type": "integer"
                },
                "capacity_min": {
                    "description": "The advertised capacity range, in persons. Either bound may be absent, and\nan unstated one is not a small one — a client must not read it as zero.",
                    "type": "integer"
                },
                "city": {
                    "type": "string",
                    "example": "Münster"
                },
                "country": {
                    "type": "string",
                    "example": "DE"
                },
                "description": {
                    "type": "string"
                },
                "image_url": {
                    "type": "string"
                },
                "name": {
                    "type": "string",
                    "example": "Digital Hub Campus Münster"
                },
                "other_amenities": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "postal_code": {
                    "type": "string"
                },
                "region_cluster": {
                    "type": "string",
                    "example": "MUENSTERLAND"
                },
                "slug": {
                    "type": "string",
                    "example": "digital-hub-campus-muenster"
                },
                "street_address": {
                    "type": "string"
                },
                "type": {
                    "description": "Type is the catalogue's own word (`CONGRESS_CENTRE`), never a translated\nlabel: the label belongs to a locale and this payload outlives every one.",
                    "type": "string",
                    "example": "CONGRESS_CENTRE"
                },
                "upcoming_event_count": {
                    "description": "UpcomingEventCount is published events still to come here. Zero is a\nnumber the card states rather than a gap.",
                    "type": "integer",
                    "example": 3
                },
                "updated_at": {
                    "description": "UpdatedAt is when the catalogue last changed this record, maintained by a\ndatabase trigger rather than by a writer. It is what `sitemap.xml` states\nas `lastmod`, so a crawler can tell a changed entry from an unchanged one\ninstead of being told \"now\" on every URL (#207).",
                    "type": "string",
                    "example": "2026-08-18T09:12:00Z"
                }
            }
        },
        "middleware.ErrorResponse": {
            "type": "object",
            "properties": {
                "error": {
                    "description": "Error is a human-readable description of what went wrong.",
                    "type": "string",
                    "example": "not found"
                },
                "request_id": {
                    "description": "RequestID correlates the response with the server's access log.",
                    "type": "string",
                    "example": "01J8Z4K4S7Q0R2V6X9YB3C5D7E"
                }
            }
        },
        "server.HealthResponse": {
            "type": "object",
            "properties": {
                "status": {
                    "description": "Status is \"ok\" while the process is healthy and \"draining\" once it has\nbeen asked to shut down.",
                    "type": "string",
                    "example": "ok"
                }
            }
        }
    }
}