# zeng.city > Hong Kong event discovery: concerts, theatre, dance, film, exhibitions, talks, family and festival events, checked against official sources and linked straight to the official booking page. Read only, keyless, Hong Kong only, times in Asia/Hong_Kong. zeng.city never sells tickets and never ranks paid placements. Every event carries a source link and the time it was last checked. Follow the ticket or source link for full and current details. ## API - [Public API base](https://zeng.city/api/v1): REST, JSON, keyless, CORS open - [OpenAPI 3.1 spec](https://zeng.city/api/v1/openapi.json): full schema for every endpoint - [List events](https://zeng.city/api/v1/events?when=tonight): GET /api/v1/events Event URL pattern: /api/v1/events/{id} - [One event](https://zeng.city/api/v1/events/evt_lcsd_186890): GET /api/v1/events/{id}, plus /ics for a calendar file - [Metadata](https://zeng.city/api/v1/meta): category ids, district ids and per day event counts - [Venues](https://zeng.city/api/v1/venues): venues with upcoming events - [Weather warnings](https://zeng.city/api/v1/weather): current HKO rain and typhoon warnings ## Query parameters for /api/v1/events - when: tonight, weekend, free, all, or a Hong Kong calendar day as YYYY-MM-DD (example when=2026-10-24) - free=1: free events only; combines with a calendar day - area: district id such as hk:wan-chai (ids from /api/v1/meta) - category: category id such as concert or theatre (ids from /api/v1/meta) - venue: venue public id - q: search text in Traditional Chinese or English - max_price: maximum ticket price in HKD - limit (1 to 100, default 30) and offset for paging Curated Places: https://zeng.city/places. GET /api/v1/sights supports free=1, area, kind, limit and offset. GET /api/v1/sights/{id} gives visitor details and official links. ## MCP - [MCP server](https://zeng.city/mcp): Streamable HTTP, JSON responses, stateless, keyless - Tools: search_events, get_event, list_tonight, list_areas, list_categories ## Data rules - Each event includes its source link (source_url) and last checked time (last_checked_at, exposed as checked_at in the API) - Hong Kong events only - Keyless read access, rate limit 60 requests per minute per IP (best effort, HTTP 429 with Retry-After when exceeded) - Do not invent prices, times or availability; quote what the API returns and link to the source ## Docs - [Developers page](https://zeng.city/developers): API and MCP overview with curl examples - [Accessibility statement](https://zeng.city/accessibility): accessibility standard, known limitations and feedback - [About](https://zeng.city/about): how events are collected, verified and corrected - [Full text version](https://zeng.city/llms-full.txt): this file plus the OpenAPI spec inline ## OpenAPI spec (inline) ```json { "openapi": "3.1.0", "info": { "title": "zeng.city public API", "version": "1.0.0", "description": "Hong Kong event discovery is keyless. Submissions enter a pending human review queue. Admin and cron routes are private. Times are Asia/Hong_Kong. Rate limit: 60 requests per minute per IP (best effort). Facts only; follow ticket and source links for full details. Plain text guide for AI agents: https://zeng.city/llms.txt" }, "servers": [ { "url": "https://zeng.city/api/v1" } ], "paths": { "/log": { "post": { "summary": "First party anonymous usage and diagnostic events", "description": "Accepts ctx and up to 50 events as JSON, including beacon text bodies. Maximum body size is 64 KB.", "responses": { "202": { "description": "Logging temporarily unavailable" }, "204": { "description": "Accepted or ignored bot" }, "400": { "description": "Invalid payload" }, "413": { "description": "Payload too large" } } } }, "/community/boards": { "get": { "summary": "Community board previews", "responses": { "200": { "description": "Read only starter boards" } } } }, "/community/boards/{id}/threads": { "get": { "summary": "Community thread preview", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Preview with no stored threads" } } } }, "/auth/magic-link": { "post": { "summary": "Sign in preview gate", "responses": { "501": { "description": "Authentication is not enabled" } } } }, "/community/threads": { "post": { "summary": "Community posting preview gate", "responses": { "501": { "description": "Posting is not enabled" } } } }, "/sights": { "get": { "summary": "Curated Hong Kong places", "parameters": [ { "name": "free", "in": "query", "required": false, "description": "1 for free places", "schema": { "type": "string" } }, { "name": "area", "in": "query", "required": false, "description": "Hong Kong area id", "schema": { "type": "string" } }, { "name": "kind", "in": "query", "required": false, "description": "attraction, outdoor, neighbourhood, museum or transport", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "1 to 100, default 30", "schema": { "type": "string" } }, { "name": "offset", "in": "query", "required": false, "description": "Paging offset", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Published sights in data with total, count, offset, next_offset and free in meta", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Sight" } }, "meta": { "type": "object" } } } } } } } } }, "/sights/{id}": { "get": { "summary": "One published place with visitor tips and official links", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Sight in data", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Sight" } } } } } }, "404": { "description": "Not found" } } } }, "/events": { "get": { "summary": "List upcoming events", "parameters": [ { "name": "when", "in": "query", "required": false, "description": "tonight, weekend, free, all or a valid YYYY-MM-DD calendar day in Hong Kong", "schema": { "type": "string" } }, { "name": "free", "in": "query", "required": false, "description": "Use 1 to filter free events, including with a calendar day", "schema": { "type": "string" } }, { "name": "area", "in": "query", "required": false, "description": "District id, e.g. hk:wan-chai", "schema": { "type": "string" } }, { "name": "category", "in": "query", "required": false, "description": "Category id, e.g. concert", "schema": { "type": "string" } }, { "name": "venue", "in": "query", "required": false, "description": "Venue public id", "schema": { "type": "string" } }, { "name": "q", "in": "query", "required": false, "description": "Search text (TC or EN)", "schema": { "type": "string" } }, { "name": "max_price", "in": "query", "required": false, "description": "Max ticket price in HKD", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "1 to 100, default 30", "schema": { "type": "string" } }, { "name": "offset", "in": "query", "required": false, "description": "Paging offset", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Events", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Event" } }, "meta": { "type": "object", "properties": { "total": { "type": "integer" }, "count": { "type": "integer" }, "offset": { "type": "integer" }, "next_offset": { "type": "integer", "nullable": true } } } } } } } } } } }, "/events/{id}": { "get": { "summary": "One event with details", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Event" }, "404": { "description": "Not found" } } } }, "/events/{id}/ics": { "get": { "summary": "Calendar file (.ics)", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "text/calendar" } } } }, "/meta": { "get": { "summary": "Categories, districts and day counts", "parameters": [ { "name": "area", "in": "query", "required": false, "description": "Optional district or neighbourhood id for local day counts", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Existing city metadata plus day_counts, a YYYY-MM-DD to event count map for today through at least the following 61 days and the last known event day in Hong Kong" } } } }, "/venues": { "get": { "summary": "Venues with upcoming events (for maps)", "responses": { "200": { "description": "Venues" } } } }, "/venues/{id}": { "get": { "summary": "Venue and its upcoming events", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Venue" } } } }, "/organisers": { "get": { "summary": "Organiser directory stub", "responses": { "200": { "description": "Empty organiser list", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "maxItems": 0, "items": { "type": "object" } } } } } } } } } }, "/submit": { "post": { "summary": "Submit an event for human review", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Submission" } } } }, "responses": { "201": { "description": "Stored pending review with id, status and email delivery flags" }, "202": { "description": "Ignored" }, "400": { "description": "Invalid submission" }, "429": { "description": "Rate limited" }, "503": { "description": "Temporarily unavailable" } } } }, "/submit/draft": { "get": { "summary": "Resume an unfinished draft", "parameters": [ { "name": "token", "in": "query", "required": false, "description": "Random draft token", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Draft in data" }, "400": { "description": "Invalid token" }, "404": { "description": "Not found" } } } }, "/email/stop": { "post": { "summary": "Stop the draft reminder", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "token" ], "properties": { "token": { "type": "string", "format": "uuid" } } } } } }, "responses": { "200": { "description": "Preference accepted" }, "400": { "description": "Invalid token" }, "503": { "description": "Temporarily unavailable" } } } }, "/settings/public": { "get": { "summary": "Public privacy contact", "responses": { "200": { "description": "Privacy contact in data" } } } }, "/weather": { "get": { "summary": "Current HKO warnings (rain, typhoon)", "responses": { "200": { "description": "Warnings" } } } } }, "components": { "schemas": { "Event": { "type": "object", "properties": { "id": { "type": "string", "example": "evt_lcsd_188359" }, "title": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "summary": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "price": { "type": "object", "properties": { "min": { "type": "number", "nullable": true }, "max": { "type": "number", "nullable": true }, "free": { "type": "boolean" }, "text": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "currency": { "type": "string", "example": "HKD" } } }, "when": { "type": "object", "properties": { "text": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "starts_on": { "type": "string", "format": "date" }, "ends_on": { "type": "string", "format": "date" }, "next": { "type": "string", "format": "date-time", "nullable": true }, "run": { "type": "boolean" } } }, "area": { "type": "object", "nullable": true, "properties": { "id": { "type": "string", "example": "hk:wan-chai" }, "name": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } } } }, "venue": { "type": "object", "nullable": true, "properties": { "public_id": { "type": "string" }, "name": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "lat": { "type": "number" }, "lng": { "type": "number" } } }, "categories": { "type": "array", "items": { "type": "string" } }, "trust": { "type": "string", "enum": [ "authoritative", "corroborated", "held" ] }, "checked_at": { "type": "string", "format": "date-time" } } }, "Sight": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "summary": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "kind": { "type": "string" }, "free": { "type": "boolean" }, "photos": { "type": "array", "default": [], "items": { "type": "object", "properties": { "alt": { "type": "object", "additionalProperties": false, "properties": { "en": { "type": "string", "maxLength": 500 }, "zh-Hant-HK": { "type": "string", "maxLength": 500 } } }, "src": { "type": "string" }, "thumb": { "type": "string" }, "author": { "type": "string" }, "licence": { "type": "string" }, "licence_url": { "type": "string" }, "source": { "type": "string" }, "source_url": { "type": "string" }, "title": { "type": "string" }, "w": { "type": "number" }, "h": { "type": "number" } } } }, "highlights": { "type": "array", "items": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } } }, "best_time": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "duration": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "nearby": { "type": "array", "maxItems": 3, "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "kind": { "type": "string" }, "free": { "type": "boolean" }, "photo": { "type": "string", "nullable": true } } } }, "events": { "type": "object", "properties": { "area_slug": { "type": "string", "nullable": true }, "total": { "type": "integer" }, "items": { "type": "array", "maxItems": 3, "items": { "type": "object", "properties": { "id": { "type": "string" }, "title": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } }, "when": { "type": "object" }, "venue": { "type": "object", "nullable": true, "properties": { "name": { "type": "object", "description": "Localised text", "properties": { "zh-Hant-HK": { "type": "string" }, "en": { "type": "string" } } } } } } } } } } } }, "Photo": { "type": "object", "properties": { "alt": { "type": "object", "additionalProperties": false, "properties": { "en": { "type": "string", "maxLength": 500 }, "zh-Hant-HK": { "type": "string", "maxLength": 500 } } }, "src": { "type": "string" }, "thumb": { "type": "string" }, "author": { "type": "string" }, "licence": { "type": "string" }, "licence_url": { "type": "string" }, "source": { "type": "string" }, "source_url": { "type": "string" }, "title": { "type": "string" }, "w": { "type": "number" }, "h": { "type": "number" } } }, "Submission": { "type": "object", "required": [ "title_zh", "title_en", "venue", "starts_on", "ends_on", "time_text", "price", "is_free", "ticket_url", "summary", "contact_email" ], "properties": { "title_zh": { "type": "string", "minLength": 0, "maxLength": 300 }, "title_en": { "type": "string", "minLength": 0, "maxLength": 300 }, "venue": { "type": "string", "minLength": 1, "maxLength": 500, "description": "Hong Kong venue" }, "starts_on": { "type": "string", "format": "date" }, "ends_on": { "type": "string", "format": "date", "description": "On or after starts_on" }, "time_text": { "type": "string", "minLength": 1, "maxLength": 500, "description": "Hong Kong time" }, "price": { "type": "number", "minimum": 0, "description": "HKD, must be 0 when is_free is true" }, "is_free": { "type": "boolean" }, "ticket_url": { "type": "string", "format": "uri", "maxLength": 2048, "description": "HTTP or HTTPS official event or ticket URL without credentials" }, "summary": { "type": "string", "minLength": 1, "maxLength": 3000 }, "contact_email": { "type": "string", "format": "email", "maxLength": 254 } } } } } } ```