{"openapi":"3.1.0","info":{"title":"meetagain public API","version":"1.0.0","description":"Public REST API. The same spec applies to every host; hostnames are relative."},"servers":[{"url":"\/"}],"tags":[{"name":"public","description":"Public Endpoints"},{"name":"data","description":"Public Data"},{"name":"auth","description":"Authentication"},{"name":"cms","description":"CMS Pages","x-badge":"Token required"},{"name":"cms-blocks","description":"CMS Blocks","x-badge":"Token required"},{"name":"logs","description":"System Logs","x-badge":"Token required"}],"paths":{"\/api\/status":{"get":{"tags":["public"],"summary":"Service health check","x-example":"curl HOST\/api\/status","responses":{"200":{"description":"OK","content":{"application\/json":{"schema":{"type":"string"}}}}}}},"\/api\/translations":{"get":{"tags":["public"],"summary":"Translation strings","x-example":"curl HOST\/api\/translations","responses":{"200":{"description":"OK"}}}},"\/api\/glossary":{"get":{"tags":["public"],"summary":"Glossary data","x-example":"curl HOST\/api\/glossary","responses":{"200":{"description":"OK"}}}},"\/api\/auth\/token":{"post":{"tags":["auth"],"summary":"Generate Bearer token (email + password)","x-example":"TOKEN=$(curl -s -X POST HOST\/api\/auth\/token \\\n  -H \u0027Content-Type: application\/json\u0027 \\\n  -d \u0027{\u0022email\u0022:\u0022admin@example.com\u0022,\u0022password\u0022:\u0022...\u0022}\u0027 | jq -r .token)","requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string"}}}}}},"responses":{"200":{"description":"Token issued","content":{"application\/json":{"schema":{"type":"object","properties":{"token":{"type":"string"}}}}}},"401":{"description":"Invalid credentials"},"429":{"description":"Too many attempts"}}},"delete":{"tags":["auth"],"summary":"Revoke current token (requires Bearer)","x-example":"curl -s -X DELETE HOST\/api\/auth\/token \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Revoked"}}}},"\/api\/events":{"get":{"tags":["data"],"summary":"List upcoming public events (paginated)","x-example":"curl \u0027HOST\/api\/events?limit=10\u0026from=2026-05-01\u0027","parameters":[{"name":"locale","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK","content":{"application\/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#\/components\/schemas\/EventSummary"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}}},"\/api\/events\/{id}":{"get":{"tags":["data"],"summary":"Single event detail","x-example":"curl HOST\/api\/events\/42","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}},{"name":"locale","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/EventDetail"}}}},"404":{"description":"Not found"}}}},"\/api\/cms\/":{"get":{"tags":["cms"],"summary":"List all CMS pages","x-example":"curl HOST\/api\/cms\/ \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["cms"],"summary":"Create page","x-example":"curl -X POST HOST\/api\/cms\/ \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022 \\\n  -H \u0027Content-Type: application\/json\u0027 \\\n  -d \u0027{\u0022slug\u0022:\u0022my-page\u0022,\u0022titles\u0022:{\u0022en\u0022:\u0022My Page\u0022},\u0022linkNames\u0022:{\u0022en\u0022:\u0022My Page\u0022}}\u0027","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created"}}}},"\/api\/cms\/{id}":{"get":{"tags":["cms"],"summary":"Get full page with blocks","x-example":"curl HOST\/api\/cms\/1 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK"}}},"put":{"tags":["cms"],"summary":"Update metadata (slug, published, titles, linkNames)","x-example":"curl -X PUT HOST\/api\/cms\/1 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022 \\\n  -H \u0027Content-Type: application\/json\u0027 \\\n  -d \u0027{\u0022published\u0022:true,\u0022titles\u0022:{\u0022en\u0022:\u0022Updated\u0022}}\u0027","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK"}}},"delete":{"tags":["cms"],"summary":"Delete page (not allowed if locked)","x-example":"curl -X DELETE HOST\/api\/cms\/1 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"204":{"description":"Deleted"}}}},"\/api\/cms\/{id}\/blocks":{"post":{"tags":["cms-blocks"],"summary":"Add block","x-example":"curl -X POST HOST\/api\/cms\/1\/blocks \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022 \\\n  -H \u0027Content-Type: application\/json\u0027 \\\n  -d \u0027{\u0022language\u0022:\u0022en\u0022,\u0022type\u0022:1,\u0022priority\u0022:1,\u0022json\u0022:{\u0022text\u0022:\u0022Hello\u0022}}\u0027","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"201":{"description":"Created"}}}},"\/api\/cms\/{id}\/blocks\/{blockId}":{"put":{"tags":["cms-blocks"],"summary":"Update block json and\/or priority","x-example":"curl -X PUT HOST\/api\/cms\/1\/blocks\/5 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022 \\\n  -H \u0027Content-Type: application\/json\u0027 \\\n  -d \u0027{\u0022priority\u0022:2,\u0022json\u0022:{\u0022text\u0022:\u0022Updated\u0022}}\u0027","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}},{"name":"blockId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK"}}},"delete":{"tags":["cms-blocks"],"summary":"Delete block","x-example":"curl -X DELETE HOST\/api\/cms\/1\/blocks\/5 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}},{"name":"blockId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"204":{"description":"Deleted"}}}},"\/api\/logs":{"get":{"tags":["logs"],"summary":"Summary of all log streams (counts + latest timestamps)","x-example":"curl \u0027HOST\/api\/logs\u0027 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"\/api\/logs\/system":{"get":{"tags":["logs"],"summary":"Recent file-based system log entries (Monolog rotating file)","x-example":"curl \u0027HOST\/api\/logs\/system?limit=50\u0026level=WARNING\u0027 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"},"400":{"description":"Bad request - limit out of range or non-numeric"}}}},"\/api\/logs\/activity":{"get":{"tags":["logs"],"summary":"Recent user activity stream entries","x-example":"curl \u0027HOST\/api\/logs\/activity?limit=50\u0027 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"},"400":{"description":"Bad request - limit out of range or non-numeric"}}}},"\/api\/logs\/not-found":{"get":{"tags":["logs"],"summary":"Recent 404 not-found URL log entries","x-example":"curl \u0027HOST\/api\/logs\/not-found?limit=50\u0027 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"},"400":{"description":"Bad request - limit out of range or non-numeric"}}}},"\/api\/logs\/cron":{"get":{"tags":["logs"],"summary":"Recent cron run log entries","x-example":"curl \u0027HOST\/api\/logs\/cron?limit=50\u0027 \\\n  -H \u0022Authorization: Bearer $TOKEN\u0022","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"},"400":{"description":"Bad request - limit out of range or non-numeric"}}}},"\/api\/groups":{"get":{"tags":["data"],"summary":"List public groups (multisite plugin only)","x-example":"curl HOST\/api\/groups","responses":{"200":{"description":"OK","content":{"application\/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#\/components\/schemas\/Group"}},"total":{"type":"integer"}}}}}},"404":{"description":"Plugin not active"}}}},"\/api\/groups\/{slug}":{"get":{"tags":["data"],"summary":"Single group detail","x-example":"curl HOST\/api\/groups\/my-group","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Group"}}}},"404":{"description":"Not found"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"EventSummary":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"start":{"type":"string","format":"date-time"},"end":{"type":["string","null"],"format":"date-time"},"location":{"type":"string"},"url":{"type":"string","format":"uri"},"previewImageUrl":{"type":["string","null"],"format":"uri"}}},"EventDetail":{"allOf":[{"$ref":"#\/components\/schemas\/EventSummary"},{"type":"object","properties":{"description":{"type":"string"}}}]},"Group":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"domain":{"type":["string","null"]},"url":{"type":"string","format":"uri"}}}}}}