{"openapi":"3.0.0","paths":{"/api":{"get":{"description":"Returns a simple greeting message to verify that the API service is up and running.","operationId":"getData","parameters":[],"responses":{"200":{"description":"Service is running"}},"summary":"Health check","tags":["Health"]}},"/api/auth/login":{"post":{"description":"Exchange a Fusion Session ID for an application JWT access token.","operationId":"login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}}},"responses":{"201":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"401":{"description":"Unauthorized"}},"summary":"Login with Fusion Session ID","tags":["Auth"]}},"/api/auth/login-credentials":{"post":{"description":"Authenticate using email and password to receive a JWT access token.","operationId":"loginWithCredentials","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginCredentials"}}}},"responses":{"201":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}}},"summary":"Login with credentials","tags":["Auth"]}},"/api/auth/me":{"get":{"description":"Retrieve details of the currently authenticated user based on the JWT token.","operationId":"getProfile","parameters":[],"responses":{"200":{"description":"User profile retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfile"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}],"summary":"Get current user profile","tags":["Auth"]}},"/api/projects/{projectId}/sessions":{"post":{"description":"Create a new session entity. A session tracks audio transcription and analysis for a room. By default, the bot is started automatically (set autoStart to false to disable).","operationId":"createSession","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSessionRequest"}}}},"responses":{"201":{"description":"Session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}},"400":{"description":"Project settings not configured"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Create a new session","tags":["Sessions"]},"get":{"description":"Retrieve a list of all sessions for the current tenant.","operationId":"listSessions","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"List of sessions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SessionResponse"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List all sessions","tags":["Sessions"]}},"/api/projects/{projectId}/sessions/{id}/start":{"post":{"description":"Command the transcription bot to join the associated ODIN room and start processing.","operationId":"startSession","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Session ID","schema":{"type":"string"}}],"responses":{"201":{"description":"Bot start command sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartSessionResponse"}}}},"400":{"description":"Project settings not configured"},"404":{"description":"Session not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Start a session (bot)","tags":["Sessions"]}},"/api/projects/{projectId}/sessions/{id}/stop":{"post":{"description":"Command the transcription bot to leave the ODIN room and stop processing.","operationId":"stopSession","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Session ID","schema":{"type":"string"}}],"responses":{"201":{"description":"Bot stop command sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopSessionResponse"}}}},"404":{"description":"Session not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Stop a session (bot)","tags":["Sessions"]}},"/api/projects/{projectId}/sessions/{id}":{"get":{"description":"Retrieve detailed information about a specific session.","operationId":"getSession","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Session ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Session details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}},"404":{"description":"Session not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get a session by ID","tags":["Sessions"]}},"/api/projects/{projectId}/sessions/{id}/actions":{"get":{"description":"Returns all plugin actions available for this session, grouped by plugin.","operationId":"getSessionActions","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Session ID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of available actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionActionsResponse"}}}},"404":{"description":"Session not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get available actions for a session","tags":["Sessions"]}},"/api/projects/{projectId}/sessions/{id}/regenerate-summary":{"post":{"description":"Delete existing summary and trigger the session-summary plugin to generate a new one with current settings.","operationId":"regenerateSummary","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Session ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Summary regeneration triggered"},"404":{"description":"Session not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Regenerate session summary","tags":["Sessions"]}},"/api/projects/{projectId}/sessions/{id}/messages":{"get":{"description":"Retrieve the complete message history (transcript) for a session.","operationId":"getMessages","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Session ID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of messages","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Message"}}}}},"404":{"description":"Session not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get messages for a session","tags":["Messages"]}},"/api/projects/{projectId}/sessions/{id}/messages/{messageId}/debug-audio":{"get":{"description":"Download the WAV file that was sent to the transcription API for this message. Only available when debug audio is enabled and within the 24-hour retention window.","operationId":"downloadDebugAudio","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Session ID","schema":{"type":"string"}},{"name":"messageId","required":true,"in":"path","description":"Message ID","schema":{"type":"string"}}],"responses":{"200":{"description":"WAV audio file"},"404":{"description":"Debug audio not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Download debug audio for a message","tags":["Messages"]}},"/api/projects/{projectId}/webhooks/subscriptions":{"post":{"description":"Register a new webhook endpoint. You can specify which events to listen to and authentication details for the callback.","operationId":"createSubscription","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookSubscriptionRequest"}}}},"responses":{"201":{"description":"Subscription created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Create a webhook subscription","tags":["Webhooks"]},"get":{"description":"Retrieve a list of all webhook subscriptions configured for this tenant, optionally filtered by project.","operationId":"listSubscriptions","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"List of subscriptions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookSubscription"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List webhook subscriptions","tags":["Webhooks"]}},"/api/projects/{projectId}/webhooks/events":{"get":{"description":"Retrieve a paginated log of events that were processed by the webhook system.","operationId":"listEvents","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by delivery status","schema":{"enum":["pending","delivered","failed"],"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Items to return","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"type":"number"}}],"responses":{"200":{"description":"List of webhook events","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List webhook events","tags":["Webhooks"]}},"/api/projects/{projectId}/webhooks/events/{id}":{"get":{"description":"Retrieve details of a specific webhook event, including the payload and a list of delivery attempts.","operationId":"getEvent","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Event ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEventDetail"}}}},"404":{"description":"Event not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get webhook event details with deliveries","tags":["Webhooks"]}},"/api/projects/{projectId}/webhooks/subscriptions/{id}":{"get":{"description":"Retrieve details of a specific webhook subscription.","operationId":"getSubscription","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Subscription ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Subscription details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}}},"404":{"description":"Subscription not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get a webhook subscription by ID","tags":["Webhooks"]},"put":{"description":"Update the configuration of an existing webhook subscription.","operationId":"updateSubscription","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Subscription ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookSubscriptionRequest"}}}},"responses":{"200":{"description":"Subscription updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}}},"404":{"description":"Subscription not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update a webhook subscription","tags":["Webhooks"]},"delete":{"description":"Permanently remove a webhook subscription.","operationId":"deleteSubscription","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Subscription ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Subscription deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteWebhookSubscriptionResponse"}}}},"404":{"description":"Subscription not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Delete a webhook subscription","tags":["Webhooks"]}},"/api/plugins":{"get":{"description":"Retrieve a list of all plugins available in the system catalog.","operationId":"listPlugins","parameters":[],"responses":{"200":{"description":"List of available plugins","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Plugin"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List available plugins","tags":["Plugins"]}},"/api/plugins/{slug}":{"get":{"description":"Retrieve detailed information about a specific plugin from the catalog.","operationId":"getPlugin","parameters":[{"name":"slug","required":true,"in":"path","description":"Plugin slug (e.g., profanity-filter)","schema":{"type":"string"}}],"responses":{"200":{"description":"Plugin details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Plugin"}}}},"404":{"description":"Plugin not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get plugin by slug","tags":["Plugins"]}},"/api/plugins/annotations/sessions/{sessionId}":{"get":{"description":"Retrieve a list of annotations created by plugins for a specific session.","operationId":"getSessionAnnotations","parameters":[{"name":"sessionId","required":true,"in":"path","description":"Session ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Session annotations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SessionAnnotation"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get session annotations","tags":["Plugins"]}},"/api/plugins/annotations/messages/batch":{"post":{"description":"Batch retrieve annotations for a set of messages, grouped by message ID.","operationId":"getMessageAnnotationsBatch","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"messageIds":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Message annotations grouped by message ID","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/MessageAnnotation"}}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get annotations for multiple messages","tags":["Plugins"]}},"/api/projects/{projectId}/plugins/instances":{"get":{"description":"Retrieve a list of all installed plugins (instances) for the specified project.","operationId":"listInstances","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"List of plugin instances","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PluginInstanceWithPlugin"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List installed plugin instances","tags":["Plugin Instances"]},"post":{"description":"Create a new instance of a plugin, configuring it for the specified project.","operationId":"createInstance","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePluginInstanceRequest"}}}},"responses":{"201":{"description":"Plugin installed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PluginInstance"}}}},"400":{"description":"Invalid request"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Install a plugin","tags":["Plugin Instances"]}},"/api/projects/{projectId}/plugins/instances/{id}":{"get":{"description":"Retrieve details of a specific plugin installation.","operationId":"getInstance","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Instance ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Plugin instance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PluginInstanceWithPlugin"}}}},"404":{"description":"Instance not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get plugin instance","tags":["Plugin Instances"]},"put":{"description":"Update settings or enable/disable a specific plugin instance.","operationId":"updateInstance","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Instance ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePluginInstanceRequest"}}}},"responses":{"200":{"description":"Instance updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PluginInstance"}}}},"404":{"description":"Instance not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update plugin instance","tags":["Plugin Instances"]},"delete":{"description":"Permanently remove a plugin instance.","operationId":"deleteInstance","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Instance ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Plugin uninstalled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletePluginInstanceResponse"}}}},"404":{"description":"Instance not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Uninstall a plugin","tags":["Plugin Instances"]}},"/api/api-keys":{"get":{"description":"Retrieve a list of all active API keys, including metadata like last used date and scopes.","operationId":"listKeys","parameters":[],"responses":{"200":{"description":"List of API keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}}}}}},"security":[{"bearer":[]}],"summary":"List all API keys for the tenant","tags":["API Keys"]},"post":{"description":"Generate a new API key with specified scopes. The secret key is only returned in the response and cannot be retrieved later.","operationId":"createKey","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKey"}}}},"responses":{"201":{"description":"API key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}}},"security":[{"bearer":[]}],"summary":"Create a new API key","tags":["API Keys"]}},"/api/api-keys/{id}":{"delete":{"description":"Permanently revoke an API key. It will essentially be deleted and cannot be used anymore.","operationId":"revokeKey","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"API key revoked"},"404":{"description":"API key not found"}},"security":[{"bearer":[]}],"summary":"Revoke an API key","tags":["API Keys"]}},"/api/api-keys/scopes":{"get":{"description":"List all valid permission scopes for API keys.","operationId":"getScopes","parameters":[],"responses":{"200":{"description":"List of available scopes"}},"security":[{"bearer":[]}],"summary":"Get available API key scopes","tags":["API Keys"]}},"/api/projects":{"get":{"description":"Retrieve a list of apps/projects associated with the current user account, including projects shared via invitation.","operationId":"listApps","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/App"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List available apps (projects)","tags":["Projects"]}},"/api/projects/{projectId}/users":{"get":{"description":"Retrieve the list of users associated with a project, including their roles and invitation status.","operationId":"getProjectUsers","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of project users","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectUser"}}}}},"401":{"description":"Session expired or invalid"},"403":{"description":"No access to this project"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get project users","tags":["Projects"]}},"/api/projects/{projectId}/users/invite":{"post":{"description":"Send an invitation to a user by email. They will be added with the specified role.","operationId":"inviteProjectUser","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteProjectUserRequest"}}}},"responses":{"201":{"description":"User invited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUser"}}}},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Invite a user to a project","tags":["Projects"]}},"/api/projects/{projectId}/users/remove":{"post":{"description":"Revoke a user's access to the project by their permission ID.","operationId":"removeProjectUser","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveProjectUserRequest"}}}},"responses":{"201":{"description":"User removed"},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Remove a user from a project","tags":["Projects"]}},"/api/projects/{projectId}/users/change-role":{"post":{"description":"Update the role assigned to a project member.","operationId":"changeProjectUserRole","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeProjectUserRoleRequest"}}}},"responses":{"201":{"description":"Role updated"},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Change a project member's role","tags":["Projects"]}},"/api/projects/token":{"post":{"description":"Generate a short-lived access token for a specific room and project context.","operationId":"generateTokenLegacy","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateTokenRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateTokenResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Generate access token","tags":["Projects"]}},"/api/projects/{projectId}/settings":{"get":{"description":"Retrieve configuration settings for a specific project.","operationId":"getAppSettings","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Project settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"404":{"description":"Settings not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get project settings","tags":["App Settings"]},"put":{"description":"Save or update configuration settings for a specific project, including token provider details.","operationId":"upsertAppSettings","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAppSettingsRequest"}}}},"responses":{"200":{"description":"Settings saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Create or update project settings","tags":["App Settings"]},"patch":{"description":"Update only the provided settings fields; all others are preserved. Ideal for changing just the bot userData without re-sending the whole configuration.","operationId":"patchAppSettings","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAppSettingsRequest"}}}},"responses":{"200":{"description":"Settings updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Partially update project settings","tags":["App Settings"]},"delete":{"description":"Remove configuration settings for a specific project.","operationId":"deleteAppSettings","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Settings deleted"},"404":{"description":"Settings not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Delete project settings","tags":["App Settings"]}},"/api/projects/{projectId}/settings/secret":{"get":{"operationId":"getSecret","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Project secret value"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get the decrypted project secret","tags":["App Settings"]}},"/api/projects/{projectId}/settings/debug-audio":{"patch":{"description":"Enable or disable debug audio storage for transcription debugging. WAV files are auto-deleted after 24 hours.","operationId":"updateDebugAudio","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDebugAudioRequest"}}}},"responses":{"200":{"description":"Debug audio setting updated"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Toggle debug audio recording","tags":["App Settings"]}},"/api/projects/{projectId}/settings/e2e-encryption":{"patch":{"description":"Set how the bot derives the ODIN cipher password. Mode `manual` requires a password (on this call or already stored); `disabled` and `automatic` clear any stored password.","operationId":"updateE2EEncryption","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateE2EEncryptionRequest"}}}},"responses":{"200":{"description":"E2E encryption setting updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update end-to-end encryption mode","tags":["App Settings"]}},"/api/projects/{projectId}/settings/sync-secret":{"post":{"operationId":"syncSecret","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Secret synced successfully"},"400":{"description":"No secret found in Payment system"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Sync project secret from Payment system","tags":["App Settings"]}},"/api/projects/{projectId}/settings/revoke-secret":{"delete":{"operationId":"revokeSecret","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Secret revoked successfully"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Revoke the locally cached project secret","tags":["App Settings"]}},"/api/events/stream":{"get":{"operationId":"stream","parameters":[{"name":"types","required":false,"in":"query","description":"Comma-separated list of event types (supports prefix wildcards like \"gathering.*\")","schema":{"type":"string"}},{"name":"resources","required":false,"in":"query","description":"Comma-separated list of resource IDs","schema":{"type":"string"}},{"name":"last-event-id","required":false,"in":"header","description":"Optional ID of the last event received for reconnection support","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Subscribe to real-time events via SSE (Tenant-wide)","tags":["Events"]}},"/api/projects/{projectId}/events/stream":{"get":{"operationId":"streamProject","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID to filter events by","schema":{"type":"string"}},{"name":"types","required":false,"in":"query","description":"Comma-separated list of event types (supports prefix wildcards like \"gathering.*\")","schema":{"type":"string"}},{"name":"resources","required":false,"in":"query","description":"Comma-separated list of resource IDs","schema":{"type":"string"}},{"name":"last-event-id","required":false,"in":"header","description":"Optional ID of the last event received for reconnection support","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Subscribe to real-time events via SSE (Project-scoped)","tags":["Events"]}},"/api/events/schema":{"get":{"description":"Discriminated union (by `type`) of every DomainEvent emitted on the SSE streams. Not a live endpoint — events are delivered via text/event-stream on the /stream routes.","operationId":"getEventSchema","parameters":[],"responses":{"200":{"description":"Union of every domain event envelope emitted on the SSE streams (discriminated by `type`).","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/SessionCreatedEvent"},{"$ref":"#/components/schemas/SessionUpdatedEvent"},{"$ref":"#/components/schemas/SessionDeletedEvent"},{"$ref":"#/components/schemas/MessageCreatedEvent"},{"$ref":"#/components/schemas/WebhookDeliveryUpdatedEvent"},{"$ref":"#/components/schemas/ParticipantCreatedEvent"},{"$ref":"#/components/schemas/ParticipantUpdatedEvent"},{"$ref":"#/components/schemas/ParticipantDeletedEvent"},{"$ref":"#/components/schemas/MessageAnnotationCreatedEvent"},{"$ref":"#/components/schemas/SessionAnnotationCreatedEvent"},{"$ref":"#/components/schemas/SanctionCreatedEvent"},{"$ref":"#/components/schemas/SanctionUpdatedEvent"},{"$ref":"#/components/schemas/SanctionRevokedEvent"},{"$ref":"#/components/schemas/GatheringCreatedEvent"},{"$ref":"#/components/schemas/GatheringUpdatedEvent"},{"$ref":"#/components/schemas/GatheringStartedEvent"},{"$ref":"#/components/schemas/GatheringEndedEvent"},{"$ref":"#/components/schemas/GatheringCancelledEvent"},{"$ref":"#/components/schemas/GatheringMemberJoinedEvent"},{"$ref":"#/components/schemas/GatheringMemberReadyEvent"},{"$ref":"#/components/schemas/GatheringMemberLeftEvent"},{"$ref":"#/components/schemas/GatheringInvitationSentEvent"},{"$ref":"#/components/schemas/GatheringInvitationAcceptedEvent"},{"$ref":"#/components/schemas/GatheringInvitationDeclinedEvent"},{"$ref":"#/components/schemas/GenericDomainEvent"}]}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Documentation-only: shape of real-time domain events","tags":["Events"]}},"/api/events/ingest":{"post":{"description":"Accepts domain events from trusted ODIN platform services (Voice server, Fleet) and publishes them into the Cortex event pipeline. Requires HMAC-SHA256 project secret authentication via X-Project-Id, X-Signature, and X-Timestamp headers.","operationId":"ingest","parameters":[{"name":"X-Timestamp","in":"header","description":"ISO 8601 timestamp of when the request was signed (must be within 5 minutes)","required":true,"schema":{"type":"string"}},{"name":"X-Signature","in":"header","description":"HMAC-SHA256 hex digest of {timestamp}{rawBody} using the shared project secret","required":true,"schema":{"type":"string"}},{"name":"X-Project-Id","in":"header","description":"The Payment project/app ID identifying the target project","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestEventDto"}}}},"responses":{"201":{"description":"Event accepted and published to the event bus","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The generated event UUID","example":"550e8400-e29b-41d4-a716-446655440000"}}}}}},"400":{"description":"Invalid request body (validation failed)"},"401":{"description":"Authentication failed (missing or invalid signature)"},"429":{"description":"Rate limit exceeded (max 100 events/s per project)"}},"summary":"Ingest an external domain event","tags":["Events"]}},"/api/projects/{projectId}/sanctions":{"post":{"description":"Apply a sanction (mute, kick, ban) to a user or participant. Define duration and reason for the action.","operationId":"createSanction","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSanctionRequest"}}}},"responses":{"201":{"description":"Sanction created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SanctionResponse"}}}},"400":{"description":"Invalid request (missing participant or user ID)"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Create a new sanction","tags":["Sanctions"]},"get":{"description":"Retrieve a log of all sanctions issued within the tenant, with optional filtering.","operationId":"listSanctions","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Filter by sanction type","schema":{"enum":["warn","mute","listen_only","text_only","rate_limit","shadow_mute","temp_ban","perm_ban","ranked_restriction","queue_delay","party_restriction","human_review"],"type":"string"}},{"name":"activeOnly","required":false,"in":"query","description":"Only return active sanctions","schema":{"example":true,"type":"boolean"}},{"name":"limit","required":false,"in":"query","description":"Pagination limit","schema":{"example":50,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Pagination offset","schema":{"example":0,"type":"number"}}],"responses":{"200":{"description":"List of sanctions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SanctionListResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List all sanctions","tags":["Sanctions"]}},"/api/projects/{projectId}/sanctions/{id}":{"get":{"description":"Retrieve details of a specific sanction record.","operationId":"getSanction","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Sanction ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Sanction details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SanctionResponse"}}}},"404":{"description":"Sanction not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get a sanction by ID","tags":["Sanctions"]},"patch":{"description":"Update the details of an active sanction.","operationId":"updateSanction","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Sanction ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSanctionRequest"}}}},"responses":{"200":{"description":"Sanction updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SanctionResponse"}}}},"404":{"description":"Sanction not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update a sanction","tags":["Sanctions"]}},"/api/projects/{projectId}/sanctions/{id}/revoke":{"post":{"description":"Prematurely end a sanction, effectively un-muting or un-banning the user.","operationId":"revokeSanction","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Sanction ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeSanctionRequest"}}}},"responses":{"200":{"description":"Sanction revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SanctionResponse"}}}},"404":{"description":"Sanction not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Revoke a sanction","tags":["Sanctions"]}},"/api/projects/{projectId}/sanctions/user/{externalUserId}":{"get":{"description":"Retrieve all sanctions (active and inactive) associated with a specific user ID.","operationId":"getSanctionsByUser","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"externalUserId","required":true,"in":"path","description":"External user ID from ODIN","schema":{"type":"string"}}],"responses":{"200":{"description":"List of sanctions for user","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SanctionResponse"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get sanctions for a user","tags":["Sanctions"]}},"/api/projects/{projectId}/sanctions/participant/{participantId}":{"get":{"description":"Retrieve all sanctions associated with a specific participant ID.","operationId":"getSanctionsByParticipant","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"participantId","required":true,"in":"path","description":"Participant ID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of sanctions for participant","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SanctionResponse"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get sanctions for a participant","tags":["Sanctions"]}},"/api/projects/{projectId}/sanctions/user/{externalUserId}/active":{"get":{"description":"Retrieve only the currently active sanctions for a user.","operationId":"getActiveSanctions","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"externalUserId","required":true,"in":"path","description":"External user ID from ODIN","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Filter by specific sanction type","schema":{"enum":["warn","mute","listen_only","text_only","rate_limit","shadow_mute","temp_ban","perm_ban","ranked_restriction","queue_delay","party_restriction","human_review"],"type":"string"}}],"responses":{"200":{"description":"List of active sanctions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SanctionResponse"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get active sanctions for a user","tags":["Sanctions"]}},"/api/projects/{projectId}/participants":{"get":{"description":"Retrieve a list of participants for a specific project. Supports pagination and search.","operationId":"listParticipants","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Pagination limit","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Pagination offset","schema":{"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search by display name or user ID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of participants","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParticipantListResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List participants","tags":["Participants"]},"post":{"description":"Create a new participant or retrieve an existing one based on projectId and externalUserId.","operationId":"createParticipant","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateParticipantRequest"}}}},"responses":{"201":{"description":"Participant created or found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParticipantResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Create or find a participant","tags":["Participants"]}},"/api/projects/{projectId}/participants/{id}":{"get":{"description":"Retrieve detailed information about a specific participant using their UUID.","operationId":"getParticipant","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Participant ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Participant details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParticipantResponse"}}}},"404":{"description":"Participant not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get a participant by ID","tags":["Participants"]},"patch":{"description":"Update display name or user data for an existing participant.","operationId":"updateParticipant","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Participant ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateParticipantRequest"}}}},"responses":{"200":{"description":"Participant updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParticipantResponse"}}}},"404":{"description":"Participant not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update a participant","tags":["Participants"]},"delete":{"description":"Delete a participant and all their associated history from the project.","operationId":"deleteParticipant","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Participant ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Participant deleted"},"404":{"description":"Participant not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Delete a participant","tags":["Participants"]}},"/api/projects/{projectId}/gatherings":{"post":{"description":"Create a new gathering with the provided metadata. The gathering will be in CREATED status initially.","operationId":"createGathering","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGatheringRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Create a new gathering","tags":["Gatherings"]},"get":{"description":"Retrieve a list of gatherings for the current tenant. Supports filtering by Project ID, Type, and Status.","operationId":"listGatherings","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Filter by gathering type","schema":{"enum":["lobby","appointment","open"],"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by gathering status","schema":{"enum":["pending","active","started","ended","cancelled","expired"],"type":"string"}},{"name":"listed","required":false,"in":"query","description":"Filter to only listed gatherings","schema":{"type":"boolean"}},{"name":"limit","required":false,"in":"query","description":"Number of items to return","schema":{"example":50,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Number of items to skip","schema":{"example":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringListResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List gatherings for the tenant","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/{id}":{"get":{"description":"Retrieve detailed information about a specific gathering using its UUID. Optionally include the list of members.","operationId":"getGathering","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}},{"name":"includeMembers","required":false,"in":"query","description":"If true, includes the list of members in the response","schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringResponse"}}}},"404":{"description":"Gathering not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get a gathering by ID","tags":["Gatherings"]},"patch":{"description":"Update the properties of an existing gathering. Only provided fields will be updated.","operationId":"updateGathering","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGatheringRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringResponse"}}}},"404":{"description":"Gathering not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update a gathering","tags":["Gatherings"]},"delete":{"description":"Permanently cancel a gathering. This action may notify invited members.","operationId":"cancelGathering","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringResponse"}}}},"404":{"description":"Gathering not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Cancel a gathering","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/{id}/start":{"post":{"description":"Transitions the gathering state to STARTED. If a roomId is provided, it associates the gathering with that active room.","operationId":"startGathering","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartGatheringRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringResponse"}}}},"404":{"description":"Gathering not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Start a gathering","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/{id}/end":{"post":{"description":"Transitions the gathering state to ENDED. This signifies the gathering is over.","operationId":"endGathering","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringResponse"}}}},"404":{"description":"Gathering not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"End a gathering","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/join":{"post":{"description":"Allows a participant to join a gathering using an 8-character join code.","operationId":"joinByCode","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project UUID","schema":{}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinGatheringRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinGatheringResponse"}}}},"404":{"description":"Invalid join code"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Join a gathering by code","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/lookup/{joinCode}":{"get":{"description":"Retrieves gathering details using its join code, without actually joining it. Useful for preview screens.","operationId":"lookupByCode","parameters":[{"name":"joinCode","required":true,"in":"path","description":"8-character join code","schema":{"type":"string"}},{"name":"projectId","required":true,"in":"path","description":"Project UUID","schema":{}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringResponse"}}}},"404":{"description":"Gathering not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Look up a gathering by join code","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/{id}/members":{"post":{"description":"Manually add a participant to a gathering.","operationId":"addMember","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddMemberRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringMember"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Add a member to a gathering","tags":["Gatherings"]},"get":{"description":"Retrieve all members currently part of the gathering.","operationId":"listMembers","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GatheringMember"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List members of a gathering","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/{id}/members/{memberId}":{"patch":{"description":"Update the status or properties of a specific member within the gathering.","operationId":"updateMember","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}},{"name":"memberId","required":true,"in":"path","description":"Member UUID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatheringMember"}}}},"404":{"description":"Member not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update a member","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/{id}/members/{participantId}":{"delete":{"description":"Remove a participant from the gathering.","operationId":"removeMember","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}},{"name":"participantId","required":true,"in":"path","description":"Participant UUID","schema":{"type":"string"}}],"responses":{"204":{"description":""},"404":{"description":"Member not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Remove a member from a gathering","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/{id}/invite":{"post":{"description":"Send invitations to multiple participants at once. Generates invitation records.","operationId":"sendInvitations","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendInvitationsRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InvitationResponse"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Send invitations to a gathering","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/{id}/invitations":{"get":{"description":"Retrieve all invitation records for a specific gathering, regardless of status.","operationId":"listGatheringInvitations","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Gathering UUID","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InvitationResponse"}}}}},"404":{"description":"Gathering not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List invitations for a gathering","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/invitations/pending":{"get":{"description":"Retrieve all pending invitations for a specific participant.","operationId":"getPendingInvitations","parameters":[{"name":"participantId","required":true,"in":"query","description":"The participant UUID to check invitations for","schema":{"type":"string"}},{"name":"projectId","required":true,"in":"path","description":"Project UUID","schema":{}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InvitationResponse"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get pending invitations","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/invitations/{invitationId}/accept":{"post":{"description":"Accept an invitation, which adds the participant to the gathering and updates the invitation status.","operationId":"acceptInvitation","parameters":[{"name":"invitationId","required":true,"in":"path","description":"Invitation UUID","schema":{"type":"string"}},{"name":"projectId","required":true,"in":"path","description":"Project UUID","schema":{}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInvitationRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinGatheringResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Accept an invitation","tags":["Gatherings"]}},"/api/projects/{projectId}/gatherings/invitations/{invitationId}/decline":{"post":{"description":"Decline an invitation, marking it as DECLINED.","operationId":"declineInvitation","parameters":[{"name":"invitationId","required":true,"in":"path","description":"Invitation UUID","schema":{"type":"string"}},{"name":"projectId","required":true,"in":"path","description":"Project UUID","schema":{}}],"responses":{"204":{"description":""}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Decline an invitation","tags":["Gatherings"]}},"/api/projects/{projectId}/token":{"post":{"description":"Generate an access token for ODIN using the method configured in the project settings.","operationId":"generateProjectToken","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateProjectTokenRequest"}}}},"responses":{"201":{"description":"Token generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateTokenResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Generate ODIN Voice Token","tags":["Projects"]}},"/api/projects/{projectId}/functions/settings":{"get":{"description":"Retrieve Functions feature settings for the project.","operationId":"getSettings","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Function settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionSettings"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get function settings","tags":["Functions"]},"put":{"description":"Update Functions feature settings for the project.","operationId":"updateSettings","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFunctionSettingsRequest"}}}},"responses":{"200":{"description":"Settings updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionSettings"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update function settings","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/verify-credentials":{"post":{"description":"Check if stored Fleet credentials are valid for Functions activation.","operationId":"verifyFleetCredentials","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{}}],"responses":{"200":{"description":"Credentials verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyCredentialsResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Verify Fleet credentials","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/resource-packages":{"get":{"description":"Get available Fleet resource packages for function deployment.","operationId":"getResourcePackages","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{}}],"responses":{"200":{"description":"Resource packages list","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResourcePackage"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get resource packages","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/locations":{"get":{"description":"Get available Fleet deployment locations for function deployment.","operationId":"getDeploymentLocations","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{}}],"responses":{"200":{"description":"Locations list","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Location"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get deployment locations","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/activate":{"post":{"description":"Start Functions activation in the background. Poll GET /settings to track progress.","operationId":"activateFunctions","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateFunctionsRequest"}}}},"responses":{"201":{"description":"Activation started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateFunctionsResponse"}}}},"400":{"description":"Invalid request or already activating"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Activate Functions (async)","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/dependencies":{"put":{"description":"Update NPM package dependencies for all functions in the project. Changes trigger a runtime restart.","operationId":"updateDependencies","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDependenciesRequest"}}}},"responses":{"200":{"description":"Dependencies updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDependenciesResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update project dependencies","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/env-vars":{"put":{"description":"Update environment variables for all functions in the project. Secrets are encrypted at rest. Changes trigger a runtime restart.","operationId":"updateEnvVars","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvVarsRequest"}}}},"responses":{"200":{"description":"Environment variables updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvVarsResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update project environment variables","tags":["Functions"]}},"/api/projects/{projectId}/functions/npm-package/{packageName}":{"get":{"description":"Fetch available versions for an npm package. Used for dependency version selection.","operationId":"getNpmPackageInfo","parameters":[{"name":"packageName","required":true,"in":"path","description":"NPM package name (e.g. \"lodash\" or \"@scope/package\")","schema":{"type":"string"}},{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{}}],"responses":{"200":{"description":"Package version info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NpmPackageInfo"}}}},"404":{"description":"Package not found on npm"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Lookup npm package versions","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/runtime-status":{"get":{"description":"Get the status of the Functions runtime (Fleet deployment).","operationId":"getRuntimeStatus","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Runtime status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuntimeStatusResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get runtime status","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/runtime/start":{"post":{"description":"Start the Functions runtime (Fleet deployment servers).","operationId":"startRuntime","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Runtime started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRuntimeResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Start runtime","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/runtime/stop":{"post":{"description":"Stop the Functions runtime (Fleet deployment servers).","operationId":"stopRuntime","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Runtime stopped","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopRuntimeResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Stop runtime","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/runtime/restart":{"post":{"description":"Restart the Functions runtime (stops then starts all servers).","operationId":"restartRuntime","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Runtime restarting","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRuntimeResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Restart runtime","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/runtime/versions":{"get":{"description":"List the available function-runtime versions (with release notes and breaking flags) and the version this project is currently pinned to.","operationId":"getRuntimeVersions","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Runtime versions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuntimeVersionsResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List runtime versions","tags":["Functions"]}},"/api/projects/{projectId}/functions/settings/runtime/upgrade":{"post":{"description":"Pin the project to a specific runtime version: swaps the Fleet binary image and restarts the runtime so the new image is pulled.","operationId":"upgradeRuntime","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRuntimeRequest"}}}},"responses":{"200":{"description":"Runtime upgrading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuntimeStatusResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Upgrade runtime version","tags":["Functions"]}},"/api/projects/{projectId}/functions":{"get":{"description":"Retrieve all functions for the project.","operationId":"listFunctions","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of functions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Function"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List functions","tags":["Functions"]},"post":{"description":"Create a new serverless function.","operationId":"createFunction","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunctionRequest"}}}},"responses":{"201":{"description":"Function created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}}},"400":{"description":"Invalid request or limit exceeded"},"409":{"description":"Function with this slug already exists"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Create function","tags":["Functions"]}},"/api/projects/{projectId}/functions/{functionId}":{"get":{"description":"Retrieve a specific function by ID.","operationId":"getFunction","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}},{"name":"functionId","required":true,"in":"path","description":"Function ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Function details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}}},"404":{"description":"Function not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get function","tags":["Functions"]},"put":{"description":"Update function draft code and configuration.","operationId":"updateFunction","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}},{"name":"functionId","required":true,"in":"path","description":"Function ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFunctionRequest"}}}},"responses":{"200":{"description":"Function updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}}},"404":{"description":"Function not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update function","tags":["Functions"]},"delete":{"description":"Delete a function and all its versions and deployments.","operationId":"deleteFunction","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}},{"name":"functionId","required":true,"in":"path","description":"Function ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Function deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteFunctionResponse"}}}},"404":{"description":"Function not found"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Delete function","tags":["Functions"]}},"/api/projects/{projectId}/functions/{functionId}/versions":{"get":{"description":"Retrieve all published versions of a function.","operationId":"listVersions","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}},{"name":"functionId","required":true,"in":"path","description":"Function ID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of versions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FunctionVersion"}}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List function versions","tags":["Functions"]}},"/api/projects/{projectId}/functions/{functionId}/publish":{"post":{"description":"Publish the current draft as a new immutable version and deploy to the shared runtime.","operationId":"publishVersion","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}},{"name":"functionId","required":true,"in":"path","description":"Function ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishFunctionRequest"}}}},"responses":{"201":{"description":"Version published","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishFunctionResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Publish function version","tags":["Functions"]}},"/api/projects/{projectId}/functions/{functionId}/deploy":{"post":{"description":"Deploy the latest published version to Fleet.","operationId":"deployFunction","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}},{"name":"functionId","required":true,"in":"path","description":"Function ID","schema":{"type":"string"}}],"responses":{"201":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFunctionResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Deploy function","tags":["Functions"]}},"/api/projects/{projectId}/functions/{functionId}/stop":{"post":{"description":"Stop the active deployment of a function.","operationId":"stopDeployment","parameters":[{"name":"projectId","required":true,"in":"path","description":"Project ID","schema":{"type":"string"}},{"name":"functionId","required":true,"in":"path","description":"Function ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Function stopped","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopFunctionResponse"}}}}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Stop function","tags":["Functions"]}},"/api/projects/{projectId}/voice/settings":{"get":{"description":"Retrieve voice-specific settings for the project including peer limit, access key count, and permissions.","operationId":"getVoiceSettings","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Voice settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSettings"}}}},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get voice settings","tags":["Voice"]}},"/api/projects/{projectId}/voice/access-keys":{"get":{"description":"Retrieve all access keys for the project.","operationId":"listAccessKeys","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of access keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OdinAccessKey"}}}}},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"List access keys","tags":["Voice"]},"post":{"description":"Create a new access key. The response includes the one-time access key string.","operationId":"createAccessKey","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccessKeyRequest"}}}},"responses":{"201":{"description":"Access key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccessKeyResponse"}}}},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Create access key","tags":["Voice"]}},"/api/projects/{projectId}/voice/access-keys/{accessKeyId}":{"put":{"description":"Update the name and description of an existing access key.","operationId":"editAccessKey","parameters":[{"name":"accessKeyId","required":true,"in":"path","description":"The access key ID","schema":{"type":"string"}},{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditAccessKeyRequest"}}}},"responses":{"200":{"description":"Access key updated"},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Edit access key","tags":["Voice"]},"delete":{"description":"Permanently delete an access key.","operationId":"deleteAccessKey","parameters":[{"name":"accessKeyId","required":true,"in":"path","description":"The access key ID","schema":{"type":"string"}},{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{}}],"responses":{"200":{"description":"Access key deleted"},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Delete access key","tags":["Voice"]}},"/api/projects/{projectId}/voice/analytics":{"get":{"description":"Retrieve peak and average concurrent peers over time for chart rendering.","operationId":"getAnalytics","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}},{"name":"start","required":true,"in":"query","description":"Unix timestamp (seconds) for the start of the range","schema":{"type":"number"}}],"responses":{"200":{"description":"Peers over time data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeersOverTime"}}}},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get voice analytics","tags":["Voice"]}},"/api/projects/{projectId}/voice/rooms-analytics":{"get":{"description":"Retrieve peak and average active rooms over time for chart rendering.","operationId":"getRoomsAnalytics","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}},{"name":"start","required":true,"in":"query","description":"Unix timestamp (seconds) for the start of the range","schema":{"type":"number"}}],"responses":{"200":{"description":"Rooms over time data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomsOverTime"}}}},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Get rooms over time analytics","tags":["Voice"]}},"/api/projects/{projectId}/voice/peer-limit":{"put":{"description":"Set the maximum number of concurrent peers for the project. Use 0 for unlimited.","operationId":"updatePeerLimit","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePeerLimitRequest"}}}},"responses":{"200":{"description":"Peer limit updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSettings"}}}},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Update peer limit","tags":["Voice"]}},"/api/projects/{projectId}/voice/activate":{"post":{"description":"Activate the ODIN Voice API for this project. Required before access keys can be created.","operationId":"activateVoice","parameters":[{"name":"projectId","required":true,"in":"path","description":"The project ID","schema":{"type":"string"}}],"responses":{"201":{"description":"Voice activated"},"401":{"description":"Session expired or invalid"}},"security":[{"api-key":[]},{"bearer":[]}],"summary":"Activate ODIN Voice","tags":["Voice"]}}},"info":{"title":"ODIN Cortex API","description":"API for ODIN Cortex","version":"1.0","contact":{}},"tags":[{"name":"Auth","description":"Authentication endpoints"},{"name":"Sessions","description":"Session management endpoints"},{"name":"Messages","description":"Message retrieval endpoints"},{"name":"Webhooks","description":"Webhook subscription management"},{"name":"Health","description":"Health check endpoints"}],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"},"api-key":{"type":"apiKey","in":"header","name":"X-API-Key"}},"schemas":{"LoginRequest":{"type":"object","properties":{"fusionSessionId":{"type":"string","description":"Fusion Session ID for authentication","example":"fsid_1234567890"}},"required":["fusionSessionId"]},"LoginResponse":{"type":"object","properties":{"accessToken":{"type":"string","description":"JWT access token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."},"sessionId":{"type":"string","description":"Fusion Session ID for Fleet and Payment SDK authentication. Only returned from the credentials login flow.","example":"abc123def456"}},"required":["accessToken"]},"LoginCredentials":{"type":"object","properties":{"email":{"type":"string","description":"User email address","example":"user@example.com"},"password":{"type":"string","description":"User password","example":"password123","minLength":6}},"required":["email","password"]},"UserProfile":{"type":"object","properties":{"userId":{"type":"string","description":"User ID","example":"user_123"},"tenantId":{"type":"string","description":"Tenant ID","example":"tenant_456"},"username":{"type":"string","description":"User name","example":"John Doe"}},"required":["userId","tenantId","username"]},"CreateSessionRequest":{"type":"object","properties":{"title":{"type":"string","description":"Title of the session","example":"Daily Standup"},"externalRoomId":{"type":"string","description":"External Room ID","example":"room_abc123"},"gateway":{"type":"string","description":"ODIN Gateway URL","example":"gateway.odin.4players.io"},"idleTimeout":{"type":"number","description":"Idle timeout in seconds. If > 0, session auto-stops after this duration with no participants. 0 or omitted means no auto-stop.","example":300},"autoStart":{"type":"boolean","description":"Whether to automatically start the bot after session creation. Defaults to true when omitted; set to false to disable.","example":true}},"required":["title","externalRoomId"]},"SessionResponse":{"type":"object","properties":{"id":{"type":"string","description":"Session ID","example":"sess_789"},"tenantId":{"type":"string","description":"Tenant ID","example":"tenant_456"},"externalRoomId":{"type":"string","description":"External Room ID","example":"room_abc123"},"projectId":{"type":"string","description":"Project ID","example":"proj_123"},"gateway":{"type":"string","description":"ODIN Gateway URL","example":"gateway.odin.4players.io"},"title":{"type":"string","description":"Session Title","example":"Daily Standup"},"createdByUserId":{"type":"string","description":"ID of the user who created the session","example":"user_123"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp","example":"2023-10-01T10:00:00Z"},"status":{"type":"string","description":"Session Status","example":"active"},"idleTimeout":{"type":"number","description":"Idle timeout in seconds. 0 or null means no auto-stop.","example":300}},"required":["id","tenantId","externalRoomId","projectId","gateway","title","createdByUserId","createdAt","status"]},"StartSessionResponse":{"type":"object","properties":{"message":{"type":"string","description":"Status message","example":"Bot start command sent"}},"required":["message"]},"StopSessionResponse":{"type":"object","properties":{"message":{"type":"string","description":"Status message","example":"Bot stop command sent"}},"required":["message"]},"SessionAction":{"type":"object","properties":{"id":{"type":"string","description":"Action ID (unique within the plugin)","example":"generate-minutes"},"label":{"type":"string","description":"Human-readable action label","example":"Generate Minutes"},"icon":{"type":"string","description":"Heroicons icon name","example":"heroicons_outline:document-text"},"endpointPath":{"type":"string","description":"Endpoint path on the plugin, relative to the plugin slug","example":"minutes"},"method":{"type":"string","description":"HTTP method to invoke the action with","example":"POST"},"type":{"type":"string","description":"How the result is handled by the client","example":"download"}},"required":["id","label","endpointPath","method","type"]},"PluginActionGroup":{"type":"object","properties":{"pluginSlug":{"type":"string","description":"Plugin slug","example":"session-summary"},"pluginName":{"type":"string","description":"Plugin display name","example":"Session Summary"},"pluginIcon":{"type":"string","description":"Plugin icon (Heroicons name)"},"instanceId":{"type":"string","description":"Plugin instance ID"},"actions":{"description":"Available actions for this plugin","type":"array","items":{"$ref":"#/components/schemas/SessionAction"}}},"required":["pluginSlug","pluginName","instanceId","actions"]},"SessionActionsResponse":{"type":"object","properties":{"sessionId":{"type":"string","description":"Session ID the actions apply to"},"plugins":{"description":"Plugins (with their actions) available for this session","type":"array","items":{"$ref":"#/components/schemas/PluginActionGroup"}}},"required":["sessionId","plugins"]},"Message":{"type":"object","properties":{"id":{"type":"string","description":"Message ID","example":"msg_123"},"sessionId":{"type":"string","description":"Session ID","example":"sess_789"},"type":{"type":"string","description":"Message type: user (transcribed speech) or system (join/leave events)","enum":["user","system"],"default":"user","example":"user"},"senderName":{"type":"string","description":"Sender name (or [System] for system messages)","example":"Alice"},"content":{"type":"string","description":"Message content","example":"Hello team!"},"timestamp":{"format":"date-time","type":"string","description":"Timestamp","example":"2023-10-01T10:05:00Z"},"hasDebugAudio":{"type":"boolean","description":"Whether a debug audio WAV file is available for download","default":false}},"required":["id","sessionId","senderName","content","timestamp"]},"CreateWebhookSubscriptionRequest":{"type":"object","properties":{"url":{"type":"string","description":"Webhook URL","example":"https://example.com/webhook"},"secret":{"type":"string","description":"Secret for HMAC-SHA256 signature verification","example":"my_secret_key"},"events":{"description":"List of events to subscribe to. Supports wildcards like \"message.*\" or \"*\"","example":["session.created","message.*"],"type":"array","items":{"type":"string"}},"description":{"type":"string","description":"Description of this webhook","example":"Production webhook endpoint"},"authType":{"type":"string","description":"How Cortex authenticates when POSTing to your webhook URL. Defaults to 'none' if omitted.","enum":["none","api_key","basic_auth","custom_headers"]},"apiKey":{"type":"string","description":"API key value (for api_key auth)","example":"sk_live_xxx"},"apiKeyHeader":{"type":"string","description":"Header name to send the API key in (for api_key auth). Defaults to 'X-API-Key' if omitted.","example":"X-API-Key"},"basicAuthUsername":{"type":"string","description":"Basic auth username"},"basicAuthPassword":{"type":"string","description":"Basic auth password"},"customHeaders":{"type":"object","additionalProperties":{"type":"string"},"description":"Custom headers to send with webhook requests","example":{"X-Custom-Header":"value"}}},"required":["url","secret","events"]},"WebhookSubscription":{"type":"object","properties":{"id":{"type":"string","description":"Subscription ID"},"tenantId":{"type":"string","description":"Tenant ID"},"projectId":{"type":"string","description":"Project/App ID"},"url":{"type":"string","description":"Webhook URL"},"events":{"description":"Subscribed events","type":"array","items":{"type":"string"}},"isActive":{"type":"boolean","description":"Whether the subscription is active"},"description":{"type":"string","description":"Description"},"authType":{"type":"string","description":"Authentication type","enum":["none","api_key","basic_auth","custom_headers"]},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"updatedAt":{"format":"date-time","type":"string","description":"Last update timestamp"}},"required":["id","tenantId","projectId","url","events","isActive","authType","createdAt","updatedAt"]},"WebhookEvent":{"type":"object","properties":{"id":{"type":"string","description":"Event ID"},"tenantId":{"type":"string","description":"Tenant ID"},"projectId":{"type":"string","description":"Project/App ID"},"eventType":{"type":"string","description":"Event type","example":"message.created"},"payload":{"type":"object","additionalProperties":true,"description":"Event payload"},"status":{"type":"string","description":"Delivery status","enum":["pending","delivered","failed"]},"attemptsCount":{"type":"number","description":"Number of delivery attempts"},"lastError":{"type":"string","description":"Last error message"},"nextAttemptAt":{"format":"date-time","type":"string","description":"Next delivery attempt time"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"}},"required":["id","tenantId","eventType","payload","status","attemptsCount","nextAttemptAt","createdAt"]},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string","description":"Delivery ID"},"webhookEventId":{"type":"string","description":"Webhook Event ID"},"subscriptionId":{"type":"string","description":"Subscription ID"},"statusCode":{"type":"number","description":"HTTP status code"},"responseBody":{"type":"string","description":"Response body"},"responseHeaders":{"type":"object","additionalProperties":{"type":"string"},"description":"Response headers"},"requestBody":{"type":"string","description":"Request body sent"},"createdAt":{"format":"date-time","type":"string","description":"Delivery timestamp"}},"required":["id","webhookEventId","subscriptionId","createdAt"]},"WebhookEventDetail":{"type":"object","properties":{"id":{"type":"string","description":"Event ID"},"tenantId":{"type":"string","description":"Tenant ID"},"projectId":{"type":"string","description":"Project/App ID"},"eventType":{"type":"string","description":"Event type","example":"message.created"},"payload":{"type":"object","additionalProperties":true,"description":"Event payload"},"status":{"type":"string","description":"Delivery status","enum":["pending","delivered","failed"]},"attemptsCount":{"type":"number","description":"Number of delivery attempts"},"lastError":{"type":"string","description":"Last error message"},"nextAttemptAt":{"format":"date-time","type":"string","description":"Next delivery attempt time"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"deliveries":{"description":"Delivery attempts","type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}},"required":["id","tenantId","eventType","payload","status","attemptsCount","nextAttemptAt","createdAt","deliveries"]},"UpdateWebhookSubscriptionRequest":{"type":"object","properties":{"url":{"type":"string","description":"Webhook URL","example":"https://example.com/webhook"},"secret":{"type":"string","description":"Secret for HMAC-SHA256 signature verification"},"events":{"description":"List of events to subscribe to","type":"array","items":{"type":"string"}},"description":{"type":"string","description":"Description of this webhook"},"isActive":{"type":"boolean","description":"Whether the subscription is active"},"authType":{"type":"string","description":"Authentication type","enum":["none","api_key","basic_auth","custom_headers"]},"apiKey":{"type":"string","description":"API key value"},"apiKeyHeader":{"type":"string","description":"API key header name"},"basicAuthUsername":{"type":"string","description":"Basic auth username"},"basicAuthPassword":{"type":"string","description":"Basic auth password"},"customHeaders":{"type":"object","additionalProperties":{"type":"string"},"description":"Custom headers"}}},"DeleteWebhookSubscriptionResponse":{"type":"object","properties":{"message":{"type":"string","description":"Status message","example":"Subscription deleted"}},"required":["message"]},"MessageAnnotation":{"type":"object","properties":{"id":{"type":"string","description":"Annotation UUID"},"tenantId":{"type":"string","description":"Tenant ID"},"pluginInstanceId":{"type":"string","description":"Plugin instance that created this"},"type":{"type":"string","description":"Annotation type","enum":["profanity","summary","action_items","sentiment"]},"data":{"type":"object","additionalProperties":true,"description":"Annotation data"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"messageId":{"type":"string","description":"Message ID this annotation is attached to"}},"required":["id","tenantId","type","data","createdAt","messageId"]},"PluginSettingField":{"type":"object","properties":{"key":{"type":"string","description":"Unique key for this setting","example":"apiKey"},"type":{"type":"string","description":"Input type","enum":["text","number","email","select","boolean","password","chips"],"example":"password"},"label":{"type":"string","description":"Human-readable label","example":"OpenAI API Key"},"description":{"type":"string","description":"Help text","example":"Your API key from OpenAI dashboard"},"required":{"type":"boolean","description":"Whether this setting is required","default":false},"default":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"description":"Default value"},"options":{"description":"Options for select type","type":"array","items":{"type":"string"}},"validation":{"type":"object","properties":{"min":{"type":"number"},"max":{"type":"number"},"pattern":{"type":"string"}},"description":"Validation rules"}},"required":["key","type","label"]},"Plugin":{"type":"object","properties":{"id":{"type":"string","description":"Plugin UUID"},"slug":{"type":"string","description":"URL-friendly identifier","example":"profanity-filter"},"name":{"type":"string","description":"Display name","example":"Profanity Filter"},"description":{"type":"string","description":"Description"},"version":{"type":"string","description":"Semantic version","example":"1.0.0"},"category":{"type":"string","description":"Category","enum":["moderation","analytics","automation","integration"]},"events":{"description":"Event patterns","example":["message.created"],"type":"array","items":{"type":"string"}},"outputAnnotationType":{"type":"string","description":"Output annotation type","enum":["profanity","summary","action_items","sentiment"]},"settingsSchema":{"description":"Settings schema","type":"array","items":{"$ref":"#/components/schemas/PluginSettingField"}},"productSlug":{"type":"string","description":"Payment product slug this plugin activates (set = paid plugin). When present, installing/enabling the plugin activates this product and disabling/uninstalling deactivates it.","example":"amanda"},"pricingUrl":{"type":"string","description":"Pricing page URL for the tied Payment product, shown in the install cost-acceptance notice.","example":"https://odin.4players.io/pricing"},"icon":{"type":"string","description":"Heroicons icon name","example":"heroicons_outline:shield-check"},"isActive":{"type":"boolean","description":"Whether plugin is available"}},"required":["id","slug","name","version","category","events","isActive"]},"SessionAnnotation":{"type":"object","properties":{"id":{"type":"string","description":"Annotation UUID"},"tenantId":{"type":"string","description":"Tenant ID"},"pluginInstanceId":{"type":"string","description":"Plugin instance that created this"},"type":{"type":"string","description":"Annotation type","enum":["profanity","summary","action_items","sentiment"]},"data":{"type":"object","additionalProperties":true,"description":"Annotation data"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"sessionId":{"type":"string","description":"Session ID this annotation is attached to"}},"required":["id","tenantId","type","data","createdAt","sessionId"]},"PluginInstanceWithPlugin":{"type":"object","properties":{"id":{"type":"string","description":"Instance UUID"},"tenantId":{"type":"string","description":"Tenant ID"},"projectId":{"type":"string","description":"Project ID (null = all projects)"},"pluginId":{"type":"string","description":"Plugin ID"},"settings":{"type":"object","additionalProperties":true,"description":"User-configured settings"},"isEnabled":{"type":"boolean","description":"Whether this instance is enabled"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"updatedAt":{"format":"date-time","type":"string","description":"Last update timestamp"},"plugin":{"description":"Plugin definition","allOf":[{"$ref":"#/components/schemas/Plugin"}]}},"required":["id","tenantId","pluginId","settings","isEnabled","createdAt","updatedAt","plugin"]},"CreatePluginInstanceRequest":{"type":"object","properties":{"pluginId":{"type":"string","description":"Plugin ID to activate"},"settings":{"type":"object","additionalProperties":true,"description":"Initial settings"}},"required":["pluginId"]},"PluginInstance":{"type":"object","properties":{"id":{"type":"string","description":"Instance UUID"},"tenantId":{"type":"string","description":"Tenant ID"},"projectId":{"type":"string","description":"Project ID (null = all projects)"},"pluginId":{"type":"string","description":"Plugin ID"},"settings":{"type":"object","additionalProperties":true,"description":"User-configured settings"},"isEnabled":{"type":"boolean","description":"Whether this instance is enabled"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"updatedAt":{"format":"date-time","type":"string","description":"Last update timestamp"}},"required":["id","tenantId","pluginId","settings","isEnabled","createdAt","updatedAt"]},"UpdatePluginInstanceRequest":{"type":"object","properties":{"settings":{"type":"object","additionalProperties":true,"description":"Updated settings"},"isEnabled":{"type":"boolean","description":"Enable/disable the instance"}}},"DeletePluginInstanceResponse":{"type":"object","properties":{"message":{"type":"string","description":"Status message","example":"Plugin instance deleted"}},"required":["message"]},"ApiKeyResponse":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier"},"name":{"type":"string","description":"Key name"},"projectId":{"type":"string","description":"Project ID this key is scoped to (null = all projects)"},"keyPrefix":{"type":"string","description":"First characters of the key for identification","example":"ots_live_abc1..."},"scopes":{"description":"Scopes this key has access to","type":"array","items":{"type":"string"}},"lastUsedAt":{"format":"date-time","type":"string","description":"When the key was last used"},"expiresAt":{"format":"date-time","type":"string","description":"Expiration date"},"createdAt":{"format":"date-time","type":"string","description":"Creation date"}},"required":["id","name","keyPrefix","scopes","createdAt"]},"CreateApiKey":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable name for the key","example":"Aiba Webhook"},"scopes":{"description":"Scopes to grant to this key","example":["plugin-endpoints"],"type":"array","items":{"type":"string"}},"projectId":{"type":"string","description":"Optional project ID to scope this key to","example":"my-project-id"},"expiresAt":{"type":"string","description":"Optional expiration date (ISO string)","example":"2025-12-31T23:59:59Z"}},"required":["name","scopes"]},"CreateApiKeyResponse":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier"},"name":{"type":"string","description":"Key name"},"projectId":{"type":"string","description":"Project ID this key is scoped to (null = all projects)"},"keyPrefix":{"type":"string","description":"First characters of the key for identification","example":"ots_live_abc1..."},"scopes":{"description":"Scopes this key has access to","type":"array","items":{"type":"string"}},"lastUsedAt":{"format":"date-time","type":"string","description":"When the key was last used"},"expiresAt":{"format":"date-time","type":"string","description":"Expiration date"},"createdAt":{"format":"date-time","type":"string","description":"Creation date"},"key":{"type":"string","description":"Full API key - shown only once at creation!"}},"required":["id","name","keyPrefix","scopes","createdAt","key"]},"ProjectPermissions":{"type":"object","properties":{"addAccessKey":{"type":"boolean","description":"Permission to add an access key"},"editAccessKey":{"type":"boolean","description":"Permission to edit an access key"},"deleteAccessKey":{"type":"boolean","description":"Permission to delete an access key"},"addUser":{"type":"boolean","description":"Permission to add a user to the project"},"editUser":{"type":"boolean","description":"Permission to edit a user's details (e.g. change role)"},"deleteUser":{"type":"boolean","description":"Permission to delete a user from the project"},"setPeerLimit":{"type":"boolean","description":"Permission to set the peer limit for the project"},"setProjectName":{"type":"boolean","description":"Permission to change the project's name"},"downloadLicense":{"type":"boolean","description":"Permission to download the project's license"}}},"ProductFeature":{"type":"object","properties":{"slug":{"type":"string","description":"Unique slug for the feature (e.g. cortex.transcription)"},"name":{"type":"string","description":"Display name of the feature"},"description":{"type":"string","description":"Description of the feature"},"dependsOnProduct":{"type":"string","description":"Product that must be activated for this feature to work"},"dependsOnFeature":{"type":"string","description":"Slug of another feature this depends on","nullable":true}}},"ProductPricing":{"type":"object","properties":{"pricingType":{"type":"string","description":"The pricing model type","enum":["free","pay_as_you_go","one_time","monthly"]},"unit":{"type":"string","description":"Unit label for pay-as-you-go pricing (e.g. PCU-day, instance-day)","nullable":true},"unitAmount":{"type":"number","description":"Amount in cents"},"currency":{"type":"string","description":"ISO 4217 currency code (e.g. EUR)"},"label":{"type":"string","description":"Human-readable tier label","nullable":true}}},"ProjectProduct":{"type":"object","properties":{"slug":{"type":"string","description":"Product slug identifier","enum":["voice","rooms","fleet","cortex"]},"name":{"type":"string","description":"Display name of the product"},"description":{"type":"string","description":"Description of the product"},"icon":{"type":"string","description":"Icon identifier or URL","nullable":true},"termsUrl":{"type":"string","description":"URL to the terms and conditions","nullable":true},"pricingUrl":{"type":"string","description":"URL to the pricing page","nullable":true},"websiteUrl":{"type":"string","description":"URL to the product website","nullable":true},"features":{"description":"Features available within this product","type":"array","items":{"$ref":"#/components/schemas/ProductFeature"}},"pricing":{"description":"Available pricing tiers","type":"array","items":{"$ref":"#/components/schemas/ProductPricing"}},"dependencies":{"description":"Slugs of products that must be activated before this product","type":"array","items":{"type":"string"}}}},"ActivatedProduct":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the activation"},"product":{"description":"Product details","allOf":[{"$ref":"#/components/schemas/ProjectProduct"}]},"activatedAt":{"type":"string","description":"When the product was activated (ISO 8601)"},"config":{"type":"object","additionalProperties":true,"description":"Product-specific configuration (e.g. { domain: \"example.rooms.chat\" })","nullable":true}}},"App":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the app/project"},"name":{"type":"string","description":"The name of the app/project"},"description":{"type":"string","description":"A brief description of the project"},"type":{"type":"string","description":"The type of the app/project","enum":["sdk","conferencing"]},"secret":{"type":"string","description":"The secret key of the app/project"},"appId":{"type":"string","description":"Application identifier associated with the project"},"created":{"type":"string","description":"The creation date and time of the project"},"updated":{"type":"string","description":"The last update date and time of the project"},"role":{"type":"string","description":"The role of the requesting user in the context of the project"},"domain":{"type":"string","description":"The domain name for the project"},"isConfigured":{"type":"boolean","description":"Whether app settings are configured for transcription"},"userCount":{"type":"number","description":"Number of users associated with this project"},"currentUserRole":{"type":"string","description":"The requesting user's role in this project"},"permissions":{"description":"Granular permission flags for the current user within this project","allOf":[{"$ref":"#/components/schemas/ProjectPermissions"}]},"billingState":{"type":"string","description":"Current billing state of the project (e.g. free, mini, indie, active, external)","enum":["free","mini","indie","active","external"]},"activatedProducts":{"description":"Products activated for this project, with full metadata and configuration","type":"array","items":{"$ref":"#/components/schemas/ActivatedProduct"}}},"required":["id","name","description","type","secret","appId","created","updated","role","domain"]},"ProjectUser":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the user"},"name":{"type":"string","description":"Display name of the user"},"email":{"type":"string","description":"Email address of the user"},"role":{"type":"string","description":"The user's role within the project","enum":["admin","maintainer","developer"]},"status":{"type":"string","description":"Status of the user's project association","enum":["active","pending","revoked"]},"created":{"type":"string","description":"When the user was added to the project"}},"required":["id","name","email","role","status"]},"InviteProjectUserRequest":{"type":"object","properties":{"email":{"type":"string","description":"Email address of the user to invite","example":"user@example.com"},"role":{"type":"string","description":"Role to assign to the invited user","enum":["admin","maintainer","developer"],"example":"developer"}},"required":["email","role"]},"RemoveProjectUserRequest":{"type":"object","properties":{"permissionId":{"type":"string","description":"The permission ID of the user to remove (ProjectUserDto.id)"}},"required":["permissionId"]},"ChangeProjectUserRoleRequest":{"type":"object","properties":{"permissionId":{"type":"string","description":"The permission ID of the user (ProjectUserDto.id)"},"role":{"type":"string","description":"New role to assign","enum":["admin","maintainer","developer"],"example":"maintainer"}},"required":["permissionId","role"]},"GenerateTokenRequest":{"type":"object","properties":{"roomId":{"type":"string","description":"The Room ID"},"projectId":{"type":"string","description":"The Project ID (API Key)"},"secret":{"type":"string","description":"The Project Secret"}},"required":["roomId","projectId","secret"]},"GenerateTokenResponse":{"type":"object","properties":{"token":{"type":"string","description":"The generated access token"}},"required":["token"]},"AppSettingsResponse":{"type":"object","properties":{"id":{"type":"string","description":"Settings ID"},"appId":{"type":"string","description":"App ID"},"tokenProviderType":{"type":"string","description":"Token provider type","enum":["access_key","webservice","rooms"]},"botUserId":{"type":"string","description":"Bot User ID (for access_key provider)"},"webserviceUrl":{"type":"string","description":"Webservice URL (for webservice provider)"},"webserviceMethod":{"type":"string","description":"Webservice method"},"botUserData":{"type":"object","additionalProperties":true,"description":"Bot peer userData"},"isConfigured":{"type":"boolean","description":"Whether settings are configured"},"hasSecret":{"type":"boolean","description":"Whether a project secret is cached locally for HMAC authentication"},"debugAudioEnabled":{"type":"boolean","description":"Whether debug audio storage is enabled for transcription debugging","default":false},"projectName":{"type":"string","description":"Human-readable project name (synced from Payment system)"},"e2eEncryptionMode":{"type":"string","description":"End-to-end encryption mode for the bot","enum":["disabled","automatic","manual"],"default":"disabled"},"e2eEncryptionPassword":{"type":"string","description":"Decrypted manual cipher password (only returned when mode=manual). Will be removed once a webhook-based mechanism replaces at-rest storage."}},"required":["id","appId","tokenProviderType","isConfigured","hasSecret"]},"AccessKeyConfig":{"type":"object","properties":{"accessKey":{"type":"string","description":"ODIN Access Key","example":"AK..."},"botUserId":{"type":"string","description":"Bot User ID","example":"transcription-bot"}},"required":["accessKey","botUserId"]},"WebserviceConfig":{"type":"object","properties":{"url":{"type":"string","description":"Token generation endpoint URL","example":"https://myserver.com/token"},"method":{"type":"string","description":"HTTP method","enum":["GET","POST"],"example":"POST"},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"HTTP headers","example":{"Authorization":"Bearer xxx"}},"bodyTemplate":{"type":"string","description":"Request body template with {{roomId}} placeholder","example":"{\"roomId\": \"{{roomId}}\"}"},"responseTokenPath":{"type":"string","description":"JSONPath to extract token from response","example":"data.token"}},"required":["url","method","responseTokenPath"]},"UpsertAppSettingsRequest":{"type":"object","properties":{"tokenProviderType":{"type":"string","description":"Token provider type","enum":["access_key","webservice","rooms"]},"accessKeyConfig":{"description":"Access Key config (required for access_key provider)","allOf":[{"$ref":"#/components/schemas/AccessKeyConfig"}]},"webserviceConfig":{"description":"Webservice config (required for webservice provider)","allOf":[{"$ref":"#/components/schemas/WebserviceConfig"}]},"botUserData":{"type":"object","additionalProperties":true,"description":"Bot peer userData as JSON","example":{"name":"Transcription Bot","role":"bot"}},"debugAudioEnabled":{"type":"boolean","description":"Enable debug audio storage for transcription debugging (auto-deleted after 24h). Defaults to false when omitted."},"e2eEncryptionMode":{"type":"string","description":"End-to-end encryption mode for the bot","enum":["disabled","automatic","manual"]},"e2eEncryptionPassword":{"type":"string","description":"Manual cipher password (only used when mode=manual). Stored encrypted at rest."}},"required":["tokenProviderType"]},"UpdateAppSettingsRequest":{"type":"object","properties":{"tokenProviderType":{"type":"string","description":"Token provider type","enum":["access_key","webservice","rooms"]},"accessKeyConfig":{"description":"Access Key config (required for access_key provider)","allOf":[{"$ref":"#/components/schemas/AccessKeyConfig"}]},"webserviceConfig":{"description":"Webservice config (required for webservice provider)","allOf":[{"$ref":"#/components/schemas/WebserviceConfig"}]},"botUserData":{"type":"object","additionalProperties":true,"description":"Bot peer userData as JSON","example":{"name":"Transcription Bot","role":"bot"}},"debugAudioEnabled":{"type":"boolean","description":"Enable debug audio storage for transcription debugging (auto-deleted after 24h). Defaults to false when omitted."},"e2eEncryptionMode":{"type":"string","description":"End-to-end encryption mode for the bot","enum":["disabled","automatic","manual"]},"e2eEncryptionPassword":{"type":"string","description":"Manual cipher password (only used when mode=manual). Stored encrypted at rest."}}},"UpdateDebugAudioRequest":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether to enable debug audio storage","example":true}},"required":["enabled"]},"UpdateE2EEncryptionRequest":{"type":"object","properties":{"mode":{"type":"string","description":"End-to-end encryption mode","enum":["disabled","automatic","manual"]},"password":{"type":"string","description":"Cipher password — required when mode=manual. Leave empty to keep existing."}},"required":["mode"]},"SessionCreatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["created"]},"data":{"$ref":"#/components/schemas/SessionResponse"}},"required":["action","data"]},"SessionCreatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["session.created"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/SessionCreatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"SessionUpdatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["updated"]},"data":{"$ref":"#/components/schemas/SessionResponse"},"changes":{"type":"object","additionalProperties":true,"description":"Previous values of changed fields"}},"required":["action","data"]},"SessionUpdatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["session.updated"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/SessionUpdatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"SessionDeletedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["deleted"]},"data":{"$ref":"#/components/schemas/SessionResponse"}},"required":["action","data"]},"SessionDeletedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["session.deleted"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/SessionDeletedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"MessageCreatedEventData":{"type":"object","properties":{"id":{"type":"string","description":"Message ID"},"sessionId":{"type":"string","description":"Session ID the message belongs to"},"participantId":{"type":"string","description":"Participant ID (null for system messages)","nullable":true},"externalUserId":{"type":"string","description":"External user ID from ODIN (null for system messages)","nullable":true},"type":{"type":"string","description":"Message type (only set on system messages)","enum":["user","system"]},"senderName":{"type":"string","description":"Sender display name (or \"[System]\" for system messages)"},"content":{"type":"string","description":"Transcribed message content"},"timestamp":{"type":"string","description":"Message timestamp","format":"date-time"},"hasDebugAudio":{"type":"boolean","description":"Whether a debug audio WAV is available (user messages only)"}},"required":["id","sessionId","participantId","externalUserId","senderName","content","timestamp"]},"MessageCreatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["created"]},"data":{"$ref":"#/components/schemas/MessageCreatedEventData"}},"required":["action","data"]},"MessageCreatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["message.created"]},"source":{"type":"string","description":"Origin service","enum":["cortex:bot"]},"payload":{"$ref":"#/components/schemas/MessageCreatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"WebhookDeliveryStatusEventData":{"type":"object","properties":{"id":{"type":"string","description":"Webhook event ID"},"eventType":{"type":"string","description":"The domain event type that triggered the webhook","example":"message.created"},"status":{"type":"string","description":"Delivery status","enum":["pending","delivered","failed"]},"attemptsCount":{"type":"number","description":"Number of delivery attempts so far"},"lastError":{"type":"string","description":"Last delivery error message, if any"},"projectId":{"type":"string","description":"Project/app ID the webhook event belongs to"}},"required":["id","eventType","status","attemptsCount"]},"WebhookDeliveryUpdatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["occurred"]},"data":{"$ref":"#/components/schemas/WebhookDeliveryStatusEventData"}},"required":["action","data"]},"WebhookDeliveryUpdatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["webhook.delivery.updated"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/WebhookDeliveryUpdatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"ParticipantResponse":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the participant"},"projectId":{"type":"string","description":"ODIN project ID this participant belongs to"},"displayName":{"type":"string","description":"Display name of the participant"},"externalUserId":{"type":"string","description":"External User ID from ODIN (stable identifier)"},"tenantId":{"type":"string","description":"Tenant ID"},"userData":{"type":"object","additionalProperties":true,"description":"User data from ODIN (parsed JSON)"},"joinedAt":{"format":"date-time","type":"string","description":"When the participant first joined any session in the project"}},"required":["id","projectId","displayName","externalUserId","tenantId","userData","joinedAt"]},"ParticipantCreatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["created"]},"data":{"$ref":"#/components/schemas/ParticipantResponse"}},"required":["action","data"]},"ParticipantCreatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["participant.created"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/ParticipantCreatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"ParticipantUpdatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["updated"]},"data":{"$ref":"#/components/schemas/ParticipantResponse"},"changes":{"type":"object","additionalProperties":true,"description":"Previous values of changed fields"}},"required":["action","data"]},"ParticipantUpdatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["participant.updated"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/ParticipantUpdatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"ParticipantDeletedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["deleted"]},"data":{"$ref":"#/components/schemas/ParticipantResponse"}},"required":["action","data"]},"ParticipantDeletedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["participant.deleted"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/ParticipantDeletedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"MessageAnnotationCreatedEventData":{"type":"object","properties":{"annotationId":{"type":"string","description":"ID of the created annotation row"},"messageId":{"type":"string","description":"Message ID this annotation is attached to"},"participantId":{"type":"string","description":"Participant ID, when available from the source message"},"externalUserId":{"type":"string","description":"External user ID, when available from the source message"},"type":{"type":"string","description":"Annotation type","example":"profanity"},"content":{"type":"object","additionalProperties":true,"description":"Annotation content (free-form, plugin-defined). Named `content` rather than `data` so the event reads `payload.data.content` instead of `payload.data.data`."}},"required":["annotationId","messageId","type","content"]},"MessageAnnotationCreatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["created"]},"data":{"$ref":"#/components/schemas/MessageAnnotationCreatedEventData"}},"required":["action","data"]},"MessageAnnotationCreatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["message.annotation.created"]},"source":{"type":"string","description":"Origin service","enum":["cortex:plugin"]},"payload":{"$ref":"#/components/schemas/MessageAnnotationCreatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"SessionAnnotationCreatedEventData":{"type":"object","properties":{"annotationId":{"type":"string","description":"ID of the created annotation row"},"sessionId":{"type":"string","description":"Session ID this annotation is attached to"},"type":{"type":"string","description":"Annotation type","example":"summary"},"content":{"type":"object","additionalProperties":true,"description":"Annotation content (free-form, plugin-defined). Named `content` rather than `data` so the event reads `payload.data.content` instead of `payload.data.data`."}},"required":["annotationId","sessionId","type","content"]},"SessionAnnotationCreatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["created"]},"data":{"$ref":"#/components/schemas/SessionAnnotationCreatedEventData"}},"required":["action","data"]},"SessionAnnotationCreatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["session.annotation.created"]},"source":{"type":"string","description":"Origin service","enum":["cortex:plugin"]},"payload":{"$ref":"#/components/schemas/SessionAnnotationCreatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"ParticipantInfo":{"type":"object","properties":{"id":{"type":"string","description":"Participant ID"},"projectId":{"type":"string","description":"ODIN project ID this participant belongs to"},"displayName":{"type":"string","description":"Display name of the participant"},"externalUserId":{"type":"string","description":"External user ID from ODIN"},"userData":{"type":"object","additionalProperties":true,"description":"User data from ODIN (parsed JSON)"},"joinedAt":{"format":"date-time","type":"string","description":"When the participant first joined the project"}},"required":["id","projectId","displayName","externalUserId"]},"SanctionResponse":{"type":"object","properties":{"id":{"type":"string","description":"Sanction ID"},"tenantId":{"type":"string","description":"Tenant ID"},"participantId":{"type":"string","description":"Participant ID (if session-scoped)"},"externalUserId":{"type":"string","description":"External user ID"},"sessionId":{"type":"string","description":"Session ID (if session-scoped)"},"type":{"type":"string","enum":["warn","mute","listen_only","text_only","rate_limit","shadow_mute","temp_ban","perm_ban","ranked_restriction","queue_delay","party_restriction","human_review"],"description":"Type of sanction"},"scope":{"type":"object","additionalProperties":true,"description":"Scope configuration"},"reason":{"type":"string","description":"Reason for sanction"},"metadata":{"type":"object","additionalProperties":true,"description":"Additional metadata"},"startAt":{"format":"date-time","type":"string","description":"When sanction becomes active"},"endAt":{"format":"date-time","type":"string","description":"When sanction expires (null = permanent)"},"createdByUserId":{"type":"string","description":"User who created the sanction"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"updatedAt":{"format":"date-time","type":"string","description":"Last update timestamp"},"revokedAt":{"format":"date-time","type":"string","description":"When sanction was revoked"},"revokedByUserId":{"type":"string","description":"User who revoked the sanction"},"isActive":{"type":"boolean","description":"Whether the sanction is currently active"},"status":{"type":"string","description":"Status: active, expired, or revoked"},"participant":{"description":"Participant information (if available)","allOf":[{"$ref":"#/components/schemas/ParticipantInfo"}]}},"required":["id","tenantId","type","startAt","createdAt","updatedAt","isActive","status"]},"SanctionCreatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["created"]},"data":{"$ref":"#/components/schemas/SanctionResponse"}},"required":["action","data"]},"SanctionCreatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["sanction.created"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/SanctionCreatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"SanctionUpdatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["updated"]},"data":{"$ref":"#/components/schemas/SanctionResponse"},"changes":{"type":"object","additionalProperties":true,"description":"Previous values of changed fields"}},"required":["action","data"]},"SanctionUpdatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["sanction.updated"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/SanctionUpdatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"SanctionRevokedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["occurred"]},"data":{"$ref":"#/components/schemas/SanctionResponse"}},"required":["action","data"]},"SanctionRevokedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["sanction.revoked"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/SanctionRevokedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringMember":{"type":"object","properties":{"id":{"type":"string","description":"Member record ID"},"gatheringId":{"type":"string","description":"Gathering ID"},"participantId":{"type":"string","description":"Participant ID"},"displayName":{"type":"string","description":"Participant display name"},"status":{"type":"string","enum":["invited","joined","ready","left"],"description":"Member status"},"role":{"type":"string","enum":["owner","member"],"description":"Member role"},"properties":{"type":"object","additionalProperties":true,"description":"Custom member properties"},"invitedAt":{"format":"date-time","type":"string","description":"When the member was invited"},"joinedAt":{"format":"date-time","type":"string","description":"When the member joined"},"readyAt":{"format":"date-time","type":"string","description":"When the member marked as ready"}},"required":["id","gatheringId","participantId","displayName","status","role"]},"GatheringResponse":{"type":"object","properties":{"id":{"type":"string","description":"Gathering ID"},"projectId":{"type":"string","description":"Project ID"},"tenantId":{"type":"string","description":"Tenant ID"},"name":{"type":"string","description":"Gathering name"},"description":{"type":"string","description":"Gathering description"},"inviterName":{"type":"string","description":"Display name of the gathering organizer"},"inviterEmail":{"type":"string","description":"Email address of the gathering organizer (used as Reply-To in invitation emails)"},"type":{"type":"string","enum":["lobby","appointment","open"],"description":"Gathering type"},"status":{"type":"string","enum":["pending","active","started","ended","cancelled","expired"],"description":"Gathering status"},"maxMembers":{"type":"number","description":"Maximum members allowed"},"memberCount":{"type":"number","description":"Current member count"},"accessPolicy":{"type":"string","description":"Access policy"},"listed":{"type":"boolean","description":"Whether gathering is listed for discovery"},"startsAt":{"format":"date-time","type":"string","description":"Scheduled start time"},"endsAt":{"format":"date-time","type":"string","description":"Scheduled end time"},"timezone":{"type":"string","description":"Timezone for scheduled times"},"roomId":{"type":"string","description":"Target ODIN room ID"},"autoStartSession":{"type":"boolean","description":"Whether session starts automatically"},"sessionId":{"type":"string","description":"Created session ID"},"joinCode":{"type":"string","description":"Join code for sharing"},"properties":{"type":"object","additionalProperties":true,"description":"Custom properties"},"ownerId":{"type":"string","description":"Owner participant ID"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"expiresAt":{"format":"date-time","type":"string","description":"Expiration timestamp"},"members":{"description":"Members (included in detailed view)","type":"array","items":{"$ref":"#/components/schemas/GatheringMember"}}},"required":["id","projectId","tenantId","name","type","status","maxMembers","memberCount","accessPolicy","listed","autoStartSession","joinCode","createdAt"]},"GatheringCreatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["created"]},"data":{"$ref":"#/components/schemas/GatheringResponse"}},"required":["action","data"]},"GatheringCreatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.created"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringCreatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringUpdatedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["updated"]},"data":{"$ref":"#/components/schemas/GatheringResponse"},"changes":{"type":"object","additionalProperties":true,"description":"Previous values of changed fields"}},"required":["action","data"]},"GatheringUpdatedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.updated"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringUpdatedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringOccurredPayload":{"type":"object","properties":{"action":{"type":"string","enum":["occurred"]},"data":{"$ref":"#/components/schemas/GatheringResponse"}},"required":["action","data"]},"GatheringStartedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.started"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringOccurredPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringEndedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.ended"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringOccurredPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringCancelledEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.cancelled"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringOccurredPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringMemberEventData":{"type":"object","properties":{"gatheringId":{"type":"string","description":"Gathering ID"},"member":{"description":"The member that joined / became ready","allOf":[{"$ref":"#/components/schemas/GatheringMember"}]}},"required":["gatheringId","member"]},"GatheringMemberPayload":{"type":"object","properties":{"action":{"type":"string","enum":["occurred"]},"data":{"$ref":"#/components/schemas/GatheringMemberEventData"}},"required":["action","data"]},"GatheringMemberJoinedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.member.joined"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringMemberPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringMemberReadyEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.member.ready"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringMemberPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringMemberLeftEventData":{"type":"object","properties":{"gatheringId":{"type":"string","description":"Gathering ID"},"participantId":{"type":"string","description":"Participant ID of the member that left"}},"required":["gatheringId","participantId"]},"GatheringMemberLeftPayload":{"type":"object","properties":{"action":{"type":"string","enum":["occurred"]},"data":{"$ref":"#/components/schemas/GatheringMemberLeftEventData"}},"required":["action","data"]},"GatheringMemberLeftEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.member.left"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringMemberLeftPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringInvitationSentPayload":{"type":"object","properties":{"action":{"type":"string","enum":["occurred"]},"data":{"oneOf":[{"$ref":"#/components/schemas/InvitationResponse"},{"$ref":"#/components/schemas/GatheringInvitationSentEmailData"}]}},"required":["action","data"]},"GatheringInvitationSentEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.invitation.sent"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringInvitationSentPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringInvitationAcceptedEventData":{"type":"object","properties":{"invitationId":{"type":"string","description":"Invitation ID"},"gatheringId":{"type":"string","description":"Gathering ID"},"participantId":{"type":"string","description":"Participant ID that accepted"}},"required":["invitationId","gatheringId","participantId"]},"GatheringInvitationAcceptedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["occurred"]},"data":{"$ref":"#/components/schemas/GatheringInvitationAcceptedEventData"}},"required":["action","data"]},"GatheringInvitationAcceptedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.invitation.accepted"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringInvitationAcceptedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GatheringInvitationDeclinedEventData":{"type":"object","properties":{"invitationId":{"type":"string","description":"Invitation ID"},"gatheringId":{"type":"string","description":"Gathering ID"}},"required":["invitationId","gatheringId"]},"GatheringInvitationDeclinedPayload":{"type":"object","properties":{"action":{"type":"string","enum":["occurred"]},"data":{"$ref":"#/components/schemas/GatheringInvitationDeclinedEventData"}},"required":["action","data"]},"GatheringInvitationDeclinedEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","enum":["gathering.invitation.declined"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api"]},"payload":{"$ref":"#/components/schemas/GatheringInvitationDeclinedPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"GenericEventPayload":{"type":"object","properties":{"action":{"type":"string","enum":["created","updated","deleted","occurred"]},"data":{"type":"object","additionalProperties":true,"description":"Event-specific data (open object for non-modelled events)"},"changes":{"type":"object","additionalProperties":true,"description":"Previous values of changed fields (updated only)"}},"required":["action","data"]},"GenericDomainEvent":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID for this specific event occurrence (UUIDv4)"},"tenantId":{"type":"string","description":"Tenant this event belongs to"},"projectId":{"type":"string","description":"Project/app ID for project-scoped events"},"resourceId":{"type":"string","description":"Composite resource identifier in resource:id format","example":"session:abc-123"},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred","format":"date-time"},"type":{"type":"string","description":"Event type for externally-ingested / non-Cortex-native events","enum":["participant.joined","participant.left","bot.status.changed","image.created","image.updated","image.ready","config.created","config.updated","config.ready","deployment.created","deployment.updated","server.created","server.updated","server.stopped","server.started","server.running"]},"source":{"type":"string","description":"Origin service","enum":["cortex:api","cortex:bot","cortex:plugin","voice:server","voice:gateway","fleet:api","fleet:server"]},"payload":{"$ref":"#/components/schemas/GenericEventPayload"}},"required":["id","tenantId","resourceId","timestamp","type","source","payload"]},"InvitationResponse":{"type":"object","properties":{"id":{"type":"string","description":"Invitation ID"},"gatheringId":{"type":"string","description":"Gathering ID"},"participantId":{"type":"string","description":"Invited participant ID"},"email":{"type":"string","description":"Invited email"},"displayName":{"type":"string","description":"Display name of the invitee"},"invitedById":{"type":"string","description":"Who sent the invitation (null for system-generated invitations)"},"status":{"type":"string","enum":["pending","accepted","declined","expired"],"description":"Invitation status"},"joinUrl":{"type":"string","description":"Join URL"},"joinCode":{"type":"string","description":"Join code"},"invitedAt":{"format":"date-time","type":"string","description":"When invitation was sent"},"expiresAt":{"format":"date-time","type":"string","description":"When invitation expires"},"respondedAt":{"format":"date-time","type":"string","description":"When invitee responded"}},"required":["id","gatheringId","status","joinUrl","joinCode","invitedAt"]},"GatheringInvitationSentEmailData":{"type":"object","properties":{"email":{"type":"string","description":"Invitee email address"},"name":{"type":"string","description":"Invitee display name"}},"required":["email","name"]},"IngestEventDto":{"type":"object","properties":{"type":{"type":"string","description":"The type of domain event being ingested","enum":["session.created","session.updated","session.deleted","message.created","participant.joined","participant.left","participant.updated","participant.created","participant.deleted","bot.status.changed","webhook.delivery.updated","message.annotation.created","session.annotation.created","sanction.created","sanction.updated","sanction.revoked","gathering.created","gathering.updated","gathering.started","gathering.ended","gathering.cancelled","gathering.member.joined","gathering.member.left","gathering.member.ready","gathering.invitation.sent","gathering.invitation.accepted","gathering.invitation.declined","image.created","image.updated","image.ready","config.created","config.updated","config.ready","deployment.created","deployment.updated","server.created","server.updated","server.stopped","server.started","server.running"],"example":"participant.joined"},"source":{"type":"string","description":"The source service that generated this event (namespace:service format)","example":"voice:server","enum":["voice:server","voice:gateway","fleet:api","fleet:server"]},"resourceId":{"type":"string","description":"Resource identifier in resource:id format (e.g. session:abc-123)","example":"session:550e8400-e29b-41d4-a716-446655440000","pattern":"^[a-z_]+:.+$"},"payload":{"type":"object","additionalProperties":true,"description":"Action-typed event payload: { action, data, changes? }","example":{"action":"occurred","data":{"sessionId":"550e8400-e29b-41d4-a716-446655440000","peerId":42,"userId":"user-1"}}},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the event occurred (defaults to server time)","example":"2026-03-20T12:00:00.000Z"}},"required":["type","source","resourceId","payload"]},"CreateSanctionRequest":{"type":"object","properties":{"participantId":{"type":"string","description":"Participant ID to sanction (for session-scoped sanctions)","example":"550e8400-e29b-41d4-a716-446655440000"},"externalUserId":{"type":"string","description":"External user ID from ODIN (for cross-session sanctions)","example":"user_abc123"},"sessionId":{"type":"string","description":"Session ID (for session-scoped sanctions)","example":"550e8400-e29b-41d4-a716-446655440001"},"type":{"type":"string","enum":["warn","mute","listen_only","text_only","rate_limit","shadow_mute","temp_ban","perm_ban","ranked_restriction","queue_delay","party_restriction","human_review"],"description":"Type of sanction to apply","example":"mute"},"scope":{"type":"object","additionalProperties":true,"description":"Scope configuration for channel-specific sanctions","example":{"channels":["team","proximity"]}},"reason":{"type":"string","description":"Reason for the sanction","example":"Repeated use of profanity detected by automated filter"},"metadata":{"type":"object","additionalProperties":true,"description":"Additional metadata (evidence, AI confidence, etc.)","example":{"confidence":0.95,"triggeredBy":"profanity_filter"}},"startAt":{"type":"string","description":"When the sanction starts (defaults to now)","example":"2024-01-15T10:00:00Z"},"endAt":{"type":"string","description":"When the sanction ends (null = permanent)","example":"2024-01-15T11:00:00Z"}},"required":["type"]},"SanctionListResponse":{"type":"object","properties":{"sanctions":{"description":"List of sanctions","type":"array","items":{"$ref":"#/components/schemas/SanctionResponse"}},"total":{"type":"number","description":"Total count (for pagination)"}},"required":["sanctions","total"]},"UpdateSanctionRequest":{"type":"object","properties":{"type":{"type":"string","description":"Updated sanction type","enum":["warn","mute","listen_only","text_only","rate_limit","shadow_mute","temp_ban","perm_ban","ranked_restriction","queue_delay","party_restriction","human_review"]},"scope":{"type":"object","additionalProperties":true,"description":"Updated scope configuration"},"reason":{"type":"string","description":"Updated reason"},"metadata":{"type":"object","additionalProperties":true,"description":"Updated metadata"},"endAt":{"type":"string","description":"Updated end time"}}},"RevokeSanctionRequest":{"type":"object","properties":{"reason":{"type":"string","description":"Reason for revocation","example":"False positive from automated detection"}}},"ParticipantListResponse":{"type":"object","properties":{"participants":{"description":"List of participants","type":"array","items":{"$ref":"#/components/schemas/ParticipantResponse"}},"total":{"type":"number","description":"Total count of participants"}},"required":["participants","total"]},"CreateParticipantRequest":{"type":"object","properties":{"externalUserId":{"type":"string","description":"External User ID from ODIN (stable identifier)"},"displayName":{"type":"string","description":"Display name of the participant"},"userData":{"type":"object","additionalProperties":true,"description":"User data from ODIN (parsed JSON)"}},"required":["externalUserId"]},"UpdateParticipantRequest":{"type":"object","properties":{"displayName":{"type":"string","description":"Display name of the participant"},"userData":{"type":"object","additionalProperties":true,"description":"User data from ODIN (parsed JSON)"}}},"InvitedParticipant":{"type":"object","properties":{"name":{"type":"string","description":"Display name of the invitee","example":"Jane Doe"},"email":{"type":"string","description":"Email address for sending the invitation","example":"jane@example.com"},"userId":{"type":"string","description":"External user ID (from ODIN) for linking to a participant record. If provided, the invitee will be added as a gathering member for attendance tracking.","example":"usr_abc123"}},"required":["name","email"]},"CreateGatheringRequest":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable name for the gathering","example":"Friday Game Night"},"type":{"type":"string","enum":["lobby","appointment","open"],"description":"Type of gathering","example":"lobby"},"maxMembers":{"type":"number","description":"Maximum number of members (2-100)","example":8,"minimum":2,"maximum":100},"accessPolicy":{"type":"string","enum":["public","private","invite-only"],"description":"Access policy for joining","example":"public"},"listed":{"type":"boolean","description":"Whether gathering appears in public search","example":false},"startsAt":{"type":"string","description":"Scheduled start time (for appointments)","example":"2024-01-20T15:00:00Z"},"endsAt":{"type":"string","description":"Scheduled end time (for appointments)","example":"2024-01-20T16:00:00Z"},"timezone":{"type":"string","description":"Timezone for scheduled times (IANA format)","example":"Europe/Berlin"},"autoStartSession":{"type":"boolean","description":"Whether to auto-start transcription session when gathering starts","example":true},"properties":{"type":"object","additionalProperties":true,"description":"Custom properties (game mode, lobby settings, etc.)","example":{"gameMode":"deathmatch","map":"dust2"}},"searchProperties":{"type":"object","additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":"Indexed search properties for discovery","example":{"gameMode":"deathmatch","skillLevel":1200}},"roomId":{"type":"string","description":"Custom room ID for ODIN. If not provided, the join code will be used as the room ID.","example":"game-room-lobby-123"},"ownerId":{"type":"string","description":"Participant UUID of the gathering owner. If not provided, the creator becomes the owner."},"description":{"type":"string","description":"Description providing context about the gathering (shown in invitation emails)","example":"Weekly team sync to discuss project progress and blockers."},"invitationUrl":{"type":"string","description":"URL where participants join the meeting (e.g., Rooms instance URL). Used in invitation emails and calendar entries as the location.","example":"https://myapp.rooms.chat/room/abc123"},"participants":{"description":"List of participants to invite. Each invitee receives an email invitation. For Appointment gatherings with a start date, a calendar invite (.ics) is attached.","type":"array","items":{"$ref":"#/components/schemas/InvitedParticipant"}},"inviterName":{"type":"string","description":"Display name of the person organizing the gathering. Shown as \"Invited by {name}\" in invitation emails and used as the ORGANIZER CN in calendar invites.","example":"Alice Smith"},"inviterEmail":{"type":"string","description":"Email address of the person organizing the gathering. Used as the Reply-To address in invitation emails and as the ORGANIZER mailto in calendar invites so recipients can reply directly to the inviter.","example":"alice@example.com"}},"required":["name","type"]},"GatheringListResponse":{"type":"object","properties":{"gatherings":{"description":"List of gatherings","type":"array","items":{"$ref":"#/components/schemas/GatheringResponse"}},"total":{"type":"number","description":"Total count (for pagination)"}},"required":["gatherings","total"]},"UpdateGatheringRequest":{"type":"object","properties":{"name":{"type":"string","description":"Updated name"},"maxMembers":{"type":"number","description":"Updated max members"},"accessPolicy":{"type":"string","enum":["public","private","invite-only"],"description":"Updated access policy"},"listed":{"type":"boolean","description":"Updated visibility"},"startsAt":{"type":"string","description":"Updated scheduled start time"},"endsAt":{"type":"string","description":"Updated scheduled end time"},"properties":{"type":"object","additionalProperties":true,"description":"Updated properties"},"searchProperties":{"type":"object","additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":"Updated search properties"},"description":{"type":"string","description":"Updated description"},"inviterName":{"type":"string","description":"Updated inviter display name"},"inviterEmail":{"type":"string","description":"Updated inviter email address"}}},"StartGatheringRequest":{"type":"object","properties":{"roomId":{"type":"string","description":"ODIN room ID to use","example":"room-123"}},"required":["roomId"]},"JoinGatheringRequest":{"type":"object","properties":{"joinCode":{"type":"string","description":"8-character join code","example":"ABCD1234"},"participantId":{"type":"string","description":"Participant ID of the joining member"}},"required":["joinCode","participantId"]},"JoinGatheringResponse":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether join was successful"},"gathering":{"description":"Gathering data","allOf":[{"$ref":"#/components/schemas/GatheringResponse"}]},"member":{"description":"Member data","allOf":[{"$ref":"#/components/schemas/GatheringMember"}]},"error":{"type":"string","description":"Error message if failed"}},"required":["success"]},"AddMemberRequest":{"type":"object","properties":{"participantId":{"type":"string","description":"Participant ID to add"},"role":{"type":"string","enum":["owner","member"],"description":"Role for the member (default: member)"},"properties":{"type":"object","additionalProperties":true,"description":"Custom member properties"}},"required":["participantId"]},"UpdateMemberRequest":{"type":"object","properties":{"status":{"type":"string","enum":["invited","joined","ready","left"],"description":"Updated member status"},"properties":{"type":"object","additionalProperties":true,"description":"Updated member properties"}}},"SendInvitationsRequest":{"type":"object","properties":{"participantIds":{"description":"Participant IDs to invite","type":"array","items":{"type":"string"}},"emails":{"description":"Email addresses to invite","type":"array","items":{"type":"string"}},"customProtocol":{"type":"string","description":"Custom protocol format for join URL","example":"mygame://"},"baseUrl":{"type":"string","description":"Base URL for HTTP join links","example":"https://game.example.com"},"invitedById":{"type":"string","description":"Participant UUID of the person sending invitations"}},"required":["invitedById"]},"AcceptInvitationRequest":{"type":"object","properties":{"participantId":{"type":"string","description":"The accepting participant UUID"}},"required":["participantId"]},"GenerateProjectTokenRequest":{"type":"object","properties":{"roomId":{"type":"string","description":"The Room ID","example":"my-awesome-room"},"userId":{"type":"string","description":"The User ID","example":"my-user-id"}},"required":["roomId","userId"]},"FunctionDependency":{"type":"object","properties":{"name":{"type":"string","description":"NPM package name","example":"node-mailjet"},"version":{"type":"string","description":"Semantic version or tag","example":"^6.0.0"}},"required":["name","version"]},"FunctionEnvVar":{"type":"object","properties":{"key":{"type":"string","description":"Environment variable name","example":"API_KEY"},"value":{"type":"string","description":"Environment variable value (masked if secret)","example":"***"},"isSecret":{"type":"boolean","description":"Whether this is a secret (encrypted at rest)","default":false}},"required":["key","value","isSecret"]},"FunctionSettings":{"type":"object","properties":{"isActivated":{"type":"boolean","description":"Whether Functions feature is activated"},"activationStep":{"type":"string","description":"Current activation step (for async progress tracking)","enum":["pending","registry","image","config","deployment","server","complete","error"]},"activationError":{"type":"string","description":"Error message if activation failed"},"fleetAppId":{"type":"number","description":"Fleet app ID"},"fleetRegistryId":{"type":"number","description":"Fleet Docker registry ID"},"fleetImageId":{"type":"string","description":"Fleet binary/image ID"},"fleetServerConfigId":{"type":"string","description":"Fleet server config ID"},"fleetDeploymentId":{"type":"number","description":"Fleet deployment ID (app location setting)"},"resourcePackageSlug":{"type":"string","description":"Resource package slug","example":"fleet-s1"},"locationCity":{"type":"string","description":"Deployment location city","example":"frankfurt"},"fleetRegion":{"type":"string","description":"Fleet region (deprecated, use locationCity)","example":"eu-west"},"maxFunctions":{"type":"number","description":"Maximum functions allowed","example":10},"maxMemoryPerFunction":{"type":"number","description":"Maximum memory per function (MB)","example":512},"dependencies":{"description":"NPM dependencies shared by all functions","type":"array","items":{"$ref":"#/components/schemas/FunctionDependency"}},"envVars":{"description":"Environment variables shared by all functions (secrets masked)","type":"array","items":{"$ref":"#/components/schemas/FunctionEnvVar"}}},"required":["isActivated","maxFunctions","maxMemoryPerFunction"]},"VerifyCredentialsResponse":{"type":"object","properties":{"valid":{"type":"boolean","description":"Whether credentials are valid"},"email":{"type":"string","description":"User email"}},"required":["valid","email"]},"ResourcePackage":{"type":"object","properties":{"id":{"type":"number","description":"Resource package ID","example":1},"name":{"type":"string","description":"Resource package name","example":"Fleet S1"},"slug":{"type":"string","description":"URL-friendly slug","example":"fleet-s1"},"type":{"type":"string","description":"Package type","enum":["shared","dedicated"],"example":"shared"},"cpuLimit":{"type":"number","description":"CPU limit (cores)","example":0.5},"memoryLimitMiB":{"type":"number","description":"Memory limit in MiB","example":512}},"required":["id","name","slug","type","cpuLimit","memoryLimitMiB"]},"Location":{"type":"object","properties":{"city":{"type":"string","description":"City code","example":"frankfurt"},"cityDisplay":{"type":"string","description":"Display name","example":"Frankfurt, Germany"},"continent":{"type":"string","description":"Continent","example":"europe"},"country":{"type":"string","description":"Country code","example":"de"},"isProtected":{"type":"boolean","description":"Whether location is DDoS protected"}},"required":["city","continent","country"]},"ActivateFunctionsRequest":{"type":"object","properties":{"resourcePackage":{"type":"string","description":"Resource package slug. Defaults to \"fleet-s1\" when omitted.","example":"fleet-s1"},"locationCity":{"type":"string","description":"Deployment location city","example":"frankfurt"},"locationCityDisplay":{"type":"string","description":"Deployment location city display name","example":"Frankfurt, Germany"},"locationContinent":{"type":"string","description":"Deployment location continent","example":"europe"},"locationCountry":{"type":"string","description":"Deployment location country","example":"de"},"locationIsProtected":{"type":"boolean","description":"Whether location is DDoS protected. Defaults to false when omitted."}},"required":["locationCity","locationContinent","locationCountry"]},"ActivateFunctionsResponse":{"type":"object","properties":{"message":{"type":"string","description":"Status message","example":"Activation started"}},"required":["message"]},"UpdateFunctionSettingsRequest":{"type":"object","properties":{"fleetRegion":{"type":"string","description":"Fleet region"},"maxFunctions":{"type":"number","description":"Maximum functions allowed (requires upgrade)"},"maxMemoryPerFunction":{"type":"number","description":"Maximum memory per function (MB)"}}},"UpdateDependenciesRequest":{"type":"object","properties":{"dependencies":{"description":"NPM dependencies for the project","type":"array","items":{"$ref":"#/components/schemas/FunctionDependency"}}},"required":["dependencies"]},"UpdateDependenciesResponse":{"type":"object","properties":{"settings":{"description":"Updated settings","allOf":[{"$ref":"#/components/schemas/FunctionSettings"}]},"message":{"type":"string","description":"Status message","example":"Dependencies updated. Runtime restarting..."}},"required":["settings","message"]},"SetEnvVarRequest":{"type":"object","properties":{"key":{"type":"string","description":"Environment variable name","example":"API_KEY"},"value":{"type":"string","description":"Environment variable value","example":"sk-..."},"isSecret":{"type":"boolean","description":"Whether this is a secret. Defaults to false when omitted."}},"required":["key","value"]},"UpdateEnvVarsRequest":{"type":"object","properties":{"envVars":{"description":"Environment variables for the project","type":"array","items":{"$ref":"#/components/schemas/SetEnvVarRequest"}}},"required":["envVars"]},"UpdateEnvVarsResponse":{"type":"object","properties":{"settings":{"description":"Updated settings","allOf":[{"$ref":"#/components/schemas/FunctionSettings"}]},"message":{"type":"string","description":"Status message","example":"Environment variables updated. Runtime restarting..."}},"required":["settings","message"]},"NpmPackageInfo":{"type":"object","properties":{"name":{"type":"string","description":"Package name","example":"node-mailjet"},"versions":{"description":"All available versions (sorted newest first)","example":["6.0.6","6.0.5","6.0.4"],"type":"array","items":{"type":"string"}},"distTags":{"type":"object","additionalProperties":{"type":"string"},"description":"Dist tags (latest, next, beta, etc.)","example":{"latest":"6.0.6","next":"7.0.0-beta.1"}}},"required":["name","versions","distTags"]},"RuntimeStatusResponse":{"type":"object","properties":{"status":{"type":"string","description":"Runtime status","enum":["running","stopped","starting","stopping","unknown"]},"serverCount":{"type":"number","description":"Number of running servers"},"fleetDeploymentId":{"type":"number","description":"Fleet deployment ID"},"message":{"type":"string","description":"Status message"},"runtimeVersion":{"type":"string","description":"Runtime version this deployment is pinned to (null = legacy/unpinned)","example":"v1","nullable":true},"latestVersion":{"type":"string","description":"The latest available runtime version","example":"v1"},"upgradeAvailable":{"type":"boolean","description":"Whether a newer runtime version is available to upgrade to"}},"required":["status","message"]},"StartRuntimeResponse":{"type":"object","properties":{"message":{"type":"string","description":"Status message","example":"Runtime started successfully"},"status":{"type":"string","description":"New runtime status","enum":["running","stopped","starting","stopping","unknown"]}},"required":["message","status"]},"StopRuntimeResponse":{"type":"object","properties":{"message":{"type":"string","description":"Status message","example":"Runtime stopped successfully"},"status":{"type":"string","description":"New runtime status","enum":["running","stopped","starting","stopping","unknown"]}},"required":["message","status"]},"RuntimeVersion":{"type":"object","properties":{"version":{"type":"string","description":"Immutable version identifier","example":"v1"},"node":{"type":"number","description":"Node.js major version baked into the image","example":20},"releasedAt":{"type":"string","description":"ISO date the version was published","example":"2026-06-03"},"notes":{"type":"string","description":"Summary of what changed in this version"},"breaking":{"type":"boolean","description":"Whether upgrading to this version may break existing function code"}},"required":["version","node","releasedAt","notes","breaking"]},"RuntimeVersionsResponse":{"type":"object","properties":{"current":{"type":"string","description":"Version the project is currently pinned to (null = legacy/unpinned)","nullable":true,"example":"v1"},"latest":{"type":"string","description":"The latest available runtime version","example":"v1"},"upgradeAvailable":{"type":"boolean","description":"Whether a newer runtime version is available"},"versions":{"description":"All published runtime versions (oldest first)","type":"array","items":{"$ref":"#/components/schemas/RuntimeVersion"}}},"required":["current","latest","upgradeAvailable","versions"]},"UpgradeRuntimeRequest":{"type":"object","properties":{"version":{"type":"string","description":"Runtime version to deploy (must be a known version)","example":"v1"}},"required":["version"]},"FunctionDeployment":{"type":"object","properties":{"id":{"type":"string","description":"Deployment UUID"},"functionId":{"type":"string","description":"Function ID"},"versionId":{"type":"string","description":"Deployed version ID"},"status":{"type":"string","description":"Deployment status","enum":["pending","deploying","running","stopped","failed"]},"fleetServiceId":{"type":"string","description":"Fleet service ID"},"fleetDeploymentId":{"type":"string","description":"Fleet deployment ID"},"serviceIp":{"type":"string","description":"Service IP address (internal)"},"servicePort":{"type":"number","description":"Service port (internal)"},"invokeUrl":{"type":"string","description":"Invoke URL (external via Cortex proxy)"},"lastError":{"type":"string","description":"Last error message"},"requestCount":{"type":"number","description":"Total request count","example":0},"lastInvokedAt":{"format":"date-time","type":"string","description":"Last invocation timestamp"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"updatedAt":{"format":"date-time","type":"string","description":"Last update timestamp"}},"required":["id","functionId","versionId","status","requestCount","createdAt","updatedAt"]},"Function":{"type":"object","properties":{"id":{"type":"string","description":"Function UUID"},"tenantId":{"type":"string","description":"Tenant ID"},"projectId":{"type":"string","description":"Project ID"},"name":{"type":"string","description":"Function name","example":"process-webhook"},"slug":{"type":"string","description":"URL-friendly identifier","example":"process-webhook"},"description":{"type":"string","description":"Function description"},"draftCode":{"type":"string","description":"Draft source code"},"draftEntrypoint":{"type":"string","description":"Entrypoint function name","example":"handler"},"runtime":{"type":"string","description":"Runtime environment","enum":["nodejs20","nodejs22"]},"authMode":{"type":"string","description":"Authentication mode","enum":["public","api_key","signed"]},"timeout":{"type":"number","description":"Execution timeout in milliseconds","example":30000},"memory":{"type":"number","description":"Memory limit in MB","example":256},"envVars":{"description":"Environment variables (secrets masked)","type":"array","items":{"$ref":"#/components/schemas/FunctionEnvVar"}},"publishedVersionId":{"type":"string","description":"Published version ID (if published)"},"status":{"type":"string","description":"Function status: draft (not published) or published (available in runtime)","enum":["draft","published"]},"activeDeployment":{"description":"Active deployment info (deprecated - use status field instead)","deprecated":true,"allOf":[{"$ref":"#/components/schemas/FunctionDeployment"}]},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"},"updatedAt":{"format":"date-time","type":"string","description":"Last update timestamp"}},"required":["id","tenantId","projectId","name","slug","draftCode","draftEntrypoint","runtime","authMode","timeout","memory","envVars","status","createdAt","updatedAt"]},"CreateFunctionRequest":{"type":"object","properties":{"name":{"type":"string","description":"Function name","example":"process-webhook"},"slug":{"type":"string","description":"URL-friendly slug (auto-generated if not provided)","example":"process-webhook"},"description":{"type":"string","description":"Function description"},"code":{"type":"string","description":"Initial source code","example":"exports.handler = async (event, ctx) => { return { statusCode: 200, body: \"Hello\" }; };"},"entrypoint":{"type":"string","description":"Entrypoint function name. Defaults to \"handler\" when omitted."},"runtime":{"type":"string","description":"Runtime environment. Defaults to \"nodejs20\" when omitted.","enum":["nodejs20","nodejs22"]},"authMode":{"type":"string","description":"Authentication mode. Defaults to \"api_key\" when omitted.","enum":["public","api_key","signed"]},"timeout":{"type":"number","description":"Execution timeout in ms (1000-300000). Defaults to 30000 when omitted."},"memory":{"type":"number","description":"Memory limit in MB (128-1024). Defaults to 256 when omitted."},"envVars":{"description":"Initial environment variables","type":"array","items":{"$ref":"#/components/schemas/SetEnvVarRequest"}}},"required":["name","code"]},"UpdateFunctionRequest":{"type":"object","properties":{"name":{"type":"string","description":"Function name"},"description":{"type":"string","description":"Function description"},"draftCode":{"type":"string","description":"Draft source code"},"draftEntrypoint":{"type":"string","description":"Entrypoint function name"},"runtime":{"type":"string","description":"Runtime environment","enum":["nodejs20","nodejs22"]},"authMode":{"type":"string","description":"Authentication mode","enum":["public","api_key","signed"]},"timeout":{"type":"number","description":"Execution timeout in ms (1000-300000)"},"memory":{"type":"number","description":"Memory limit in MB (128-1024)"},"envVars":{"description":"Updated environment variables (replaces all)","type":"array","items":{"$ref":"#/components/schemas/SetEnvVarRequest"}}}},"DeleteFunctionResponse":{"type":"object","properties":{"message":{"type":"string","description":"Status message","example":"Function deleted successfully"}},"required":["message"]},"FunctionVersion":{"type":"object","properties":{"id":{"type":"string","description":"Version UUID"},"functionId":{"type":"string","description":"Function ID"},"version":{"type":"number","description":"Version number","example":1},"code":{"type":"string","description":"Source code (frozen)"},"entrypoint":{"type":"string","description":"Entrypoint function name"},"status":{"type":"string","description":"Build status","enum":["building","ready","failed"]},"buildLogs":{"type":"string","description":"Build logs output"},"buildError":{"type":"string","description":"Build error message"},"runtime":{"type":"string","description":"Runtime environment","enum":["nodejs20","nodejs22"]},"timeout":{"type":"number","description":"Execution timeout in ms"},"memory":{"type":"number","description":"Memory limit in MB"},"publishedBy":{"type":"string","description":"User who published this version"},"changelog":{"type":"string","description":"Changelog description"},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp"}},"required":["id","functionId","version","code","entrypoint","status","runtime","timeout","memory","createdAt"]},"PublishFunctionRequest":{"type":"object","properties":{"changelog":{"type":"string","description":"Changelog/description of changes"}}},"PublishFunctionResponse":{"type":"object","properties":{"version":{"description":"The published version","allOf":[{"$ref":"#/components/schemas/FunctionVersion"}]},"message":{"type":"string","description":"Status message","example":"Version 1 published successfully"}},"required":["version","message"]},"DeployFunctionResponse":{"type":"object","properties":{"deployment":{"description":"The deployment","allOf":[{"$ref":"#/components/schemas/FunctionDeployment"}]},"invokeUrl":{"type":"string","description":"Public invoke URL","example":"https://ots.odin.4players.io/invoke/proj123/my-function"},"message":{"type":"string","description":"Status message","example":"Deployment started"}},"required":["deployment","invokeUrl","message"]},"StopFunctionResponse":{"type":"object","properties":{"message":{"type":"string","description":"Status message","example":"Function stopped successfully"}},"required":["message"]},"VoiceSettings":{"type":"object","properties":{"peerLimit":{"type":"number","description":"Maximum number of concurrent peers. 0 = unlimited."},"accessKeysCount":{"type":"number","description":"Number of access keys created for this project"},"hostingType":{"type":"string","description":"Hosting type of the project (e.g. \"hosted\", \"on-premise\")"},"permissions":{"description":"Permission flags for the current user","allOf":[{"$ref":"#/components/schemas/ProjectPermissions"}]}},"required":["peerLimit","accessKeysCount"]},"OdinAccessKey":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the access key"},"name":{"type":"string","description":"Human-readable name of the access key"},"description":{"type":"string","description":"Optional description of the access key"},"pubKey":{"type":"string","description":"The public key (base64-encoded, 44 characters)"},"keyId":{"type":"string","description":"Short identifier derived from the public key"},"created":{"type":"string","description":"ISO 8601 creation timestamp"},"updated":{"type":"string","description":"ISO 8601 last-update timestamp"}},"required":["id","name","pubKey","keyId"]},"CreateAccessKeyRequest":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable name for the new access key"},"description":{"type":"string","description":"Optional description for the access key"}},"required":["name"]},"CreateAccessKeyResponse":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the access key"},"name":{"type":"string","description":"Human-readable name of the access key"},"description":{"type":"string","description":"Optional description of the access key"},"pubKey":{"type":"string","description":"The public key (base64-encoded, 44 characters)"},"keyId":{"type":"string","description":"Short identifier derived from the public key"},"created":{"type":"string","description":"ISO 8601 creation timestamp"},"updated":{"type":"string","description":"ISO 8601 last-update timestamp"},"accessKey":{"type":"string","description":"The one-time access key string. Copy this immediately — it cannot be retrieved again."}},"required":["id","name","pubKey","keyId","accessKey"]},"EditAccessKeyRequest":{"type":"object","properties":{"name":{"type":"string","description":"Updated name for the access key"},"description":{"type":"string","description":"Updated description for the access key"}},"required":["name"]},"PeersOverTime":{"type":"object","properties":{"peak":{"type":"array","description":"Peak concurrent users over time. Each entry is [timestamp_ms, count].","items":{"type":"array","items":{"type":"number"}}},"average":{"type":"array","description":"Average concurrent users over time. Each entry is [timestamp_ms, count].","items":{"type":"array","items":{"type":"number"}}}},"required":["peak","average"]},"RoomsOverTime":{"type":"object","properties":{"peak":{"type":"array","description":"Peak active rooms over time. Each entry is [timestamp_ms, count].","items":{"type":"array","items":{"type":"number"}}},"average":{"type":"array","description":"Average active rooms over time. Each entry is [timestamp_ms, count].","items":{"type":"array","items":{"type":"number"}}}},"required":["peak","average"]},"UpdatePeerLimitRequest":{"type":"object","properties":{"peerLimit":{"type":"number","description":"Maximum number of concurrent peers. 0 = unlimited."}},"required":["peerLimit"]}}}}