{"components":{"parameters":{"backendPath":{"description":"Backend sub-path to forward to (e.g. `validateApiKey`, `login`, `getInstanceUserPackage`)","example":"validateApiKey","in":"path","name":"path","required":true,"schema":{"type":"string"}},"slug":{"description":"Instance slug identifier (lowercase alphanumeric, hyphens, underscores)","example":"game_hoster","in":"path","name":"slug","required":true,"schema":{"pattern":"^[a-z0-9_-]+$","type":"string"}}},"responses":{"NotFound":{"content":{"application/json":{"schema":{"properties":{"error":{"example":"Nicht gefunden","type":"string"},"ok":{"example":false,"type":"boolean"}},"type":"object"}}},"description":"Resource not found"},"ProxyNetworkError":{"content":{"application/json":{"example":{"error":"Backend nicht erreichbar","error_type":"network","ok":false,"retryable":true},"schema":{"$ref":"#/components/schemas/ProxyErrorResponse"}}},"description":"Backend unreachable (network/connection error)"},"ProxyTimeout":{"content":{"application/json":{"example":{"error":"Request timed out","error_type":"timeout","ok":false,"retryable":true},"schema":{"$ref":"#/components/schemas/ProxyErrorResponse"}}},"description":"Proxy timeout \u2014 upstream exceeded 15 s response window"},"RateLimited":{"content":{"application/json":{"schema":{"properties":{"error":{"example":"Too many requests","type":"string"}},"type":"object"}}},"description":"Rate limit exceeded \u2014 slow down and retry","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer"}}}}},"schemas":{"HealthResponse":{"properties":{"status":{"enum":["ok"],"example":"ok","type":"string"}},"required":["status"],"type":"object"},"HubAiDraftRequest":{"properties":{"brief":{"example":"Erzeuge ein ruhiges B2B Branding","type":"string"},"existing_data":{"type":"object"},"prompt":{"description":"Alias for brief","type":"string"},"prompts":{"items":{"type":"string"},"type":"array"},"target":{"enum":["branding","project","legal"],"type":"string"}},"type":"object"},"HubAiDraftResponse":{"description":"KI draft response. `demo_json` is returned for REST clients and is not persisted.","properties":{"demo_json":{"type":"object"},"draft":{"type":"object"},"missing_inputs":{"items":{"type":"string"},"type":"array"},"model":{"example":"hub_assistant","type":"string"},"ok":{"example":true,"type":"boolean"},"provider":{"example":"ki_manager","type":"string"},"run_id":{"example":"run_123","type":"string"},"target":{"example":"branding","type":"string"},"warnings":{"items":{"type":"string"},"type":"array"}},"type":"object"},"HubApiToken":{"description":"API token metadata. Never includes the secret/hash; raw_token is returned only at creation.","properties":{"created_at":{"example":"2026-01-01T00:00:00+00:00","type":"string"},"created_by":{"example":"uuid-of-creator","type":"string"},"expires_at":{"example":null,"type":["string","null"]},"hub_id":{"example":"hub_platform_home","type":"string"},"last_used_at":{"example":null,"type":["string","null"]},"name":{"example":"CI read token","type":"string"},"prefix":{"example":"cha_AbCdEf12","type":"string"},"revoked":{"example":false,"type":"boolean"},"scopes":{"example":["hub:read"],"items":{"type":"string"},"type":"array"},"token_id":{"example":"b1c2d3e4-...","type":"string"}},"type":"object"},"HubAppsResponse":{"description":"Apps installed on a hub (token- or session-readable).","properties":{"apps":{"items":{"properties":{"category":{"example":"support","type":"string"},"description":{"example":"Ticket system","type":"string"},"icon":{"example":"\ud83d\udce6","type":"string"},"name":{"example":"Helpdesk","type":"string"},"slug":{"example":"helpdesk","type":"string"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"type":"array"},"hub_id":{"example":"hub_platform_home","type":"string"},"ok":{"example":true,"type":"boolean"}},"required":["ok","apps"],"type":"object"},"HubAuditEntry":{"description":"A single hub audit event. Sensitive values (API keys, secrets) are stored redacted.","properties":{"action":{"example":"hub_webhook_created","type":"string"},"actor":{"example":"owner-uuid","type":"string"},"category":{"example":"hub","type":"string"},"details":{"example":"{\"webhook_id\": \"wh_...\"}","type":"string"},"ip":{"example":"","type":"string"},"severity":{"example":"info","type":"string"},"ts":{"example":"2026-01-01T00:00:00+00:00","type":"string"}},"type":"object"},"HubAuditLogResponse":{"description":"Hub audit log entries (most recent first). No secrets are exposed.","properties":{"entries":{"items":{"$ref":"#/components/schemas/HubAuditEntry"},"type":"array"},"hub_id":{"example":"hub_platform_home","type":"string"},"ok":{"example":true,"type":"boolean"},"total":{"example":0,"type":"integer"}},"required":["ok","entries"],"type":"object"},"HubBillingSummaryResponse":{"description":"Aggregate billing totals only \u2014 no individual transaction details are exposed.","properties":{"currency":{"example":"EUR","type":"string"},"hub_id":{"example":"hub_platform_home","type":"string"},"next_payout":{"example":"","type":"string"},"ok":{"example":true,"type":"boolean"},"total_earned":{"example":0,"type":"number"},"total_paid_out":{"example":0,"type":"number"},"total_pending":{"example":0,"type":"number"}},"required":["ok"],"type":"object"},"HubBranding":{"properties":{"accent_color":{"example":"#f59e0b","type":"string"},"background_color":{"example":"#06060e","type":"string"},"company_name":{"example":"DEELIAR","type":"string"},"custom_css":{"example":"","type":"string"},"favicon_url":{"example":"","type":"string"},"footer_text":{"example":"","type":"string"},"hide_powered_by":{"example":false,"type":"boolean"},"logo_url":{"example":"","type":"string"},"primary_color":{"example":"#6366f1","type":"string"},"primary_light":{"example":"#818cf8","type":"string"},"surface_color":{"example":"#14141f","type":"string"},"tagline":{"example":"App Hub","type":"string"},"text_color":{"example":"#f1f5f9","type":"string"}},"type":"object"},"HubBrandingResponse":{"properties":{"branding":{"$ref":"#/components/schemas/HubBranding"},"hub_id":{"example":"hub_platform_home","type":"string"},"ok":{"example":true,"type":"boolean"}},"required":["ok","hub_id","branding"],"type":"object"},"HubDetailResponse":{"description":"Hub object. Field set varies by authentication level: public (no auth), editor (session with editor role), or admin (session with owner/admin role).","properties":{"hub":{"properties":{"apps":{"description":"App slugs assigned to this hub","items":{"type":"string"},"type":"array"},"apps_detail":{"description":"Enriched app objects (always present)","items":{"type":"object"},"type":"array"},"hub_id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"status":{"enum":["active","trial","suspended","cancelled"],"type":"string"}},"type":"object"},"ok":{"example":true,"type":"boolean"}},"required":["ok","hub"],"type":"object"},"HubListResponse":{"properties":{"hubs":{"items":{"$ref":"#/components/schemas/HubPublic"},"type":"array"},"ok":{"example":true,"type":"boolean"}},"required":["ok","hubs"],"type":"object"},"HubProject":{"properties":{"active":{"example":true,"type":"boolean"},"app_url":{"example":"https://example.com","type":"string"},"category":{"example":"productivity","type":"string"},"config":{"type":"object"},"description":{"example":"Kurzbeschreibung","type":["string","object"]},"i18n":{"type":"object"},"icon":{"example":"\ud83d\ude80","type":"string"},"legal":{"type":"object"},"modus":{"example":"prod","type":"string"},"name":{"example":"My Tool","type":"string"},"packages":{"items":{"type":"object"},"type":"array"},"slug":{"example":"my-tool","type":"string"}},"type":"object"},"HubProjectRequest":{"properties":{"app_url":{"example":"https://example.com","type":"string"},"category":{"example":"productivity","type":"string"},"description_de":{"type":"string"},"description_en":{"type":"string"},"features":{"items":{"type":"object"},"type":"array"},"i18n":{"type":"object"},"icon":{"example":"\ud83d\ude80","type":"string"},"legal":{"type":"object"},"link_docs":{"type":"string"},"link_support":{"type":"string"},"modus_view_kachel":{"example":"prod","type":"string"},"name":{"example":"My Tool","type":"string"},"packages":{"items":{"type":"object"},"type":"array"},"primary_color":{"example":"#6366f1","type":"string"},"slug":{"example":"my-tool","type":"string"},"tagline_de":{"type":"string"},"tagline_en":{"type":"string"},"type":{"example":"platform","type":"string"},"waitlist_url":{"type":"string"}},"required":["name","slug"],"type":"object"},"HubPublic":{"properties":{"apps_count":{"example":3,"type":"integer"},"auth_mode":{"enum":["platform","invite_only","external"],"example":"platform","type":"string"},"company_name":{"example":"Acme GmbH","type":"string"},"hub_id":{"example":"hub_abc123","type":"string"},"logo_url":{"example":"","type":"string"},"name":{"example":"Mein Hub","type":"string"},"primary_color":{"example":"#6366f1","type":"string"},"slug":{"example":"mein-hub","type":"string"},"storefront":{"type":"object"},"tagline":{"example":"Willkommen bei Mein Hub","type":"string"},"tier":{"enum":["hub_free","hub_starter","hub_pro","hub_enterprise"],"example":"hub_pro","type":"string"}},"type":"object"},"HubPublicProfileResponse":{"description":"Non-sensitive public profile of a hub (token- or session-readable).","properties":{"apps":{"items":{"properties":{"category":{"example":"support","type":"string"},"icon":{"example":"\ud83d\udce6","type":"string"},"name":{"example":"Helpdesk","type":"string"},"slug":{"example":"helpdesk","type":"string"}},"type":"object"},"type":"array"},"branding":{"properties":{"accent_color":{"example":"#f59e0b","type":"string"},"company_name":{"example":"DEELIAR","type":"string"},"logo_url":{"example":"","type":"string"},"primary_color":{"example":"#6366f1","type":"string"},"primary_light":{"example":"#818cf8","type":"string"},"tagline":{"example":"App Hub","type":"string"}},"type":"object"},"hub_id":{"example":"hub_platform_home","type":"string"},"name":{"example":"DEELIAR","type":"string"},"ok":{"example":true,"type":"boolean"},"settings":{"properties":{"auth_mode":{"example":"hub","type":"string"},"registration_open":{"example":true,"type":"boolean"}},"type":"object"},"slug":{"example":"home","type":"string"},"status":{"example":"active","type":"string"},"tier":{"example":"platform","type":"string"}},"required":["ok","hub_id"],"type":"object"},"HubSettingsResponse":{"description":"Non-sensitive hub settings. Built from an explicit allowlist \u2014 never contains Stripe keys, API tokens, webhook secrets, internal UUIDs or SMTP/e-mail credentials.","properties":{"auth_mode":{"example":"platform","type":"string"},"default_language":{"example":"de","type":"string"},"features":{"additionalProperties":{"type":"boolean"},"description":"Active feature/module flags (booleans only), derived from the hub tier/package.","example":{"custom_branding":true,"custom_domain":false,"stripe_billing":true},"type":"object"},"hub_id":{"example":"hub_platform_home","type":"string"},"ok":{"example":true,"type":"boolean"},"settings":{"properties":{"billing_enabled":{"example":false,"type":"boolean"},"custom_branding":{"example":false,"type":"boolean"},"registration_open":{"example":true,"type":"boolean"},"visibility":{"example":"public","type":"string"}},"type":"object"}},"required":["ok","hub_id","settings"],"type":"object"},"HubTokenCreateResponse":{"description":"Result of creating an API token. raw_token is shown ONLY here and is never retrievable again.","properties":{"ok":{"example":true,"type":"boolean"},"token":{"properties":{"prefix":{"example":"cha_AbCdEf12","type":"string"},"raw_token":{"example":"cha_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","type":"string"},"scopes":{"example":["hub:read"],"items":{"type":"string"},"type":"array"},"token_id":{"example":"b1c2d3e4-...","type":"string"}},"required":["token_id","prefix","scopes","raw_token"],"type":"object"}},"required":["ok","token"],"type":"object"},"HubTokenListResponse":{"description":"List of API tokens for a hub. Secrets/raw tokens are never included.","properties":{"ok":{"example":true,"type":"boolean"},"tokens":{"items":{"$ref":"#/components/schemas/HubApiToken"},"type":"array"}},"required":["ok","tokens"],"type":"object"},"HubWebhook":{"description":"Webhook configuration. The signing secret is NEVER returned in plain text here \u2014 only a masked preview.","properties":{"created_at":{"example":"2026-01-01T00:00:00+00:00","type":"string"},"description":{"example":"Billing sync","type":"string"},"enabled":{"example":true,"type":"boolean"},"events":{"example":["rental.created","hub.updated"],"items":{"type":"string"},"type":"array"},"hub_id":{"example":"hub_platform_home","type":"string"},"secret_masked":{"example":"whsec_********************1a2b","type":"string"},"url":{"example":"https://example.com/hooks/deeliar","type":"string"},"webhook_id":{"example":"wh_ab12cd34ef56gh78ij90","type":"string"}},"type":"object"},"HubWebhookCreateRequest":{"properties":{"description":{"example":"Billing sync","type":"string"},"events":{"example":["rental.created"],"items":{"enum":["rental.created","rental.cancelled","hub.status_changed","hub.updated","project.created","project.updated","project.deleted"],"type":"string"},"type":"array"},"url":{"example":"https://example.com/hooks/deeliar","type":"string"}},"required":["url","events"],"type":"object"},"HubWebhookCreateResponse":{"description":"Result of creating a webhook. `secret` is the signing secret and is shown ONLY here, once.","properties":{"ok":{"example":true,"type":"boolean"},"secret":{"example":"whsec_xxxxxxxxxxxxxxxxxxxxxxxx","type":"string"},"webhook_id":{"example":"wh_ab12cd34ef56gh78ij90","type":"string"}},"required":["ok","webhook_id","secret"],"type":"object"},"HubWebhookDeliveriesResponse":{"properties":{"deliveries":{"items":{"$ref":"#/components/schemas/HubWebhookDelivery"},"type":"array"},"ok":{"example":true,"type":"boolean"}},"required":["ok","deliveries"],"type":"object"},"HubWebhookDelivery":{"properties":{"attempts":{"example":1,"type":"integer"},"created_at":{"example":"2026-01-01T00:00:00+00:00","type":"string"},"delivery_id":{"example":"whd_123","type":"string"},"event":{"example":"rental.created","type":"string"},"status":{"example":"delivered","type":"string"},"status_code":{"example":200,"type":["integer","null"]},"webhook_id":{"example":"wh_ab12cd34ef56gh78ij90","type":"string"}},"type":"object"},"HubWebhookListResponse":{"description":"List of webhook configurations. Signing secrets are masked, never in plain text.","properties":{"ok":{"example":true,"type":"boolean"},"webhooks":{"items":{"$ref":"#/components/schemas/HubWebhook"},"type":"array"}},"required":["ok","webhooks"],"type":"object"},"HubWebhookRotateSecretResponse":{"description":"New signing secret after rotation. Shown ONLY here, once.","properties":{"ok":{"example":true,"type":"boolean"},"secret":{"example":"whsec_xxxxxxxxxxxxxxxxxxxxxxxx","type":"string"}},"required":["ok","secret"],"type":"object"},"HubWebhookTestResponse":{"description":"Result of a synchronous test delivery.","properties":{"error":{"example":"","type":"string"},"ok":{"example":true,"type":"boolean"},"response_body":{"example":"","type":"string"},"status_code":{"example":200,"type":["integer","null"]}},"required":["ok"],"type":"object"},"HubWebhookUpdateRequest":{"description":"Partial update. Any subset of fields may be supplied.","properties":{"description":{"example":"Billing sync","type":"string"},"enabled":{"example":true,"type":"boolean"},"events":{"example":["hub.updated"],"items":{"type":"string"},"type":"array"},"url":{"example":"https://example.com/hooks/deeliar","type":"string"}},"type":"object"},"IncidentEntry":{"properties":{"date":{"example":"2026-04-10","format":"date","type":"string"},"date_display":{"example":"10. April 2026","type":"string"},"desc":{"example":"Kurzfristig erh\u00f6hte Antwortzeiten aufgrund DB-Last","type":"string"},"resolved_display":{"example":"Behoben um 14:32 UTC","type":"string"},"title":{"example":"Erh\u00f6hte Latenz API","type":"string"}},"type":"object"},"IncidentsResponse":{"properties":{"incidents":{"items":{"$ref":"#/components/schemas/IncidentEntry"},"type":"array"},"ok":{"example":true,"type":"boolean"}},"required":["ok","incidents"],"type":"object"},"InstanceConfigResponse":{"description":"Public instance configuration fields","properties":{"category":{"example":"gaming","type":"string"},"icon":{"example":"\ud83c\udfae","type":"string"},"name":{"example":"Game Hoster","type":"string"},"slug":{"example":"game_hoster","type":"string"},"type":{"example":"platform","type":"string"}},"type":"object"},"LegalDocVersion":{"properties":{"acceptance_count":{"example":0,"type":"integer"},"doc_type":{"enum":["privacy","imprint","terms"],"type":"string"},"hub_id":{"example":"hub_platform_home","type":"string"},"id":{"example":"ldv_123","type":"string"},"lang":{"enum":["de","en"],"type":"string"},"note":{"example":"Entwurf","type":"string"},"sections":{"items":{"type":"object"},"type":"array"},"status":{"example":"draft","type":"string"},"title":{"example":"Datenschutzerkl\u00e4rung","type":"string"},"version_num":{"example":1,"type":"integer"}},"type":"object"},"LegalDocVersionRequest":{"properties":{"doc_type":{"enum":["privacy","imprint","terms"],"type":"string"},"lang":{"enum":["de","en"],"example":"de","type":"string"},"note":{"type":"string"},"sections":{"items":{"properties":{"content":{"type":"string"},"heading":{"type":"string"}},"type":"object"},"type":"array"},"title":{"example":"Datenschutzerkl\u00e4rung","type":"string"}},"type":"object"},"OkResponse":{"properties":{"ok":{"example":true,"type":"boolean"}},"required":["ok"],"type":"object"},"ProxyErrorResponse":{"properties":{"error":{"example":"Request timed out","type":"string"},"error_type":{"enum":["timeout","network","upstream_error"],"type":"string"},"ok":{"example":false,"type":"boolean"},"retryable":{"description":"true for GET/HEAD/OPTIONS on timeout/network errors; always false for POST/PUT/PATCH/DELETE and upstream errors","type":"boolean"}},"required":["ok","error","error_type","retryable"],"type":"object"},"ServiceEntry":{"properties":{"key":{"example":"hub","type":"string"},"latency_ms":{"description":"Round-trip latency in ms for http_ping sources; null for others","example":12,"type":["integer","null"]},"source":{"enum":["internal","internal_metrics","http_ping","fs_check","env_check","smtp_config","smtp_tcp","public_summary"],"example":"internal","type":"string"},"status":{"enum":["up","degraded","down"],"example":"up","type":"string"}},"required":["key","status","latency_ms","source"],"type":"object"},"ServiceStatusResponse":{"properties":{"monitoring_ok":{"description":"false when at least one external check failed (partial data state)","example":true,"type":"boolean"},"ok":{"example":true,"type":"boolean"},"services":{"items":{"$ref":"#/components/schemas/ServiceEntry"},"type":"array"}},"required":["ok","monitoring_ok","services"],"type":"object"},"UptimeDayEntry":{"properties":{"date":{"example":"2026-04-24","format":"date","type":"string"},"status":{"enum":["up","degraded","unknown"],"example":"up","type":"string"}},"required":["date","status"],"type":"object"},"UptimeResponse":{"properties":{"days":{"description":"Always exactly 30 entries, chronologically ascending","items":{"$ref":"#/components/schemas/UptimeDayEntry"},"maxItems":30,"minItems":30,"type":"array"},"ok":{"example":true,"type":"boolean"}},"required":["ok","days"],"type":"object"},"ValidateApiKeyRequest":{"properties":{"api_key":{"description":"The API key to validate","example":"dlr_live_xxxxxxxxxxxx","type":"string"},"required_scope":{"description":"Optional: only accept keys with this scope (or full-access). Keys without a scope field default to full-access for backwards compatibility.","enum":["read-only","billing-read","integration-write","full-access"],"example":"billing-read","type":"string"}},"required":["api_key"],"type":"object"},"ValidateApiKeyResponse":{"properties":{"control":{"description":"true = valid key; false = invalid, revoked, or insufficient scope","type":"boolean"},"error":{"description":"Error message. Present only when control=false.","example":"Insufficient scope","type":"string"},"kunde_uuid":{"description":"Permanent account UUID. Present only when control=true.","example":"<account-uuid>","type":"string"},"scopes":{"description":"Scopes assigned to this key. Present only when control=true.","example":["billing-read"],"items":{"type":"string"},"type":"array"}},"required":["control"],"type":"object"}},"securitySchemes":{"ApiKeyHeader":{"description":"Server-to-server API key. Created via Dashboard \u2192 Settings \u2192 API Keys. Shown in plain text only once at creation. **Never use in browser code.** Scopes: `read-only` | `billing-read` | `integration-write` | `full-access`.","in":"header","name":"X-API-Key","type":"apiKey"},"HubBearerToken":{"bearerFormat":"cha_...","description":"Hub-scoped Bearer token created in Hub Admin \u2192 Integration & Docs. Tokens are limited to one hub_id and explicit scopes such as `hub:branding:read`, `hub:projects:write`, `hub:legal:write`, `hub:ai:draft`.","scheme":"bearer","type":"http"},"SessionCookie":{"description":"Session cookie issued after successful platform login. Used for browser-facing dashboard flows only \u2014 **not suitable for server-to-server integrations.**","in":"cookie","name":"session","type":"apiKey"}}},"info":{"contact":{"name":"DEELIAR Support","url":"/support"},"description":"DEELIAR is a web-based multi-tenant platform. This specification covers:\n\n- **Public endpoints** accessible without authentication\n- **Server-to-server endpoints** via the backend proxy (`/backendserver/*`), requiring an `X-API-Key` header\n\n- **Hub Admin REST endpoints** for token-authenticated branding, project, legal, and KI demo JSON workflows\n\n**Not covered here** (excluded intentionally):\n- Browser session-only flows (login, dashboard, account management)\n- Platform-admin-only endpoints (`/api/hubs` write operations, `/metrics`)\n- Internal or unstable endpoints\n\nFor the full session-based browser documentation see `/api-docs`.\n\n**Authentication flows are mutually exclusive:**\n- `SessionCookie` \u2014 browser login flows only; never use for server integrations\n- `ApiKeyHeader` \u2014 server-to-server only via `/backendserver/*`; never expose in browsers\n- `HubBearerToken` \u2014 Hub Admin REST access with tenant-scoped Bearer tokens","license":{"name":"Proprietary \u2014 All rights reserved"},"title":"DEELIAR Platform API","version":"2.6.0"},"openapi":"3.1.0","paths":{"/api/hubs/packages":{"get":{"description":"Returns the list of available hub subscription packages/tiers. No authentication required.","operationId":"listHubPackages","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"ok":{"example":true,"type":"boolean"},"packages":{"items":{"type":"object"},"type":"array"}},"required":["ok","packages"],"type":"object"}}},"description":"Package list"}},"security":[],"summary":"List available hub packages","tags":["public-hubs"]}},"/api/hubs/public":{"get":{"description":"Returns all hubs with status `active`, including public branding fields. No authentication required. Rate-limited to 30 req/min.","operationId":"listPublicHubs","responses":{"200":{"content":{"application/json":{"example":{"hubs":[{"apps_count":3,"hub_id":"hub_abc123","name":"Mein Hub","primary_color":"#6366f1","slug":"mein-hub","tagline":"Willkommen bei Mein Hub","tier":"hub_pro"}],"ok":true},"schema":{"$ref":"#/components/schemas/HubListResponse"}}},"description":"List of active hubs"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[],"summary":"List active hubs","tags":["public-hubs"]}},"/api/hubs/{hub_id}":{"get":{"description":"Returns hub details. Public fields are returned without authentication. Sensitive fields (billing, API keys, admin lists) are only included when the request is authenticated as a hub admin or owner via session cookie. Rate-limited to 30 req/min.","operationId":"getHub","parameters":[{"description":"Unique hub identifier","example":"hub_abc123","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubDetailResponse"}}},"description":"Hub data (field set varies by authentication level)"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"SessionCookie":[]}],"summary":"Hub details","tags":["public-hubs"]}},"/api/hubs/{hub_id}/apps":{"get":{"description":"Returns the apps installed on this hub with display metadata. Accessible via session cookie or Bearer token. Requires the `hub:apps:read` scope.","operationId":"listHubApps","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubAppsResponse"}}},"description":"Success"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:apps:read` scope"}},"security":[{"HubBearerToken":[]}],"summary":"List hub apps","tags":["hub-admin"]}},"/api/hubs/{hub_id}/audit-log":{"get":{"description":"Returns hub-scoped audit events (most recent first). Accessible to hub owner/admins via session, or a Bearer token with `hub:audit:read`. Sensitive values are redacted; no secrets are exposed. Optional filters: action, from, to (YYYY-MM-DD), limit (10\u2013500).","operationId":"getHubAuditLog","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"action","schema":{"type":"string"}},{"in":"query","name":"from","schema":{"example":"2026-01-01","type":"string"}},{"in":"query","name":"to","schema":{"example":"2026-12-31","type":"string"}},{"in":"query","name":"limit","schema":{"default":200,"maximum":500,"minimum":10,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubAuditLogResponse"}}},"description":"Success"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:audit:read` scope"}},"security":[{"HubBearerToken":[]}],"summary":"Read hub audit log","tags":["hub-admin"]}},"/api/hubs/{hub_id}/audit-log/export":{"get":{"description":"Exports the hub audit log as a downloadable JSON or CSV attachment. Accessible to hub owner/admins via session, or a Bearer token with `hub:audit:read`. No secrets are exposed.","operationId":"exportHubAuditLog","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"format","schema":{"default":"json","enum":["json","csv"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/HubAuditEntry"},"type":"array"}},"text/csv":{"schema":{"type":"string"}}},"description":"Audit log file (Content-Disposition: attachment)"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:audit:read` scope"}},"security":[{"HubBearerToken":[]}],"summary":"Export hub audit log","tags":["hub-admin"]}},"/api/hubs/{hub_id}/billing-summary":{"get":{"description":"Returns aggregate billing totals only \u2014 no individual transaction details. Accessible via session cookie or Bearer token. Requires the `hub:billing:read` scope.","operationId":"getHubBillingSummary","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubBillingSummaryResponse"}}},"description":"Success"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:billing:read` scope"}},"security":[{"HubBearerToken":[]}],"summary":"Get hub billing summary","tags":["hub-admin"]}},"/api/hubs/{hub_id}/branding":{"get":{"description":"Returns the editable branding JSON for one hub. Requires `hub:branding:read`.","operationId":"getHubBranding","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubBrandingResponse"}}},"description":"Success"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:branding:read` scope"}},"security":[{"HubBearerToken":[]}],"summary":"Get hub branding","tags":["hub-admin"]},"patch":{"description":"Updates branding fields. AI is not used; this persists the submitted JSON. Requires `hub:branding:write`.","operationId":"updateHubBranding","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubBranding"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubBrandingResponse"}}},"description":"Success"},"400":{"description":"Invalid branding payload"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:branding:write` scope"}},"security":[{"HubBearerToken":[]}],"summary":"Update hub branding","tags":["hub-admin"]}},"/api/hubs/{hub_id}/branding/ai/demo-json":{"post":{"description":"Calls the configured KI Manager and returns normalized demo JSON only. No Hub data is persisted by this endpoint.","operationId":"generateHubBrandingDemoJson","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubAiDraftRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubAiDraftResponse"}}},"description":"Draft generated"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:ai:draft` scope"},"503":{"description":"KI Manager/provider unavailable or not configured"}},"security":[{"HubBearerToken":[]}],"summary":"Generate branding demo JSON","tags":["hub-admin"]}},"/api/hubs/{hub_id}/legal-docs":{"get":{"description":"Lists legal document versions. Requires `hub:legal:read` and Hub owner/admin session or token scope.","operationId":"listHubLegalDocs","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"doc_type","schema":{"enum":["privacy","imprint","terms"],"type":"string"}},{"in":"query","name":"lang","schema":{"enum":["de","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"ok":{"type":"boolean"},"versions":{"items":{"$ref":"#/components/schemas/LegalDocVersion"},"type":"array"}},"type":"object"}}},"description":"Legal versions"}},"security":[{"HubBearerToken":[]}],"summary":"List legal document versions","tags":["hub-admin"]},"post":{"description":"Creates a new legal document version. Requires `hub:legal:write`.","operationId":"createHubLegalDoc","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegalDocVersionRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"ok":{"type":"boolean"},"version":{"$ref":"#/components/schemas/LegalDocVersion"}},"type":"object"}}},"description":"Version created"},"400":{"description":"Invalid legal document payload"}},"security":[{"HubBearerToken":[]}],"summary":"Create legal document draft","tags":["hub-admin"]}},"/api/hubs/{hub_id}/legal-docs/ai/demo-json":{"post":{"description":"Calls the configured KI Manager and returns normalized demo JSON only. No Hub data is persisted by this endpoint.","operationId":"generateHubLegalDemoJson","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubAiDraftRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubAiDraftResponse"}}},"description":"Draft generated"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:ai:draft` scope"},"503":{"description":"KI Manager/provider unavailable or not configured"}},"security":[{"HubBearerToken":[]}],"summary":"Generate legal demo JSON","tags":["hub-admin"]}},"/api/hubs/{hub_id}/legal-docs/seed":{"post":{"operationId":"seedHubLegalDocs","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"activate":{"example":true,"type":"boolean"},"force":{"example":false,"type":"boolean"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"}},"security":[{"HubBearerToken":[]}],"summary":"Seed default legal templates","tags":["hub-admin"]}},"/api/hubs/{hub_id}/legal-docs/stats":{"get":{"operationId":"getHubLegalDocStats","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"doc_type","required":true,"schema":{"enum":["privacy","imprint","terms"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"}},"security":[{"HubBearerToken":[]}],"summary":"Get legal acceptance stats","tags":["hub-admin"]}},"/api/hubs/{hub_id}/legal-docs/{version_id}":{"delete":{"operationId":"deleteHubLegalDoc","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"ldv_123","in":"path","name":"version_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"},"409":{"description":"Only drafts can be deleted"}},"security":[{"HubBearerToken":[]}],"summary":"Delete legal document draft","tags":["hub-admin"]},"get":{"operationId":"getHubLegalDoc","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"ldv_123","in":"path","name":"version_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"ok":{"type":"boolean"},"version":{"$ref":"#/components/schemas/LegalDocVersion"}},"type":"object"}}},"description":"Legal version"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"HubBearerToken":[]}],"summary":"Get legal document version","tags":["hub-admin"]},"patch":{"operationId":"updateHubLegalDoc","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"ldv_123","in":"path","name":"version_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegalDocVersionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"ok":{"type":"boolean"},"version":{"$ref":"#/components/schemas/LegalDocVersion"}},"type":"object"}}},"description":"Legal version updated"},"409":{"description":"Only drafts can be edited"}},"security":[{"HubBearerToken":[]}],"summary":"Update legal document draft","tags":["hub-admin"]}},"/api/hubs/{hub_id}/legal-docs/{version_id}/activate":{"post":{"description":"Activates a legal doc version and archives the previous active version. Requires `hub:legal:write`.","operationId":"activateHubLegalDoc","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"ldv_123","in":"path","name":"version_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"ok":{"type":"boolean"},"version":{"$ref":"#/components/schemas/LegalDocVersion"}},"type":"object"}}},"description":"Version activated"}},"security":[{"HubBearerToken":[]}],"summary":"Activate legal document version","tags":["hub-admin"]}},"/api/hubs/{hub_id}/projects":{"get":{"description":"Lists Custom Projects configured in the hub. Requires `hub:projects:read`.","operationId":"listHubProjects","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"ok":{"type":"boolean"},"projects":{"items":{"$ref":"#/components/schemas/HubProject"},"type":"array"}},"type":"object"}}},"description":"Project list"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:projects:read` scope"}},"security":[{"HubBearerToken":[]}],"summary":"List custom projects","tags":["hub-admin"]},"post":{"description":"Creates and persists a custom project/instance. Requires `hub:projects:write`.","operationId":"createHubProject","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubProjectRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"name":{"example":"My Tool","type":"string"},"ok":{"example":true,"type":"boolean"},"slug":{"example":"my-tool","type":"string"}},"type":"object"}}},"description":"Project created"},"400":{"description":"Invalid project payload"},"409":{"description":"Slug already exists"}},"security":[{"HubBearerToken":[]}],"summary":"Create custom project","tags":["hub-admin"]}},"/api/hubs/{hub_id}/projects/ai/demo-json":{"post":{"description":"Calls the configured KI Manager and returns normalized demo JSON only. No Hub data is persisted by this endpoint.","operationId":"generateHubProjectDemoJson","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubAiDraftRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubAiDraftResponse"}}},"description":"Draft generated"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:ai:draft` scope"},"503":{"description":"KI Manager/provider unavailable or not configured"}},"security":[{"HubBearerToken":[]}],"summary":"Generate project demo JSON","tags":["hub-admin"]}},"/api/hubs/{hub_id}/projects/reorder":{"post":{"description":"Persists custom project ordering. Requires `hub:projects:write`.","operationId":"reorderHubProjects","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"order":{"items":{"type":"string"},"type":"array"}},"required":["order"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"}},"security":[{"HubBearerToken":[]}],"summary":"Reorder custom projects","tags":["hub-admin"]}},"/api/hubs/{hub_id}/projects/{slug}":{"delete":{"description":"Removes a custom project from the hub. Requires `hub:projects:write`.","operationId":"deleteHubProject","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"my-tool","in":"path","name":"slug","required":true,"schema":{"pattern":"^[a-z0-9_-]+$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"HubBearerToken":[]}],"summary":"Delete custom project","tags":["hub-admin"]},"get":{"operationId":"getHubProject","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"my-tool","in":"path","name":"slug","required":true,"schema":{"pattern":"^[a-z0-9_-]+$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"ok":{"type":"boolean"},"project":{"$ref":"#/components/schemas/HubProject"}},"type":"object"}}},"description":"Project detail"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"HubBearerToken":[]}],"summary":"Get custom project","tags":["hub-admin"]},"patch":{"description":"Updates and persists project JSON. Requires `hub:projects:write`.","operationId":"updateHubProject","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"my-tool","in":"path","name":"slug","required":true,"schema":{"pattern":"^[a-z0-9_-]+$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubProjectRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"},"400":{"description":"Invalid project payload"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"HubBearerToken":[]}],"summary":"Update custom project","tags":["hub-admin"]}},"/api/hubs/{hub_id}/public-profile":{"get":{"description":"Returns non-sensitive hub data (name, status, branding subset, apps, public settings). Accessible via session cookie or Bearer token. Requires the `hub:read` scope.","operationId":"getHubPublicProfile","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubPublicProfileResponse"}}},"description":"Success"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:read` scope"}},"security":[{"HubBearerToken":[]}],"summary":"Get hub public profile","tags":["hub-admin"]}},"/api/hubs/{hub_id}/settings":{"get":{"description":"Returns non-sensitive hub settings (auth mode, registration/visibility flags, default language, active feature flags). No secrets, keys or tokens are exposed. Accessible via session cookie or Bearer token. Requires the `hub:settings:read` scope.","operationId":"getHubSettings","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubSettingsResponse"}}},"description":"Success"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:settings:read` scope"}},"security":[{"HubBearerToken":[]}],"summary":"Get hub settings","tags":["hub-admin"]}},"/api/hubs/{hub_id}/tokens":{"get":{"description":"Lists all active API tokens for this hub (metadata only \u2014 secrets are never returned). Requires a hub owner/admin session cookie.","operationId":"listHubApiTokens","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubTokenListResponse"}}},"description":"Success"},"401":{"description":"Not authenticated"},"403":{"description":"No owner/admin access to this hub"}},"security":[{"SessionCookie":[]}],"summary":"List hub API tokens","tags":["hub-admin"]},"post":{"description":"Creates a new API token for this hub. The plain-text `raw_token` is returned ONLY in this response and is never retrievable again. Requires a hub owner/admin session cookie plus a valid CSRF token.","operationId":"createHubApiToken","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"expires_at":{"description":"ISO-8601 UTC timestamp; omit for no expiry.","type":"string"},"name":{"example":"CI read token","type":"string"},"scopes":{"example":["hub:read"],"items":{"type":"string"},"type":"array"}},"required":["name","scopes"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubTokenCreateResponse"}}},"description":"Token created"},"400":{"description":"Invalid name/scopes payload"},"401":{"description":"Not authenticated"},"403":{"description":"No owner/admin access or invalid CSRF token"},"429":{"description":"Per-hub token limit reached"}},"security":[{"SessionCookie":[]}],"summary":"Create hub API token","tags":["hub-admin"]}},"/api/hubs/{hub_id}/tokens/{token_id}":{"delete":{"description":"Revokes an API token immediately. Requires a hub owner/admin session cookie plus a valid CSRF token.","operationId":"revokeHubApiToken","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"b1c2d3e4-...","in":"path","name":"token_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"},"401":{"description":"Not authenticated"},"403":{"description":"No owner/admin access or invalid CSRF token"},"404":{"description":"Token not found"}},"security":[{"SessionCookie":[]}],"summary":"Revoke hub API token","tags":["hub-admin"]}},"/api/hubs/{hub_id}/webhooks":{"get":{"description":"Lists the hub's outbound webhook configurations. Signing secrets are masked and never returned in plain text. Accessible via session cookie or Bearer token with `hub:webhook:read`.","operationId":"listHubWebhooks","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubWebhookListResponse"}}},"description":"Success"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:webhook:read` scope"}},"security":[{"HubBearerToken":[]}],"summary":"List webhooks","tags":["hub-admin"]},"post":{"description":"Creates an outbound webhook. The signing `secret` is returned ONLY in this response and is never retrievable again. Requires `hub:webhook:write`.","operationId":"createHubWebhook","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubWebhookCreateRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubWebhookCreateResponse"}}},"description":"Webhook created"},"400":{"description":"Invalid URL or events payload"},"401":{"description":"Missing or invalid Bearer token"},"403":{"description":"Token missing `hub:webhook:write` scope"},"429":{"description":"Per-hub webhook limit reached"}},"security":[{"HubBearerToken":[]}],"summary":"Create webhook","tags":["hub-admin"]}},"/api/hubs/{hub_id}/webhooks/{webhook_id}":{"delete":{"description":"Deletes a webhook and its delivery logs. Requires `hub:webhook:write`. Session callers are additionally 2FA-gated; Bearer-token callers are authenticated via their scoped token.","operationId":"deleteHubWebhook","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"wh_ab12cd34ef56gh78ij90","in":"path","name":"webhook_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"},"403":{"description":"Token missing `hub:webhook:write` scope, or 2FA required (session)"},"404":{"description":"Webhook not found"}},"security":[{"HubBearerToken":[]}],"summary":"Delete webhook","tags":["hub-admin"]},"patch":{"description":"Updates webhook url/events/enabled/description. Requires `hub:webhook:write`.","operationId":"updateHubWebhook","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"wh_ab12cd34ef56gh78ij90","in":"path","name":"webhook_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubWebhookUpdateRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"},"400":{"description":"No or invalid changes"},"403":{"description":"Token missing `hub:webhook:write` scope"},"404":{"description":"Webhook not found"}},"security":[{"HubBearerToken":[]}],"summary":"Update webhook","tags":["hub-admin"]}},"/api/hubs/{hub_id}/webhooks/{webhook_id}/deliveries":{"get":{"description":"Lists recent delivery attempts for a webhook. Requires `hub:webhook:read`.","operationId":"listHubWebhookDeliveries","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"wh_ab12cd34ef56gh78ij90","in":"path","name":"webhook_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubWebhookDeliveriesResponse"}}},"description":"Success"},"403":{"description":"Token missing `hub:webhook:read` scope"},"404":{"description":"Webhook not found"}},"security":[{"HubBearerToken":[]}],"summary":"List webhook deliveries","tags":["hub-admin"]}},"/api/hubs/{hub_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry":{"post":{"description":"Re-queues a failed delivery attempt. Requires `hub:webhook:write`.","operationId":"retryHubWebhookDelivery","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"wh_ab12cd34ef56gh78ij90","in":"path","name":"webhook_id","required":true,"schema":{"type":"string"}},{"example":"whd_123","in":"path","name":"delivery_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}},"description":"Success"},"403":{"description":"Token missing `hub:webhook:write` scope"},"404":{"description":"Webhook or delivery not found"},"409":{"description":"Delivery already succeeded"}},"security":[{"HubBearerToken":[]}],"summary":"Retry a webhook delivery","tags":["hub-admin"]}},"/api/hubs/{hub_id}/webhooks/{webhook_id}/rotate-secret":{"post":{"description":"Generates a new signing secret and returns it ONCE in the response. Requires `hub:webhook:write`. Session callers are additionally 2FA-gated.","operationId":"rotateHubWebhookSecret","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"wh_ab12cd34ef56gh78ij90","in":"path","name":"webhook_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubWebhookRotateSecretResponse"}}},"description":"Success"},"403":{"description":"Token missing `hub:webhook:write` scope, or 2FA required (session)"},"404":{"description":"Webhook not found"}},"security":[{"HubBearerToken":[]}],"summary":"Rotate webhook signing secret","tags":["hub-admin"]}},"/api/hubs/{hub_id}/webhooks/{webhook_id}/test":{"post":{"description":"Synchronously sends a test payload to the webhook. Requires `hub:webhook:write`.","operationId":"testHubWebhook","parameters":[{"example":"hub_platform_home","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}},{"example":"wh_ab12cd34ef56gh78ij90","in":"path","name":"webhook_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubWebhookTestResponse"}}},"description":"Success"},"403":{"description":"Token missing `hub:webhook:write` scope"},"404":{"description":"Webhook not found"}},"security":[{"HubBearerToken":[]}],"summary":"Send test delivery","tags":["hub-admin"]}},"/api/status/incidents":{"get":{"description":"Returns all incidents from `incidents.json`. Used as a fallback source when the primary monitoring collector is unavailable. Also drives the uptime bars on the status page.","operationId":"getIncidents","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentsResponse"}}},"description":"Incident list"}},"security":[],"summary":"Incidents list","tags":["monitoring"]}},"/api/status/services":{"get":{"description":"Returns real-time status of all platform services. Results are cached for 30 seconds. `monitoring_ok: false` indicates at least one external check failed (partial data state).","operationId":"getServiceHealth","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatusResponse"}}},"description":"Service status list"}},"security":[],"summary":"Live service health (cached 30 s)","tags":["monitoring"]}},"/api/status/uptime":{"get":{"description":"Returns a status entry for each of the last 30 days. Days before app start are marked `unknown`. Days matching entries in `incidents.json` are marked `degraded`. Always returns exactly 30 entries in chronological ascending order.","operationId":"getUptimeHistory","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeResponse"}}},"description":"30-day uptime history array"}},"security":[],"summary":"30-day uptime history","tags":["monitoring"]}},"/api/v1/hubs/packages":{"get":{"description":"Versioned canonical path for `GET /api/hubs/packages`. Returns the list of available hub subscription packages/tiers. No authentication required.","operationId":"v1ListHubPackages","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"ok":{"example":true,"type":"boolean"},"packages":{"items":{"type":"object"},"type":"array"}},"required":["ok","packages"],"type":"object"}}},"description":"Package list"}},"security":[],"summary":"List available hub packages (v1)","tags":["public-hubs"]}},"/api/v1/hubs/public":{"get":{"description":"Versioned canonical path for `GET /api/hubs/public`. Returns all hubs with status `active`, including public branding fields. No authentication required. Rate-limited to 30 req/min.","operationId":"v1ListPublicHubs","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubListResponse"}}},"description":"List of active hubs"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[],"summary":"List active hubs (v1)","tags":["public-hubs"]}},"/api/v1/hubs/{hub_id}":{"get":{"description":"Versioned canonical path for `GET /api/hubs/{hub_id}`. Returns hub details. Public fields are returned without authentication. Sensitive fields are only included when authenticated as a hub admin or owner. Rate-limited to 30 req/min.","operationId":"v1GetHub","parameters":[{"description":"Unique hub identifier","example":"hub_abc123","in":"path","name":"hub_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HubDetailResponse"}}},"description":"Hub data (field set varies by authentication level)"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"SessionCookie":[]}],"summary":"Hub details (v1)","tags":["public-hubs"]}},"/api/v1/status/incidents":{"get":{"description":"Versioned canonical path for `GET /api/status/incidents`. Returns all incidents from `incidents.json`.","operationId":"v1GetIncidents","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentsResponse"}}},"description":"Incident list"}},"security":[],"summary":"Incidents list (v1)","tags":["monitoring"]}},"/api/v1/status/services":{"get":{"description":"Versioned canonical path for `GET /api/status/services`. Returns real-time status of all platform services. Results are cached for 30 seconds.","operationId":"v1GetServiceHealth","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatusResponse"}}},"description":"Service status list"}},"security":[],"summary":"Live service health (v1, cached 30 s)","tags":["monitoring"]}},"/api/v1/status/uptime":{"get":{"description":"Versioned canonical path for `GET /api/status/uptime`. Returns a status entry for each of the last 30 days. Always returns exactly 30 entries in chronological ascending order.","operationId":"v1GetUptimeHistory","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeResponse"}}},"description":"30-day uptime history array"}},"security":[],"summary":"30-day uptime history (v1)","tags":["monitoring"]}},"/backendserver/validateApiKey":{"post":{"description":"Checks whether an API key is valid and active. Returns the `kunde_uuid` of the associated account and the assigned scopes on success.\n\nOptionally pass `required_scope` to enforce a minimum scope \u2014 the endpoint rejects the key if it does not have the required scope (unless it has `full-access`).\n\n**Important:** Call this endpoint server-side only. Never expose API keys in browser code. Rate-limited to 20 req/min.\n\n**Edge case:** `kunde_uuid` returned here is the permanent account UUID, not a session token. Endpoints such as `/backendserver/getInstanceUserPackage` expect a valid session token in the `kunde_uuid` field \u2014 those flows require the user to authenticate via the normal login flow first.","operationId":"validateApiKey","requestBody":{"content":{"application/json":{"examples":{"basic":{"summary":"Validate key (no scope check)","value":{"api_key":"dlr_live_xxxxxxxxxxxx"}},"with_scope":{"summary":"Validate key with required scope","value":{"api_key":"dlr_live_xxxxxxxxxxxx","required_scope":"billing-read"}}},"schema":{"$ref":"#/components/schemas/ValidateApiKeyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"insufficient_scope":{"summary":"Key exists but scope insufficient","value":{"control":false,"error":"Insufficient scope"}},"invalid":{"summary":"Invalid or revoked key","value":{"control":false}},"valid":{"summary":"Valid key","value":{"control":true,"kunde_uuid":"<permanent-account-uuid>","scopes":["billing-read"]}}},"schema":{"$ref":"#/components/schemas/ValidateApiKeyResponse"}}},"description":"Validation result"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"ApiKeyHeader":[]}],"summary":"Validate an API key (server-to-server only)","tags":["backend-proxy"]}},"/backendserver/{path}":{"delete":{"description":"Forwards DELETE requests. **Non-idempotent \u2014 never automatically retried.** Rate-limited to 30 req/min.","operationId":"backendProxyDelete","parameters":[{"$ref":"#/components/parameters/backendPath"}],"responses":{"200":{"description":"Upstream response forwarded as-is"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"$ref":"#/components/responses/ProxyNetworkError"},"504":{"$ref":"#/components/responses/ProxyTimeout"}},"security":[{"ApiKeyHeader":[]}],"summary":"Backend proxy \u2014 DELETE","tags":["backend-proxy"]},"get":{"description":"Forwards GET requests to the auth/panel backend. Idempotent \u2014 eligible for up to 3 automatic retries on timeout or network error. Rate-limited to 30 req/min.","operationId":"backendProxyGet","parameters":[{"$ref":"#/components/parameters/backendPath"}],"responses":{"200":{"description":"Upstream response forwarded as-is"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"$ref":"#/components/responses/ProxyNetworkError"},"504":{"$ref":"#/components/responses/ProxyTimeout"}},"security":[{"ApiKeyHeader":[]}],"summary":"Backend proxy \u2014 GET","tags":["backend-proxy"]},"patch":{"description":"Forwards PATCH requests. **Non-idempotent \u2014 never automatically retried.** Rate-limited to 30 req/min.","operationId":"backendProxyPatch","parameters":[{"$ref":"#/components/parameters/backendPath"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":false},"responses":{"200":{"description":"Upstream response forwarded as-is"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"$ref":"#/components/responses/ProxyNetworkError"},"504":{"$ref":"#/components/responses/ProxyTimeout"}},"security":[{"ApiKeyHeader":[]}],"summary":"Backend proxy \u2014 PATCH","tags":["backend-proxy"]},"post":{"description":"Forwards POST requests to the auth/panel backend. **Non-idempotent \u2014 never automatically retried.** `retryable: false` is always returned on error. Rate-limited to 30 req/min.","operationId":"backendProxyPost","parameters":[{"$ref":"#/components/parameters/backendPath"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":false},"responses":{"200":{"description":"Upstream response forwarded as-is"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"$ref":"#/components/responses/ProxyNetworkError"},"504":{"$ref":"#/components/responses/ProxyTimeout"}},"security":[{"ApiKeyHeader":[]}],"summary":"Backend proxy \u2014 POST","tags":["backend-proxy"]},"put":{"description":"Forwards PUT requests. **Non-idempotent \u2014 never automatically retried.** Rate-limited to 30 req/min.","operationId":"backendProxyPut","parameters":[{"$ref":"#/components/parameters/backendPath"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":false},"responses":{"200":{"description":"Upstream response forwarded as-is"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"$ref":"#/components/responses/ProxyNetworkError"},"504":{"$ref":"#/components/responses/ProxyTimeout"}},"security":[{"ApiKeyHeader":[]}],"summary":"Backend proxy \u2014 PUT","tags":["backend-proxy"]}},"/health":{"get":{"description":"Returns 200 as long as the process is running. No authentication required. Suitable for load-balancer health probes.","operationId":"getHealth","responses":{"200":{"content":{"application/json":{"example":{"status":"ok"},"schema":{"$ref":"#/components/schemas/HealthResponse"}}},"description":"Service is up"}},"security":[],"summary":"Liveness check","tags":["monitoring"]}},"/{slug}/api/config":{"get":{"description":"Returns the public configuration for an instance (theme, name, available features). No authentication required. Rate-limited to 30 req/min.","operationId":"getInstanceConfig","parameters":[{"$ref":"#/components/parameters/slug"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceConfigResponse"}}},"description":"Public instance configuration"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[],"summary":"Instance public configuration","tags":["public-instances"]}},"/{slug}/api/packages":{"get":{"description":"Returns available packages for a specific instance (e.g. `/game_hoster/api/packages`). No authentication required. Rate-limited to 30 req/min.","operationId":"getInstancePackages","parameters":[{"$ref":"#/components/parameters/slug"}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"type":"object"},"type":"array"}}},"description":"Package list for the instance"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[],"summary":"Instance packages","tags":["public-instances"]}}},"servers":[{"description":"Current instance","url":"/"}],"tags":[{"description":"Health checks and service status endpoints (no auth required)","name":"monitoring"},{"description":"Publicly readable hub information \u2014 no authentication required","name":"public-hubs"},{"description":"Publicly readable instance (slug-based) data \u2014 no authentication required","name":"public-instances"},{"description":"Server-to-server backend proxy at `/backendserver/*`. **Not for browser use.** Requires `X-API-Key` header. Global rate limit: 30 req/min. `validateApiKey`: 20 req/min. Only GET/HEAD/OPTIONS are automatically retried (up to 3 attempts) on timeout/network error. POST/PUT/PATCH/DELETE are never automatically retried.","name":"backend-proxy"},{"description":"Tenant-scoped Hub Admin REST endpoints secured by Hub Bearer token scopes.","name":"hub-admin"}]}
