openapi: 3.0.0 info: title: PipesHub API description: | Unified API documentation for PipesHub services. PipesHub is an enterprise-grade platform providing: - User authentication and management - Document storage and version control - Knowledge base management - Enterprise search and conversational AI - Third-party integrations via connectors - System configuration management - Crawling job scheduling - Email services ## Authentication Most endpoints require JWT Bearer token authentication. Some internal endpoints use scoped tokens for service-to-service communication. **OAuth 2.0 Bearer tokens** from `POST /oauth2/token` use the same `Authorization: Bearer` header. For **`client_credentials`**, machine tokens may encode `userId === client_id` in the JWT; the **Node API gateway** resolves the OAuth **app creator** and sets the authenticated user accordingly. See the **OAuth Provider** tag for full behavior. ## Base URLs All endpoints use the `/api/v1` prefix unless otherwise noted. version: 1.0.0 contact: name: API Support email: support@pipeshub.com servers: - url: '{instance_url}/api/v1' description: Base API URL variables: instance_url: default: https://app.pipeshub.com description: Base server URL (without /api/v1) - url: '{instance_url}' description: Root URL (used for MCP endpoints mounted at /mcp) variables: instance_url: default: https://app.pipeshub.com description: Base server URL tags: - name: User Account description: User authentication including multi-step MFA, password reset, OTP login, and token management - name: Organization Auth Config description: Admin configuration of authentication methods including MFA steps and allowed providers - name: OAuth Provider description: | PipesHub OAuth 2.0 Authorization Server implementing RFC 6749, RFC 7636 (PKCE), and OpenID Connect. **Supported Grant Types:** - `authorization_code` - Standard OAuth flow with PKCE support - `client_credentials` - Machine-to-machine authentication - `refresh_token` - Token refresh for long-lived access **Security Features:** - PKCE (Proof Key for Code Exchange) for public clients - State parameter for CSRF protection - Configurable token lifetimes - Token revocation and introspection **OpenID Connect:** - ID tokens with standard claims - UserInfo endpoint for profile data - Discovery endpoint for automatic configuration **Machine tokens (`client_credentials`) — gateway and downstream identity:** Access tokens may encode **`userId === client_id`**. The **Node.js API gateway** resolves the effective user to the OAuth **app creator**: first using the JWT **`createdBy`** claim when present, otherwise by loading the OAuth app by **`client_id`** from the registry. After verification it sets the authenticated session to that creator. **Python services:** Validate `Authorization: Bearer` as today and use the JWT payload’s **`userId`** as-is for scopes and user-scoped logic (which may still equal **`client_id`** for machine tokens). **Operational note:** Prefer tokens whose JWT already carries the creator as **`userId`**; use **`POST /oauth-clients/{appId}/revoke-all-tokens`** and obtain new tokens from **`POST /oauth2/token`** when rotating integrations. - name: OAuth Apps description: | Manage OAuth 2.0 client applications registered with PipesHub. OAuth apps allow third-party applications to access PipesHub APIs on behalf of users or organizations. Each app receives a client ID and secret for authentication. **Who can see which apps** - **Everyone (including org admins)** sees and manages only OAuth apps **they created** (`createdBy`). Other members' apps are hidden (not listed; individual operations return not found). **Who authorizes vs. client credentials** - **Authorization code:** Any authenticated user in the workspace may complete consent for a valid `client_id`; issued tokens represent **that user**. - **Client credentials:** Access tokens represent the **OAuth app creator** (who registered the client), not the caller. **Scopes** - `GET /oauth-clients/scopes` returns scopes grouped by category for the **signed-in user's role**. - **Org admins** may register apps that request additional **admin-only** scopes; non-admins cannot select those scopes when creating or updating an app. **App Types:** - **Confidential clients**: Server-side apps that can securely store secrets - **Public clients**: Browser/mobile apps that cannot securely store secrets (use PKCE) **App Lifecycle:** - Create apps with name, redirect URIs, allowed scopes, and optional URLs (homepage, privacy, terms) - Regenerate secrets if compromised - Suspend/activate apps to control access - Revoke all tokens for emergency access removal - name: OpenID Connect description: | OpenID Connect 1.0 endpoints for identity federation and discovery. **Discovery:** - `/.well-known/openid-configuration` - Authorization server metadata - `/.well-known/oauth-authorization-server` - Authorization server metadata (RFC 8414) - `/.well-known/oauth-protected-resource/mcp` - Protected resource metadata (RFC 9728) - `/.well-known/jwks.json` - Public keys for token verification **UserInfo:** - `/oauth2/userinfo` - Get authenticated user's profile information **Supported Claims:** - `user_id` - User identifier - `email`, `email_verified` - Email information - `name`, `given_name`, `family_name` - Name information - name: Organizations description: Organization management operations - name: Knowledge Base description: Knowledge base management operations - name: Knowledge Hub description: Unified browse API for root and child nodes (apps, record groups, folders, records) with filtering and search - name: Conversations description: AI-powered conversational chat management with citations and follow-up questions - name: Semantic Search description: Enterprise semantic search across all indexed knowledge with relevance scoring - name: Agents description: Custom AI agents with specialized capabilities and tool integrations - name: AI Models Providers description: Manage individual AI model providers - add, update, delete, and set defaults. - name: Web Search description: Manage web search providers (DuckDuckGo, Serper, Tavily, Exa) and settings for internet search. components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: JWT Bearer token for authenticated requests scopedToken: type: http scheme: bearer bearerFormat: JWT description: | Scoped JWT token for service-to-service authentication. Format: "Bearer {scoped_token}" Required scopes vary by endpoint. oauth2: type: oauth2 description: | OAuth 2.0 authentication with fine-grained scopes. Supports authorization_code (with PKCE) and client_credentials flows. OAuth tokens are Bearer JWTs — use the same Authorization header as regular tokens. For **client_credentials**, machine JWTs may use `userId === client_id`; the Node gateway resolves the OAuth app creator — see **OAuth Provider** tag. flows: authorizationCode: authorizationUrl: /api/v1/oauth2/authorize tokenUrl: /api/v1/oauth2/token refreshUrl: /api/v1/oauth2/token scopes: openid: OpenID Connect authentication profile: User profile information email: User email address offline_access: Offline access (refresh tokens) org:read: Read organization information org:write: Update organization settings org:admin: Full organization administration user:read: Read user profiles user:write: Update user profiles user:invite: Invite new users user:delete: Delete users usergroup:read: Read user groups usergroup:write: Create and manage user groups team:read: Read team information team:write: Create and manage teams kb:read: Read knowledge bases and records kb:write: Create and update knowledge bases kb:delete: Delete knowledge bases and records kb:upload: Upload files to knowledge bases semantic:read: Read semantic search results and history semantic:write: Execute semantic search semantic:delete: Delete semantic search history conversation:read: Read conversations conversation:write: Create and manage conversations conversation:chat: Send messages in conversations agent:read: Read AI agents agent:write: Create and manage AI agents agent:execute: Execute AI agents connector:read: Read connector configurations connector:write: Create and update connectors connector:sync: Trigger connector synchronization connector:delete: Delete connectors config:read: Read system configuration config:write: Update system configuration crawl:read: Read crawling jobs crawl:write: Create and manage crawling jobs crawl:delete: Delete crawling jobs clientCredentials: tokenUrl: /api/v1/oauth2/token scopes: openid: OpenID Connect authentication profile: User profile information email: User email address offline_access: Offline access (refresh tokens) org:read: Read organization information org:write: Update organization settings org:admin: Full organization administration user:read: Read user profiles user:write: Update user profiles user:invite: Invite new users user:delete: Delete users usergroup:read: Read user groups usergroup:write: Create and manage user groups team:read: Read team information team:write: Create and manage teams kb:read: Read knowledge bases and records kb:write: Create and update knowledge bases kb:delete: Delete knowledge bases and records kb:upload: Upload files to knowledge bases semantic:write: Execute semantic search semantic:read: Read semantic search results and history semantic:delete: Delete semantic search history conversation:read: Read conversations conversation:write: Create and manage conversations conversation:chat: Send messages in conversations agent:read: Read AI agents agent:write: Create and manage AI agents agent:execute: Execute AI agents connector:read: Read connector configurations connector:write: Create and update connectors connector:sync: Trigger connector synchronization connector:delete: Delete connectors config:read: Read system configuration config:write: Update system configuration crawl:read: Read crawling jobs crawl:write: Create and manage crawling jobs schemas: AuthMethod: type: object additionalProperties: false description: Authentication method configuration properties: type: type: string enum: - samlSso - otp - password - google - microsoft - azureAd - oauth description: | Type of authentication method: - `password`: Email/password authentication - `otp`: One-time password via email (6-digit, expires in 10 minutes) - `google`: Google OAuth 2.0 - `microsoft`: Microsoft OAuth 2.0 - `azureAd`: Azure Active Directory - `samlSso`: SAML 2.0 Single Sign-On - `oauth`: Generic OAuth 2.0 provider required: - type AuthStep: type: object additionalProperties: false description: A single step in multi-factor authentication flow properties: order: type: integer description: Order of the authentication step (1-3, must be unique across steps) minimum: 1 maximum: 3 allowedMethods: type: array items: $ref: '#/components/schemas/AuthMethod' description: List of allowed authentication methods for this step. User can choose any one method from this list. minItems: 1 required: - order - allowedMethods AuthConfig: type: object additionalProperties: false description: | Organization authentication configuration. Supports 1-3 authentication steps for multi-factor authentication. **Validation Rules:** - Minimum 1 step, maximum 3 steps - Each step must have unique order - No duplicate methods within the same step - No method can appear in multiple steps properties: authMethods: type: array items: $ref: '#/components/schemas/AuthStep' description: List of authentication steps in order minItems: 1 maxItems: 3 required: - authMethods UpdateAuthMethodResponse: type: object additionalProperties: false description: Response after updating organization authentication methods properties: message: type: string example: Auth method updated authMethod: type: array description: Updated authentication steps (same shape as request body) items: $ref: '#/components/schemas/AuthStep' required: - message - authMethod OrgAuthConfigSetupResponse: type: object additionalProperties: false description: Response from setting up organization auth configuration properties: message: type: string required: - message InitAuthRequest: type: object additionalProperties: false description: | Optional JSON body for `/userAccount/initAuth`. Valid shapes include: omitting the body entirely, sending `{}` (empty object), or `{ "email": "
" }`. Neither the body nor `email` is required. When `email` is omitted or empty, the session is still created and `allowedMethods` / `authProviders` are returned as usual; clients typically supply `email` later on `/userAccount/authenticate`. The `email` property remains supported mainly for legacy clients and backward compatibility. properties: email: type: string format: email description: | Optional; retained for legacy reasons. When set, stored on the auth session for correlation with later `/authenticate` calls (RFC 5321 compliant address). example: user@example.com InitAuthResponse: type: object additionalProperties: false description: Response containing available authentication methods and session info properties: currentStep: type: integer description: Current authentication step (0-indexed). Always 0 for initial response. example: 0 allowedMethods: type: array items: type: string enum: - samlSso - otp - password - google - microsoft - azureAd - oauth description: List of allowed authentication methods for the current step example: - password - google - otp message: type: string description: Response message example: Authentication initialized authProviders: $ref: '#/components/schemas/AuthProviders' jitEnabled: type: boolean description: True when at least one allowed external provider has JIT provisioning enabled required: - currentStep - allowedMethods - message - authProviders - jitEnabled AuthProviderGooglePublicConfig: type: object additionalProperties: false description: Public Google OAuth settings returned to clients properties: clientId: type: string description: Google OAuth client ID enableJit: type: boolean description: Whether just-in-time user provisioning is enabled for Google AuthProviderMicrosoftPublicConfig: type: object additionalProperties: false description: Public Microsoft OAuth settings returned to clients properties: tenantId: type: string description: Microsoft tenant ID clientId: type: string description: Microsoft OAuth client ID enableJit: type: boolean description: Whether just-in-time user provisioning is enabled for Microsoft AuthProviderAzureAdPublicConfig: type: object additionalProperties: false description: Public Azure AD OAuth settings returned to clients properties: tenantId: type: string description: Azure AD tenant ID clientId: type: string description: Azure AD client ID enableJit: type: boolean description: Whether just-in-time user provisioning is enabled for Azure AD AuthProviderOAuthPublicConfig: type: object additionalProperties: false description: Public generic OAuth provider settings returned to clients properties: providerName: type: string description: Custom OAuth provider display name clientId: type: string description: OAuth client ID tokenEndpoint: type: string description: OAuth token endpoint URL authorizationUrl: type: string description: OAuth authorization URL clientSecret: type: string description: Client secret (omitted when stripped for public responses) userInfoEndpoint: type: string description: UserInfo endpoint URL scope: type: string description: Default OAuth scopes enableJit: type: boolean description: Whether just-in-time user provisioning is enabled for this provider required: - providerName - clientId - tokenEndpoint - authorizationUrl AuthProviders: type: object additionalProperties: false description: Configuration for external authentication providers (returned when those methods are allowed) properties: google: $ref: '#/components/schemas/AuthProviderGooglePublicConfig' microsoft: $ref: '#/components/schemas/AuthProviderMicrosoftPublicConfig' azuread: $ref: '#/components/schemas/AuthProviderAzureAdPublicConfig' oauth: $ref: '#/components/schemas/AuthProviderOAuthPublicConfig' saml: type: object description: Present when SAML SSO is an allowed method; may be an empty object additionalProperties: true AuthenticateRequest: type: object additionalProperties: false description: | Request to authenticate using specified method. **Credential format varies by method:** - `password`: `{ password: "string" }` - `otp`: `{ otp: "123456" }` (6-digit code) - `google`: `"google-id-token-string"` - `microsoft`: `{ accessToken: "...", idToken: "..." }` - `azureAd`: `{ accessToken: "...", idToken: "..." }` - `oauth`: `{ accessToken: "...", idToken: "..." }` - `samlSso`: handled via redirect flow properties: method: type: string enum: - samlSso - otp - password - google - microsoft - azureAd - oauth description: Authentication method to use credentials: oneOf: - $ref: '#/components/schemas/PasswordCredentials' - $ref: '#/components/schemas/OtpCredentials' - $ref: '#/components/schemas/OAuthCredentials' - type: string description: Google ID token (for google method) description: Credentials based on the authentication method email: type: string format: email description: Optional email for verification (used with some OAuth methods) cf-turnstile-response: type: string description: Cloudflare Turnstile CAPTCHA token (optional, if CAPTCHA is enabled) required: - method - credentials PasswordCredentials: type: object additionalProperties: false description: Credentials for password authentication properties: password: type: string description: User password format: password required: - password OtpCredentials: type: object additionalProperties: false description: Credentials for OTP authentication properties: otp: type: string description: 6-digit one-time password pattern: ^\d{6}$ example: '123456' required: - otp OAuthCredentials: type: object additionalProperties: false description: Credentials for OAuth authentication (Microsoft, Azure AD, generic OAuth) properties: accessToken: type: string description: OAuth access token idToken: type: string description: OAuth ID token (JWT) required: - accessToken AuthenticateMultiStepResponse: type: object additionalProperties: false description: Current authentication step succeeded; additional MFA steps remain properties: status: type: string enum: - success description: Step completion status nextStep: type: integer description: Next authentication step index allowedMethods: type: array items: type: string description: Allowed method types for the next step authProviders: $ref: '#/components/schemas/AuthProviders' required: - status - nextStep - allowedMethods - authProviders AuthenticateFinalResponse: type: object additionalProperties: false description: All authentication steps complete; JWT tokens returned properties: message: type: string description: Success message example: Fully authenticated accessToken: type: string description: JWT access token (1 hour expiry) refreshToken: type: string description: JWT refresh token (7 days expiry) required: - message - accessToken - refreshToken AuthenticateResponse: oneOf: - $ref: '#/components/schemas/AuthenticateMultiStepResponse' - $ref: '#/components/schemas/AuthenticateFinalResponse' description: | Either the next step in a multi-factor flow (`status`, `nextStep`, `allowedMethods`, `authProviders`) or final tokens (`message`, `accessToken`, `refreshToken`). AuthenticatedPasswordResetResponse: type: object additionalProperties: false description: Response after authenticated user changes password (new access token issued) properties: data: type: string example: password reset accessToken: type: string description: New JWT access token after password change required: - data - accessToken RefreshTokenResponse: type: object additionalProperties: false description: Response with new access token properties: user: $ref: '#/components/schemas/RefreshTokenUser' accessToken: type: string description: New JWT access token (24 hour default expiry, configurable via ACCESS_TOKEN_EXPIRY) required: - user - accessToken RefreshTokenUser: type: object additionalProperties: false description: User record returned with a refreshed access token properties: _id: type: string description: User ID orgId: type: string description: Organization ID email: type: string format: email fullName: type: string firstName: type: string lastName: type: string designation: type: string hasLoggedIn: type: boolean isDeleted: type: boolean slug: type: string createdAt: type: string updatedAt: type: string __v: type: integer required: - _id - orgId - email - fullName - hasLoggedIn - isDeleted - slug - createdAt - updatedAt - __v OrgAuthConfigCreateRequest: type: object additionalProperties: false description: Request to create initial organization auth configuration properties: contactEmail: type: string format: email description: Organization contact email registeredName: type: string description: Organization registered name adminFullName: type: string description: Admin user full name sendEmail: type: boolean description: Whether to send welcome email default: false required: - contactEmail - registeredName - adminFullName ErrorResponse: type: object additionalProperties: false description: | Standard error envelope returned by all errors routed through `ErrorMiddleware`. Applies to all `BaseError` subclasses including `HttpError`, `ValidationError`, and others. The `code` field is a machine-readable string identifying the error type (e.g. `HTTP_UNAUTHORIZED`, `HTTP_NOT_FOUND`, `VALIDATION_ERROR`, `INTERNAL_ERROR`). properties: error: type: object additionalProperties: false required: - code - message properties: code: type: string description: | Machine-readable error code. For application errors it takes the form `HTTP_` For unhandled runtime errors (e.g. database unavailable) it is `INTERNAL_ERROR`. example: HTTP_BAD_REQUEST message: type: string description: Human-readable description of the error example: Admin access required metadata: type: object description: Additional context (only present in development environments) additionalProperties: true required: - error StreamRecordErrorResponse: type: object additionalProperties: false description: | Error payload returned by the legacy record-stream proxy when the downstream streaming request fails after route middleware has passed. required: - error properties: error: type: string description: Human-readable error message from the gateway or downstream stream service OAuthTokenRequest: type: object description: | OAuth 2.0 Token Request (RFC 6749 Section 4.1.3). Request body for exchanging authorization code or credentials for tokens. properties: grant_type: type: string enum: - authorization_code - client_credentials - refresh_token description: | OAuth grant type: - `authorization_code`: Exchange auth code for tokens - `client_credentials`: Machine-to-machine auth - `refresh_token`: Get new access token using refresh token code: type: string description: Authorization code (required for authorization_code grant) redirect_uri: type: string format: uri description: Redirect URI (required for authorization_code grant) client_id: type: string description: Client ID (can also be sent via Basic auth header) client_secret: type: string description: Client secret (can also be sent via Basic auth header) refresh_token: type: string description: Refresh token (required for refresh_token grant) scope: type: string description: Requested scopes (optional, defaults to original grant scopes) code_verifier: type: string description: | PKCE code verifier (RFC 7636). Required if code_challenge was used. Must be 43-128 characters from [A-Za-z0-9-._~] pattern: ^[A-Za-z0-9\-._~]{43,128}$ required: - grant_type OAuthTokenResponse: type: object description: | OAuth 2.0 Token Response (RFC 6749 Section 5.1). Contains the access token and optional refresh/ID tokens. properties: access_token: type: string description: The access token for API requests token_type: type: string example: Bearer description: Token type (always "Bearer") expires_in: type: integer description: Access token lifetime in seconds example: 3600 refresh_token: type: string description: Refresh token for obtaining new access tokens scope: type: string description: Granted scopes (may differ from requested) id_token: type: string description: OpenID Connect ID token (JWT) if openid scope was requested OAuthRevokeRequest: type: object description: | OAuth 2.0 Token Revocation Request (RFC 7009). Revokes an access or refresh token. properties: token: type: string description: The token to revoke token_type_hint: type: string enum: - access_token - refresh_token description: Hint about token type (optional, improves performance) client_id: type: string description: Client ID client_secret: type: string description: Client secret required: - token - client_id OAuthIntrospectRequest: type: object description: | OAuth 2.0 Token Introspection Request (RFC 7662). Check if a token is active and get its metadata. properties: token: type: string description: The token to introspect token_type_hint: type: string enum: - access_token - refresh_token description: Hint about token type client_id: type: string description: Client ID client_secret: type: string description: Client secret required: - token - client_id OAuthIntrospectResponse: type: object description: | OAuth 2.0 Token Introspection Response (RFC 7662). Contains token metadata if active, or just `active: false` if not. properties: active: type: boolean description: Whether the token is currently active scope: type: string description: Scopes granted to the token client_id: type: string description: Client ID the token was issued to username: type: string description: User identifier (if user-based token) token_type: type: string description: Token type exp: type: integer description: Token expiration timestamp (Unix epoch) iat: type: integer description: Token issuance timestamp (Unix epoch) nbf: type: integer description: Token not-before timestamp (Unix epoch) user_id: type: string description: User ID aud: type: string description: Audience (client ID) iss: type: string description: Issuer URL jti: type: string description: Unique token identifier required: - active OAuthErrorResponse: type: object description: | OAuth 2.0 Error Response (RFC 6749 Section 5.2). Standard error format for OAuth endpoints. properties: error: type: string description: | Error code. Common values: - `invalid_request` - Missing or invalid parameter - `invalid_client` - Client authentication failed - `invalid_grant` - Invalid authorization code or refresh token - `unauthorized_client` - Client not authorized for this grant type - `unsupported_grant_type` - Grant type not supported - `invalid_scope` - Requested scope is invalid or exceeds allowed - `access_denied` - User denied authorization enum: - invalid_request - invalid_client - invalid_grant - unauthorized_client - unsupported_grant_type - invalid_scope - access_denied - server_error error_description: type: string description: Human-readable error description error_uri: type: string format: uri description: URI with more information about the error state: type: string description: State parameter from the authorization request required: - error OAuthUserInfoResponse: type: object description: | OpenID Connect UserInfo Response. Contains claims about the authenticated user. properties: user_id: type: string description: User ID name: type: string description: Full name given_name: type: string description: First name family_name: type: string description: Last name email: type: string format: email description: Email address email_verified: type: boolean description: Whether email has been verified picture: type: string format: uri description: Profile picture URL updated_at: type: integer description: Last profile update timestamp (Unix epoch) required: - user_id CreateOAuthAppRequest: type: object description: | Request to create a new OAuth app (`createAppSchema` in `oauth.validators.ts`). **Required:** `name`, `allowedScopes`. **Optional:** `description`, `redirectUris`, `allowedGrantTypes`, `homepageUrl`, `privacyPolicyUrl`, `termsOfServiceUrl`, `isConfidential`, `accessTokenLifetime`, `refreshTokenLifetime`. **Redirect rule (Zod refine):** If the effective grant list includes `authorization_code` (including when `allowedGrantTypes` is omitted — defaults to `authorization_code` + `refresh_token`), at least one redirect URI is required. If grants exclude `authorization_code`, `redirectUris` may be omitted. properties: name: type: string description: App name (displayed to users during authorization) minLength: 1 maxLength: 100 example: My Integration App description: type: string description: App description maxLength: 500 example: Integrates PipesHub with our internal tools redirectUris: type: array items: type: string format: uri description: | Allowed redirect URIs (max 10). Required when an effective grant list includes `authorization_code` (including the default when `allowedGrantTypes` is omitted). maxItems: 10 example: - https://myapp.com/callback - http://localhost:3000/callback allowedGrantTypes: type: array items: type: string enum: - authorization_code - client_credentials - refresh_token description: | Allowed grant types. Defaults to `["authorization_code", "refresh_token"]` if omitted (applied by the service, not Zod). example: - authorization_code - refresh_token allowedScopes: type: array items: type: string description: Scopes the app can request (non-empty) minItems: 1 example: - openid - profile - read:records homepageUrl: type: string format: uri description: App homepage URL (shown during authorization) privacyPolicyUrl: type: string format: uri description: Privacy policy URL termsOfServiceUrl: type: string format: uri description: Terms of service URL isConfidential: type: boolean description: | Whether the app can securely store secrets. - `true`: Server-side app (secret required for token requests) - `false`: Browser/mobile app (must use PKCE) default: true accessTokenLifetime: type: integer description: Access token lifetime in seconds (300–86400) minimum: 300 maximum: 86400 default: 3600 example: 3600 refreshTokenLifetime: type: integer description: Refresh token lifetime in seconds (3600–31536000) minimum: 3600 maximum: 31536000 default: 2592000 example: 2592000 required: - name - allowedScopes UpdateOAuthAppRequest: type: object description: | Request to update an OAuth app (`updateAppSchema` in `oauth.validators.ts`). All fields are optional — include only fields that should change. URL fields (`homepageUrl`, `privacyPolicyUrl`, `termsOfServiceUrl`) accept `null` to clear them (nullable in Zod). **Redirect rule (Zod refine):** If `allowedGrantTypes` includes `authorization_code` and `redirectUris` is present in the body, `redirectUris` must contain at least one URI. properties: name: type: string description: App name minLength: 1 maxLength: 100 description: type: string description: App description maxLength: 500 redirectUris: type: array items: type: string format: uri description: | Allowed redirect URIs (up to 10). Required when `authorization_code` grant type is enabled. Preserved in the database even if `authorization_code` is removed from grant types. maxItems: 10 allowedGrantTypes: type: array items: type: string enum: - authorization_code - client_credentials - refresh_token allowedScopes: type: array items: type: string minItems: 1 homepageUrl: type: string format: uri nullable: true privacyPolicyUrl: type: string format: uri nullable: true termsOfServiceUrl: type: string format: uri nullable: true accessTokenLifetime: type: integer minimum: 300 maximum: 86400 refreshTokenLifetime: type: integer minimum: 3600 maximum: 31536000 OAuthAppResponse: type: object description: | OAuth app details (without secret). Fields under `required:` always appear in `toAppResponse` (`oauth.app.service.ts`); optional URL/description fields are only present when set by the caller. required: - id - slug - clientId - name - redirectUris - allowedGrantTypes - allowedScopes - status - isConfidential - accessTokenLifetime - refreshTokenLifetime - createdAt - updatedAt properties: id: type: string description: App ID slug: type: string description: URL-friendly app slug clientId: type: string description: OAuth client ID name: type: string description: App name description: type: string description: App description redirectUris: type: array items: type: string format: uri description: Allowed redirect URIs (always returned; may be empty) allowedGrantTypes: type: array items: type: string description: Allowed grant types allowedScopes: type: array items: type: string description: Allowed scopes status: type: string enum: - active - suspended - revoked description: App status homepageUrl: type: string format: uri description: App homepage privacyPolicyUrl: type: string format: uri description: Privacy policy URL termsOfServiceUrl: type: string format: uri description: Terms of service URL isConfidential: type: boolean description: Whether app is a confidential client accessTokenLifetime: type: integer description: Access token lifetime in seconds refreshTokenLifetime: type: integer description: Refresh token lifetime in seconds createdAt: type: string format: date-time description: Creation timestamp updatedAt: type: string format: date-time description: Last update timestamp OAuthAppWithSecret: allOf: - $ref: '#/components/schemas/OAuthAppResponse' - type: object properties: clientSecret: type: string description: | Client secret (only shown on creation and secret regeneration). Store this securely - it cannot be retrieved later. required: - clientSecret CreateOAuthAppResponse: type: object description: | Response body for `POST /oauth-clients` (`oauth.app.controller.ts` `createApp`). The new app (including one-time `clientSecret`) is nested under `app`. required: - message - app properties: message: type: string example: OAuth app created successfully app: $ref: '#/components/schemas/OAuthAppWithSecret' RegenerateOAuthAppSecretResponse: type: object description: | Response body for `POST /oauth-clients/{appId}/regenerate-secret` (`regenerateSecret`). required: - message - clientId - clientSecret properties: message: type: string example: Client secret regenerated successfully clientId: type: string description: OAuth client ID (unchanged) clientSecret: type: string description: New client secret (store securely; previous secret is invalidated) UpdateOAuthAppResponse: type: object description: | Response body for `PUT /oauth-clients/{appId}` (`oauth.app.controller.ts` `updateApp`). Updated app (never includes `clientSecret`) is nested under `app`. required: - message - app properties: message: type: string example: OAuth app updated successfully app: $ref: '#/components/schemas/OAuthAppResponse' SuspendOAuthAppResponse: type: object description: | Response body for `POST /oauth-clients/{appId}/suspend` (`oauth.app.controller.ts` `suspendApp`). Suspended app (never includes `clientSecret`) is nested under `app`. required: - message - app properties: message: type: string example: OAuth app suspended successfully app: $ref: '#/components/schemas/OAuthAppResponse' ActivateOAuthAppResponse: type: object description: | Response body for `POST /oauth-clients/{appId}/activate` (`oauth.app.controller.ts` `activateApp`). Re-activated app (never includes `clientSecret`) is nested under `app`. required: - message - app properties: message: type: string example: OAuth app activated successfully app: $ref: '#/components/schemas/OAuthAppResponse' OAuthAppListResponse: type: object description: Paginated list of OAuth apps required: - data - pagination properties: data: type: array items: $ref: '#/components/schemas/OAuthAppResponse' description: List of OAuth apps pagination: type: object required: - page - limit - total - totalPages properties: page: type: integer description: Current page number limit: type: integer description: Items per page total: type: integer description: Total number of items totalPages: type: integer description: Total number of pages OAuthScopeInfo: type: object description: Information about an OAuth scope properties: name: type: string description: Scope identifier example: openid description: type: string description: Human-readable scope description example: OpenID Connect authentication category: type: string description: Scope category for grouping (matches the key under `scopes` on list responses) example: Identity requiresUserConsent: type: boolean description: Whether end-user consent is required when this scope is requested example: false required: - name - description - category - requiresUserConsent OAuthScopesGroupedResponse: type: object description: | OAuth scopes available to the signed-in user for app registration, grouped by category label. Category keys are UI labels (e.g. `Identity`, `Knowledge Base`); each maps to a list of scopes in that group. Categories defined in server config may appear with an **empty array** when every scope in that category is restricted for the caller's role (e.g. non–org-admin users never receive admin-only scopes). properties: scopes: type: object description: Map of category display name to scopes in that category additionalProperties: type: array items: $ref: '#/components/schemas/OAuthScopeInfo' required: - scopes OAuthClientManagementRateLimitError: type: object description: JSON body when OAuth client management routes exceed the per-minute rate limit (same limiter as other `/oauth-clients/*` routes). required: - error properties: error: type: object required: - code - message properties: code: type: string example: TOO_MANY_REQUESTS message: type: string example: Too many OAuth client requests. Please try again later. retryAfter: type: integer nullable: true description: Seconds until the limit window resets (when `Retry-After` is present); may be null. ApplicationJsonErrorResponse: type: object description: | Standard JSON error envelope from `ErrorMiddleware` for `BaseError` subclasses (`error.middleware.ts`). Returned for most API 4xx errors (unauthorized, forbidden, not found, validation failures, etc.). required: - error properties: error: type: object required: - code - message properties: code: type: string description: Machine-readable code (e.g. `HTTP_UNAUTHORIZED`, `HTTP_FORBIDDEN`). message: type: string metadata: type: object description: Optional; may appear in non-production for some errors. additionalProperties: true OAuthTokenListItem: type: object description: | Information about an issued token (one element returned by `listTokensForApp` in `oauth_token.service.ts`). `userId` is omitted for client-credentials access tokens; all other fields are always populated. required: - id - tokenType - scopes - createdAt - expiresAt - isRevoked properties: id: type: string description: Token ID tokenType: type: string enum: - access - refresh description: Type of token userId: type: string description: User ID (omitted for client-credentials access tokens) scopes: type: array items: type: string description: Granted scopes createdAt: type: string format: date-time description: Token creation time expiresAt: type: string format: date-time description: Token expiration time isRevoked: type: boolean description: Whether token has been revoked OAuthAppTokensListResponse: type: object description: | Response body for `GET /oauth-clients/{appId}/tokens` (`listAppTokens`). required: - tokens properties: tokens: type: array items: $ref: '#/components/schemas/OAuthTokenListItem' description: Active access and refresh tokens for the app Address: type: object additionalProperties: false properties: _id: type: string format: ObjectId description: Optional address document id addressLine1: type: string description: Address line 1 city: type: string description: City state: type: string description: State/Province postCode: type: string description: Postal/ZIP code country: type: string description: Country Organization: type: object properties: _id: type: string format: ObjectId description: Unique organization identifier slug: type: string description: Unique slug for the organization registeredName: type: string description: Registered name shortName: type: string description: Short name or display name domain: type: string description: Organization domain contactEmail: type: string format: email description: Contact email address accountType: type: string enum: - individual - business description: Type of account permanentAddress: $ref: '#/components/schemas/Address' onBoardingStatus: type: string enum: - configured - notConfigured - skipped description: Onboarding status isDeleted: type: boolean description: Soft delete flag default: false __v: type: integer description: Document version (MongoDB) createdAt: type: string format: date-time description: Creation timestamp (ISO 8601) updatedAt: type: string format: date-time description: Last update timestamp (ISO 8601) required: - _id - slug - registeredName - domain - contactEmail - accountType - onBoardingStatus - isDeleted - createdAt - updatedAt - __v KnowledgeBaseCreateResponse: type: object additionalProperties: false description: Response returned when a knowledge base is created properties: id: type: string description: Knowledge base ID name: type: string description: Knowledge base name createdAtTimestamp: type: integer format: int64 description: Creation timestamp in milliseconds updatedAtTimestamp: type: integer format: int64 description: Last update timestamp in milliseconds userRole: type: string enum: - OWNER - WRITER - READER description: User's role in this knowledge base required: - id - name - createdAtTimestamp - updatedAtTimestamp - userRole FolderCreateResponseSchema: type: object additionalProperties: false description: Response returned when a folder is created (root or nested subfolder) properties: id: type: string description: Unique folder identifier name: type: string description: Name of the folder required: - id - name FolderUpdateResponseSchema: type: object additionalProperties: false description: Response returned by PUT /knowledgeBase/{kbId}/folder/{folderId} (updateFolder). required: - success - message properties: success: type: boolean example: true message: type: string example: Folder updated successfully FolderDeleteResponseSchema: type: object additionalProperties: false description: Response returned by DELETE /knowledgeBase/{kbId}/folder/{folderId} (deleteFolder). required: - success - message properties: success: type: boolean example: true message: type: string example: Folder deleted successfully KnowledgeBaseMoveRecordRequestBody: type: object additionalProperties: false description: Request body for PUT /knowledgeBase/{kbId}/record/{recordId}/move (moveRecord). required: - newParentId properties: newParentId: type: string nullable: true description: Target folder ID, or null to move the record to the knowledge base root KnowledgeBaseMoveRecordResponse: type: object additionalProperties: false description: Response returned by PUT /knowledgeBase/{kbId}/record/{recordId}/move (moveRecord). required: - success - message properties: success: type: boolean example: true message: type: string example: Record moved successfully GetAllKnowledgeBaseResponseSchema: type: object additionalProperties: false description: Response returned by GET /knowledgeBase (listKnowledgeBases). required: - knowledgeBases - pagination - filters properties: knowledgeBases: type: array items: type: object additionalProperties: false required: - id - name - connectorId - createdAtTimestamp - updatedAtTimestamp - createdBy - userRole - folders properties: id: type: string name: type: string connectorId: type: string nullable: true createdAtTimestamp: type: integer format: int64 updatedAtTimestamp: type: integer format: int64 createdBy: type: string userRole: type: string enum: - OWNER - WRITER - READER folders: type: array items: type: object additionalProperties: false required: - id - name properties: id: type: string name: type: string createdAtTimestamp: type: integer format: int64 path: type: string pagination: type: object additionalProperties: false required: - page - limit - totalCount - totalPages - hasNext - hasPrev properties: page: type: integer limit: type: integer totalCount: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean filters: type: object additionalProperties: false required: - applied - available properties: applied: type: object additionalProperties: false description: | Active filters. Empty `{}` when defaults. Keys use snake_case for sort fields (backend convention in kb_service.py). properties: search: type: string permissions: type: array items: type: string enum: - OWNER - WRITER - READER sort_by: type: string enum: - name - createdAtTimestamp - updatedAtTimestamp - userRole sort_order: type: string enum: - asc - desc available: type: object additionalProperties: false required: - permissions - sortFields - sortOrders properties: permissions: type: array items: type: string enum: - OWNER - WRITER - READER sortFields: type: array items: type: string enum: - name - createdAtTimestamp - updatedAtTimestamp - userRole sortOrders: type: array items: type: string enum: - asc - desc GetKnowledgeBaseById: type: object additionalProperties: false description: Response returned by GET /knowledgeBase/{kbId} (getKnowledgeBase). required: - id - name - connectorId - createdAtTimestamp - updatedAtTimestamp - createdBy - userRole - folders properties: id: type: string description: Knowledge base ID name: type: string description: Knowledge base name connectorId: type: string nullable: true description: Associated connector ID (null for manual KBs) createdAtTimestamp: type: integer format: int64 description: Creation timestamp in milliseconds updatedAtTimestamp: type: integer format: int64 description: Last update timestamp in milliseconds createdBy: type: string description: User ID of the creator userRole: type: string enum: - OWNER - WRITER - READER description: User's role in this knowledge base folders: type: array description: Root-level folders in this knowledge base items: type: object additionalProperties: false required: - id - name properties: id: type: string description: Folder ID name: type: string description: Folder name createdAtTimestamp: type: integer format: int64 description: Creation timestamp in milliseconds UpdateKnowledgeBaseById: type: object additionalProperties: false description: Response returned by PUT /knowledgeBase/{kbId} (updateKnowledgeBase). required: - success - message properties: success: type: boolean example: true message: type: string example: Knowledge base updated successfully DeleteKnowledgeBaseById: type: object additionalProperties: false description: Response returned by DELETE /knowledgeBase/{kbId} (deleteKnowledgeBase). required: - success - message properties: success: type: boolean example: true message: type: string example: Knowledge base deleted successfully RecordTypeEnum: type: string description: | Type of content. Mirrors the backend `RecordType` enum (`backend/python/app/models/entities.py`); connector-sourced records may use any of the connector-specific types below. - FILE: Uploaded or synced documents (PDF, DOCX, etc.) - DRIVE: Drive/folder container (Google Drive, OneDrive, etc.) - WEBPAGE: Web pages crawled or bookmarked - DATABASE: Database object (e.g. Notion database) - DATASOURCE: Data source object - MESSAGE: Chat/messaging content (Slack, Teams) - MAIL: Email messages (Gmail, Outlook) - GROUP_MAIL: Group/shared mailbox email messages - TICKET: Support/issue tickets (Jira, ServiceNow) - COMMENT: Comments from collaboration tools - INLINE_COMMENT: Inline comments anchored to content (e.g. Confluence) - CONFLUENCE_PAGE: Confluence page - CONFLUENCE_BLOGPOST: Confluence blog post - SHAREPOINT_PAGE: SharePoint page - SHAREPOINT_LIST: SharePoint list - SHAREPOINT_LIST_ITEM: SharePoint list item - SHAREPOINT_DOCUMENT_LIBRARY: SharePoint document library - LINK: Web link / bookmark - PROJECT: Project entity (e.g. Jira project) - PULL_REQUEST: Source-control pull request - MEETING: Meeting record (e.g. Zoom) - PRODUCT: Product entity (CRM) - DEAL: Deal/opportunity entity (CRM) - CASE: Case entity (CRM/support) - TASK: Task entity - ARTIFACT: Generated/derived artifact - CODE_FILE: Source-code file - SQL_TABLE: SQL table object - SQL_VIEW: SQL view object - OTHERS: Miscellaneous content types enum: - FILE - DRIVE - WEBPAGE - DATABASE - DATASOURCE - MESSAGE - MAIL - GROUP_MAIL - TICKET - COMMENT - INLINE_COMMENT - CONFLUENCE_PAGE - CONFLUENCE_BLOGPOST - SHAREPOINT_PAGE - SHAREPOINT_LIST - SHAREPOINT_LIST_ITEM - SHAREPOINT_DOCUMENT_LIBRARY - LINK - PROJECT - PULL_REQUEST - MEETING - PRODUCT - DEAL - CASE - TASK - ARTIFACT - CODE_FILE - SQL_TABLE - SQL_VIEW - OTHERS example: FILE ConnectorNameEnum: type: string description: | Name of the source connector. Mirrors the values of the backend `Connectors` enum (`backend/python/app/config/constants/arangodb.py`); records store the enum value (e.g. Google Drive is `DRIVE`, SharePoint Online is `SHAREPOINT ONLINE`), not the enum member name. enum: - DRIVE - DRIVE WORKSPACE - GMAIL - GMAIL WORKSPACE - CALENDAR - ONEDRIVE - SHAREPOINT ONLINE - OUTLOOK - OUTLOOK PERSONAL - OUTLOOK CALENDAR - MICROSOFT TEAMS - NOTION - SLACK - SLACK WORKSPACE - KB - CONFLUENCE - CONFLUENCE DATA CENTER - CONFLUENCE DATA CENTER PERSONAL - JIRA - JIRA PERSONAL - JIRA DATA CENTER - JIRA DATA CENTER PERSONAL - BOX - NEXTCLOUD - DROPBOX - DROPBOX PERSONAL - WEB - BOOKSTACK - GITHUB - SERVICENOW - SALESFORCE - S3 - MINIO - GCS - AZURE BLOB - AZURE FILES - LINEAR - ZAMMAD - ZOOM - GITLAB - GITLAB PERSONAL - SNOWFLAKE - POSTGRESQL - MARIADB - UNKNOWN - RSS - LOCAL_FS - CODING_SANDBOX - DATABASE_SANDBOX - IMAGE_GENERATION - ATTACHMENTS example: DRIVE Record: type: object description: | A record represents a single document, file, or content item within a knowledge base. Records can originate from file uploads or external connectors (Google Drive, OneDrive, etc.). properties: id: type: string description: Unique record identifier (UUID format) example: 550e8400-e29b-41d4-a716-446655440000 recordName: type: string description: Display name of the record example: Q4 Financial Report.pdf name: type: string description: Display name (alias for recordName) externalRecordId: type: string description: External storage document ID (links to Storage module) example: 507f1f77bcf86cd799439011 recordType: $ref: '#/components/schemas/RecordTypeEnum' origin: type: string enum: - UPLOAD - CONNECTOR description: | Source of the record: - UPLOAD: Manually uploaded via API/UI - CONNECTOR: Synced from external connector example: UPLOAD connectorId: type: string description: ID of the connector that synced this record (null for uploads) example: conn_123456 connectorName: $ref: '#/components/schemas/ConnectorNameEnum' orgId: type: string description: Organization ID that owns this record example: org_abc123 kbId: type: string description: Knowledge base ID containing this record example: kb_xyz789 folderId: type: string nullable: true description: Parent folder ID (null if at KB root) example: folder_456 version: type: integer description: Current version number (increments on updates) default: 0 example: 3 isLatestVersion: type: boolean description: Whether this is the latest version createdAtTimestamp: type: integer format: int64 description: Creation timestamp in milliseconds example: 1704153600000 updatedAtTimestamp: type: integer format: int64 description: Last update timestamp in milliseconds example: 1704240000000 sourceCreatedAtTimestamp: type: integer format: int64 description: Source creation timestamp (from connector) sourceLastModifiedTimestamp: type: integer format: int64 description: Source last modified timestamp (from connector) indexingStatus: type: string enum: - NOT_STARTED - PAUSED - IN_PROGRESS - COMPLETED - FAILED - FILE_TYPE_NOT_SUPPORTED - AUTO_INDEX_OFF - EMPTY - ENABLE_MULTIMODAL_MODELS - QUEUED description: | Current indexing/processing status: - NOT_STARTED: Awaiting indexing - QUEUED: In indexing queue - IN_PROGRESS: Currently being indexed - COMPLETED: Successfully indexed and searchable - FAILED: Indexing failed (check error details) - PAUSED: Indexing paused by user - FILE_TYPE_NOT_SUPPORTED: Unsupported file format - AUTO_INDEX_OFF: Auto-indexing disabled for this record - EMPTY: File has no extractable content - ENABLE_MULTIMODAL_MODELS: Requires multimodal AI models example: COMPLETED isDeleted: type: boolean description: Soft delete flag default: false isArchived: type: boolean description: Archive flag for inactive records default: false webUrl: type: string format: uri description: Direct URL to access the original content example: https://drive.google.com/file/d/abc123 mimeType: type: string description: MIME type of the file content example: application/pdf sizeInBytes: type: integer format: int64 description: File size in bytes example: 1048576 extension: type: string description: File extension (without dot) example: pdf sha256Hash: type: string description: SHA-256 hash for content deduplication type: type: string description: Node type identifier example: record fileRecord: type: object nullable: true description: File-specific metadata (present when recordType is FILE) properties: id: type: string name: type: string extension: type: string mimeType: type: string sizeInBytes: type: integer format: int64 webUrl: type: string path: type: string nullable: true isFile: type: boolean mailRecord: type: object nullable: true description: Email-specific metadata (present when recordType is MAIL or GROUP_MAIL) ticketRecord: type: object nullable: true description: Ticket-specific metadata (present when recordType is TICKET) additionalProperties: true required: - recordName - recordType - origin - orgId UpdateRecordEnrichment: type: object description: | Fields merged into successful record-update responses (Node gateway and Local KB connector). properties: timestamp: type: integer format: int64 description: Epoch milliseconds when the response was generated fileUpdated: type: boolean location: type: string enum: - kb_root - folder kb: type: object additionalProperties: true userPermission: type: string GetRecordByIdResponseSchema: type: object additionalProperties: false description: Response returned by GET /knowledgeBase/record/{recordId}. required: - record - knowledgeBase - folder - metadata - permissions properties: record: type: object additionalProperties: false required: - id - orgId - recordName - externalRecordId - connectorId - connectorName - recordType - origin - version - isLatestVersion - createdAtTimestamp - updatedAtTimestamp - sourceCreatedAtTimestamp - sourceLastModifiedTimestamp - lastSyncTimestamp - indexingStatus - extractionStatus - isDeleted - isArchived - isDirty - isVLMOcrProcessed - mimeType - sizeInBytes - webUrl - fileRecord - mailRecord - ticketRecord properties: id: type: string orgId: type: string recordName: type: string externalRecordId: type: string externalRootGroupId: type: string nullable: true externalGroupId: type: string nullable: true connectorId: type: string connectorName: $ref: '#/components/schemas/ConnectorNameEnum' recordType: $ref: '#/components/schemas/RecordTypeEnum' origin: type: string version: type: integer isLatestVersion: type: boolean createdAtTimestamp: type: integer format: int64 updatedAtTimestamp: type: integer format: int64 sourceCreatedAtTimestamp: type: integer format: int64 sourceLastModifiedTimestamp: type: integer format: int64 lastSyncTimestamp: type: integer format: int64 lastIndexTimestamp: type: integer format: int64 lastExtractionTimestamp: type: integer format: int64 indexingStatus: type: string extractionStatus: type: string isDeleted: type: boolean isArchived: type: boolean isDirty: type: boolean isVLMOcrProcessed: type: boolean mimeType: type: string sizeInBytes: type: integer format: int64 md5Checksum: type: string virtualRecordId: type: string webUrl: type: string fileRecord: type: object nullable: true additionalProperties: false required: - id - orgId - name - extension - mimeType - sizeInBytes - isFile - webUrl properties: id: type: string orgId: type: string name: type: string extension: type: string mimeType: type: string sizeInBytes: type: integer format: int64 isFile: type: boolean webUrl: type: string path: type: string nullable: true localFsRelativePath: type: string nullable: true mailRecord: type: object nullable: true additionalProperties: false properties: {} ticketRecord: type: object nullable: true additionalProperties: false properties: {} knowledgeBase: type: object nullable: true additionalProperties: false required: - id - name - orgId properties: id: type: string name: type: string orgId: type: string folder: type: object nullable: true additionalProperties: false required: - id - name properties: id: type: string name: type: string metadata: type: object additionalProperties: false required: - languages - topics - subcategories1 - subcategories2 - subcategories3 - departments - categories properties: languages: type: array items: type: object additionalProperties: false required: - id - name properties: id: type: string name: type: string topics: type: array items: type: object additionalProperties: false required: - id - name properties: id: type: string name: type: string subcategories1: type: array items: type: object additionalProperties: false required: - id - name properties: id: type: string name: type: string subcategories2: type: array items: type: object additionalProperties: false required: - id - name properties: id: type: string name: type: string subcategories3: type: array items: type: object additionalProperties: false required: - id - name properties: id: type: string name: type: string departments: type: array items: type: object additionalProperties: false required: - id - name properties: id: type: string name: type: string categories: type: array items: type: object additionalProperties: false required: - id - name properties: id: type: string name: type: string permissions: type: array items: type: object additionalProperties: false required: - id - name - type - relationship - accessType properties: id: type: string name: type: string type: type: string relationship: type: string enum: - OWNER - WRITER - READER accessType: type: string DeleteRecordResponseSchema: type: object additionalProperties: false description: Response returned by DELETE /knowledgeBase/record/{recordId}. required: - success - message - recordId properties: success: type: boolean enum: - true message: type: string recordId: type: string connector: type: string nullable: true timestamp: type: integer format: int64 nullable: true reIndexRecordResponseSchema: type: object additionalProperties: false description: Response returned by POST /knowledgeBase/reindex/record/{recordId}. required: - success - message - eventPublished - depth properties: success: type: boolean enum: - true message: type: string recordId: type: string nullable: true recordName: type: string nullable: true connector: type: string nullable: true eventPublished: type: boolean userRole: type: string nullable: true depth: type: integer ReIndexRecordGroupResponseSchema: type: object additionalProperties: false description: Response returned by POST /knowledgeBase/reindex/record-group/{recordGroupId}. required: - success - message - recordGroupId - depth - eventPublished properties: success: type: boolean enum: - true message: type: string recordGroupId: type: string depth: type: integer connector: type: string nullable: true eventPublished: type: boolean UploadLimitsResponseSchema: type: object additionalProperties: false description: Upload constraints returned by GET /knowledgeBase/limits. required: - maxFilesPerRequest - maxFileSizeBytes properties: maxFilesPerRequest: type: integer minimum: 1 example: 1000 description: Maximum number of files per upload request maxFileSizeBytes: type: integer minimum: 1 example: 31457280 description: Maximum file size in bytes (default 30MB when platform settings unavailable) UploadStreamSSEEvent: type: object description: | Server-Sent Event envelope for the KB streaming upload endpoint (`POST /knowledgeBase/{kbId}/upload`, with optional `folderId` query param). These endpoints respond with `Content-Type: text/event-stream`: the upload and its per-file progress are a single request. The body streams one terminal event per file, then a final `done` summary, then closes. `data` is a JSON-encoded string whose decoded shape depends on `event`: - `file:succeeded` — see `UploadSucceededFileDetail`. The file was uploaded and its record created; content indexing then continues asynchronously. - `file:failed` — see `UploadFailedFileDetail`. Covers files rejected up front (oversize / unsupported type — these carry `reason`), files that failed the storage upload (`stage: "upload"`), and files the indexing service could not create (`stage: "index"`). - `done` — see `UploadDoneSummary`. Final event; the stream closes after it. - `error` — `{ "message": string }`. Emitted only on a catastrophic mid-stream failure (after the 200 headers were already sent), then the stream closes. Clients MUST treat any file without a terminal `file:succeeded` / `file:failed` as failed when this is received. The stream also emits SSE comment heartbeats (`: keepalive`) roughly every 1s during slow work; these carry no `event`/`data` and should be ignored. Authentication, permission, and request-shape failures occur BEFORE the stream starts and are returned as ordinary 4xx JSON errors (not stream events). properties: event: type: string enum: - file:succeeded - file:failed - done - error data: type: string description: JSON-encoded event payload. Shape depends on `event`. IndexingStatusFilter: type: string description: | Indexing status used to filter which records are included in a scoped reindex (record or record-group). Omit `statusFilters` to reindex all descendants regardless of status. enum: - NOT_STARTED - QUEUED - IN_PROGRESS - COMPLETED - FAILED - FILE_TYPE_NOT_SUPPORTED - AUTO_INDEX_OFF - EMPTY ReindexRecordRequestBody: type: object description: Optional body for single-record reindex. properties: depth: type: integer minimum: -1 maximum: 100 default: 0 description: | Child traversal depth (`0` = record only; higher values include descendants; `100` is used by clients for folder-like reindex). force: type: boolean default: false description: Force reindex even when the connector considers the record unchanged. statusFilters: type: array items: $ref: '#/components/schemas/IndexingStatusFilter' description: | When set, only records whose indexing status matches one of these values are reindexed (applies to the record and its descendants per `depth`). ReindexRecordGroupRequestBody: type: object description: Optional body for record-group (folder/KB container) reindex. properties: depth: type: integer minimum: -1 maximum: 100 default: 0 description: Depth of records under the record group to include. force: type: boolean default: false description: Force reindex for all matched records in the group. statusFilters: type: array items: $ref: '#/components/schemas/IndexingStatusFilter' description: | When set, only records matching these indexing statuses are reindexed. DateRangeFilter: type: object description: Date range filter with optional inclusive bounds (epoch ms). properties: gte: type: integer nullable: true description: Greater-than-or-equal bound (epoch ms). lte: type: integer nullable: true description: Less-than-or-equal bound (epoch ms). SizeRangeFilter: type: object description: Size range filter with optional inclusive bounds (bytes). properties: gte: type: integer nullable: true description: Greater-than-or-equal bound (bytes). lte: type: integer nullable: true description: Less-than-or-equal bound (bytes). FilterOption: type: object description: A single filter option for knowledge hub filters. required: - id - label properties: id: type: string description: Filter ID value to send in requests. label: type: string description: Display label for the filter. type: type: string nullable: true description: Additional type information (currently unused, may be null). connectorType: type: string nullable: true description: Connector type/name. Set only for entries in the `connectors` list. KnowledgeHubNode: type: object description: | One element of `items`. The live API keeps keys stable and sets inapplicable values to JSON `null` (not omitted). required: - id - name - nodeType - parentId - origin - connector - recordType - recordGroupType - indexingStatus - reason - createdAt - updatedAt - sizeInBytes - mimeType - extension - webUrl - hasChildren - previewRenderable - permission - sharingStatus - isInternal properties: id: type: string description: Unique identifier for the node. name: type: string description: Display name of the node. nodeType: type: string enum: - app - recordGroup - folder - record description: Type of the node (app, recordGroup, folder, or record). parentId: type: string nullable: true description: Parent node ID, or `null` at the root browse level. origin: type: string enum: - COLLECTION - CONNECTOR description: Origin type. connector: type: string nullable: true description: Connector display name / key when applicable; otherwise `null`. recordType: type: string nullable: true description: Record type when `nodeType` is `record`; otherwise `null`. recordGroupType: type: string nullable: true description: Record group type when `nodeType` is `recordGroup`; otherwise `null`. indexingStatus: type: string nullable: true description: Indexing status when `nodeType` is `record`; otherwise `null`. reason: type: string nullable: true description: Failure or status reason when set; otherwise `null`. isInternal: type: boolean description: True for internal/system nodes that do not originate from a source. createdAt: type: integer description: Creation timestamp (epoch ms). updatedAt: type: integer description: Update timestamp (epoch ms). sizeInBytes: type: integer nullable: true description: File size in bytes for file records; otherwise `null`. mimeType: type: string nullable: true extension: type: string nullable: true webUrl: type: string nullable: true hasChildren: type: boolean description: Whether the node has children (sidebar / tree). previewRenderable: type: boolean nullable: true permission: type: object nullable: true description: Per-item permission when `include=permissions` is requested; otherwise `null`. required: - role - canEdit - canDelete properties: role: type: string canEdit: type: boolean canDelete: type: boolean sharingStatus: type: string nullable: true description: | Sharing status (e.g. `private`, `shared`, `team`, `workspace`) when applicable; otherwise `null`. KnowledgeHubNodesResponse: type: object description: | Response body for the Knowledge Hub nodes API. The deployed service serialises optional values as JSON `null` and always includes the keys listed in `required` (Swagger / clients will see stable shapes, not omitted properties). required: - success - error - id - currentNode - parentNode - items - pagination - filters - breadcrumbs - counts - permissions properties: success: type: boolean enum: - true description: Always `true` on HTTP 200. Failures use 4xx/5xx error envelopes, not this body shape. error: type: string nullable: true description: Always `null` on HTTP 200. id: type: string nullable: true description: Current parent node ID when browsing children; `null` at root. currentNode: type: object nullable: true description: Node being browsed when `parentId` is in the path; `null` at root. required: - id - name - nodeType properties: id: type: string name: type: string nodeType: type: string description: One of `app`, `recordGroup`, `folder`, `record`. subType: type: string nullable: true description: Connector name or record type when applicable; otherwise `null`. parentNode: type: object nullable: true description: Parent of `currentNode` when present; `null` when not applicable. required: - id - name - nodeType properties: id: type: string name: type: string nodeType: type: string description: One of `app`, `recordGroup`, `folder`, `record`. subType: type: string nullable: true items: type: array description: Page of nodes for the current browse or search. items: $ref: '#/components/schemas/KnowledgeHubNode' pagination: type: object required: - page - limit - totalItems - totalPages - hasNext - hasPrev properties: page: type: integer description: Current page (1-indexed). limit: type: integer description: Page size. totalItems: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean filters: type: object required: - applied - available properties: applied: type: object description: Echo of applied filters; unused slots are JSON `null`. required: - q - nodeTypes - recordTypes - origins - connectorIds - indexingStatus - createdAt - updatedAt - size - sortBy - sortOrder properties: q: type: string nullable: true nodeTypes: type: array nullable: true items: type: string recordTypes: type: array nullable: true items: type: string origins: type: array nullable: true items: type: string connectorIds: type: array nullable: true items: type: string indexingStatus: type: array nullable: true items: type: string createdAt: nullable: true allOf: - $ref: '#/components/schemas/DateRangeFilter' updatedAt: nullable: true allOf: - $ref: '#/components/schemas/DateRangeFilter' size: nullable: true allOf: - $ref: '#/components/schemas/SizeRangeFilter' sortBy: type: string description: Effective sort field after server normalisation. sortOrder: type: string description: Effective sort order after server normalisation. available: type: object nullable: true description: Populated when `include=availableFilters`; otherwise `null`. required: - nodeTypes - recordTypes - origins - connectors - indexingStatus - sortBy - sortOrder properties: nodeTypes: type: array items: $ref: '#/components/schemas/FilterOption' recordTypes: type: array items: $ref: '#/components/schemas/FilterOption' origins: type: array items: $ref: '#/components/schemas/FilterOption' connectors: type: array items: $ref: '#/components/schemas/FilterOption' indexingStatus: type: array items: $ref: '#/components/schemas/FilterOption' sortBy: type: array items: $ref: '#/components/schemas/FilterOption' sortOrder: type: array items: $ref: '#/components/schemas/FilterOption' breadcrumbs: type: array nullable: true description: Present when `include=breadcrumbs`; otherwise `null`. items: type: object required: - id - name - nodeType properties: id: type: string name: type: string nodeType: type: string description: One of `app`, `recordGroup`, `folder`, `record`. subType: type: string nullable: true counts: type: object nullable: true description: Present when `include=counts`; otherwise `null`. required: - items - total properties: items: type: array items: type: object required: - label - count properties: label: type: string count: type: integer total: type: integer permissions: type: object nullable: true description: Present when `include=permissions`; otherwise `null`. required: - role - canUpload - canCreateFolders - canEdit - canDelete - canManagePermissions properties: role: type: string canUpload: type: boolean canCreateFolders: type: boolean canEdit: type: boolean canDelete: type: boolean canManagePermissions: type: boolean Filters: type: object additionalProperties: false description: | App connector instance ids and knowledge-base / record-group ids that narrow retrieval for a turn. For **org assistant** chat streams, send explicit `apps` / `kb` lists. For **agent** chat streams, send explicit id lists, or **omit** `filters` (and `tools`) to let the service use the agent’s stored knowledge and tool configuration. Sending `{ "apps": [], "kb": [] }` on an agent stream means **no** knowledge sources for that turn (it is not “full org default”). properties: apps: type: array items: type: string description: | Connector instance ids to scope retrieval for this turn. Each element must be a UUID (connector instance id, record-group id, etc.) or the org knowledge-base collection sentinel `knowledgeBase_` (pattern `knowledgeBase_[a-zA-Z0-9_-]+`). Gateway validation matches Zod `appOrKbIdSchema`. kb: type: array items: type: string description: | Knowledge-base / record-group ids to scope retrieval for this turn. Each element uses the same accepted formats as `apps`: a UUID or `knowledgeBase_` (pattern `knowledgeBase_[a-zA-Z0-9_-]+`). AppliedFilterNode: type: object additionalProperties: false description: A single filter node selected by the user (used for display/persistence of active filters) properties: id: type: string description: Unique identifier of the filter node name: type: string description: Display name of the filter node nodeType: type: string description: Type of the node (e.g. app, recordGroup, folder, record) connector: type: string description: Connector identifier associated with this node AppliedFilters: type: object additionalProperties: false description: | Rich filter state selected by the user, used for display and persistence only. This mirrors the active selection shown in the UI and is distinct from the machine-readable `filters` field used for retrieval scoping. properties: apps: type: array items: $ref: '#/components/schemas/AppliedFilterNode' description: Applied app/connector filter nodes kb: type: array items: $ref: '#/components/schemas/AppliedFilterNode' description: Applied knowledge-base filter nodes ChatAttachmentRef: type: object additionalProperties: false description: | Reference to an attachment produced by `POST /conversations/attachments/upload` (or the equivalent agent route). Include in create/stream/message bodies so the turn is sent with uploaded files. required: - recordId properties: recordId: type: string minLength: 1 description: Attachment record id returned from the upload endpoint. recordName: type: string minLength: 1 description: Original display name of the file when known. mimeType: type: string minLength: 1 description: MIME type of the uploaded file. extension: type: string minLength: 1 description: File extension (e.g. `pdf`). virtualRecordId: type: string minLength: 1 description: Optional synthetic record id used by the graph layer. ChatAttachmentUploadRef: type: object additionalProperties: false description: | Concrete attachment metadata returned by `POST /conversations/attachments/upload` (or the equivalent agent route). required: - recordId - recordName - mimeType - extension - virtualRecordId properties: recordId: type: string minLength: 1 description: Server-assigned attachment record id. recordName: type: string minLength: 1 description: Original filename stored for the attachment. mimeType: type: string minLength: 1 description: MIME type of the uploaded file. extension: type: string minLength: 1 description: File extension derived by the backend. virtualRecordId: type: string minLength: 1 description: Synthetic record id used by the graph layer. ocrMode: type: string minLength: 1 description: Optional backend-reported processing mode for the attachment. ChatAttachmentUploadResponse: type: object additionalProperties: false description: | Success envelope returned by `POST /conversations/attachments/upload` and `POST /agents/{agentKey}/conversations/attachments/upload`. required: - conversationId - attachments properties: conversationId: type: string nullable: true description: | Existing conversation id echoed from the request when the upload is tied to a thread; otherwise `null`. attachments: type: array minItems: 1 items: $ref: '#/components/schemas/ChatAttachmentUploadRef' CreateConversationRequest: type: object description: | Request body for creating a new AI conversation. **Query Processing:** The query is processed through PipesHub's AI pipeline which: - Performs semantic search across indexed knowledge bases - Retrieves relevant context from matching documents - Generates a response with citations to source materials - Suggests follow-up questions based on the conversation required: - query properties: query: type: string minLength: 1 maxLength: 100000 description: | The user's question or prompt to start the conversation. Supports natural language queries of any complexity. example: What are the key findings from our Q4 financial report? recordIds: type: array items: type: string format: objectId description: | Limit the AI's knowledge scope to specific records/documents. When provided, only these records will be searched for context. example: - 507f1f77bcf86cd799439011 - 507f1f77bcf86cd799439012 filters: $ref: '#/components/schemas/Filters' appliedFilters: $ref: '#/components/schemas/AppliedFilters' attachments: type: array items: $ref: '#/components/schemas/ChatAttachmentRef' description: | Uploaded chat attachments to associate with this conversation turn (see `POST /conversations/attachments/upload`). modelKey: type: string description: | Identifier for the AI model configuration to use. Available models depend on organization settings. example: gpt-4-turbo modelName: type: string description: Display name of the AI model example: GPT-4 Turbo modelFriendlyName: type: string description: Friendly display name of the selected model example: GPT-4 Turbo chatMode: type: string enum: - web_search - internal_search description: | Chat mode affecting response behavior. example: internal_search timezone: type: string minLength: 1 description: | IANA timezone identifier from the client (top-level field). Used to provide time-aware context to the AI. example: America/New_York currentTime: type: string format: date-time description: | ISO 8601 / RFC 3339 datetime from the client (top-level field; UTC `Z` or numeric offset). example: '2026-04-12T16:00:00+05:30' tools: type: array items: type: string minLength: 1 description: | Optional list of tool identifiers (fully-qualified action names such as "jira.create_issue") that the AI agent is permitted to invoke for this request. When omitted the agent may use any configured tool. Applicable only when chatMode is an agent mode (e.g. "agent:auto"). example: - jira.create_issue - confluence.search_content AgentStreamCreateConversationRequest: type: object additionalProperties: false description: | Request body for `POST /agents/{agentKey}/conversations/stream`. Only `query` is required; all other fields are optional overrides or routing hints. Unknown fields are stripped during validation. required: - query properties: query: type: string minLength: 1 maxLength: 100000 description: | User prompt for the first turn. Saved as the initial `user_query` message and sent to the agent backend. recordIds: type: array items: type: string format: objectId description: | Optional record ids to include as context for this turn. Each id must be a 24-character MongoDB ObjectId. filters: allOf: - $ref: '#/components/schemas/Filters' description: | Optional retrieval scope (`apps` / `kb`) for this turn. Each id must be a UUID or a `knowledgeBase_` collection id. Omit for agent defaults; send `{ "apps": [], "kb": [] }` to force no knowledge sources for this turn. appliedFilters: allOf: - $ref: '#/components/schemas/AppliedFilters' description: | UI filter state persisted on the saved user message. Not used for retrieval and not forwarded to the upstream agent backend. attachments: type: array items: $ref: '#/components/schemas/ChatAttachmentRef' description: | Uploaded attachments to ground this turn. Each entry references a record id returned from the agent attachment upload endpoint. chatMode: type: string enum: - auto - quick - verification - deep description: | Chat mode hint forwarded to the agent backend. - `auto` lets the agent pick its default strategy. - `quick` favors low-latency answers over depth. - `verification` runs additional grounding/verification passes. - `deep` performs deeper retrieval and reasoning. modelKey: type: string minLength: 1 description: | AI model configuration id for this turn. Omit to use the agent's default model. modelName: type: string minLength: 1 description: Provider model name (the underlying LLM identifier). modelFriendlyName: type: string minLength: 1 description: Friendly UI label for the selected model. timezone: type: string minLength: 1 description: | Client IANA timezone, such as `America/New_York`. Helps the agent resolve relative date references in the prompt. currentTime: type: string format: date-time description: | Client time in ISO 8601 / RFC 3339 format (UTC `Z` or numeric offset). Sent alongside `timezone` for time-aware answers. tools: type: array items: type: string minLength: 1 description: | Allowed tool ids for this turn, such as `jira.create_issue`. Omit to let the agent use its default toolset; send `[]` to disable tools for this turn. example: query: what are some latest tech news? modelKey: 5c1832f4-fa19-4167-b913-307fad3a6551 modelName: gpt-5.4-mini modelFriendlyName: GPT 5.4 mini chatMode: auto timezone: Asia/Kolkata currentTime: '2026-05-19T12:58:01+05:30' tools: [] filters: apps: - 2605c882-61d4-4aa2-b480-a68c957c151d - ed6d6cc4-70bd-4838-9aeb-488e910c833a - aeab9ddc-fb9b-47c8-ad98-bd4744e19555 kb: - 8747da12-4724-4a95-ac92-827b88d79647 appliedFilters: apps: - id: 2605c882-61d4-4aa2-b480-a68c957c151d name: US Headlines, abcnews nodeType: app connector: RSS - id: ed6d6cc4-70bd-4838-9aeb-488e910c833a name: ABC News RSS nodeType: app connector: RSS - id: aeab9ddc-fb9b-47c8-ad98-bd4744e19555 name: Hacker news rss nodeType: app connector: RSS kb: - id: 8747da12-4724-4a95-ac92-827b88d79647 name: Siddhant Ota's Private nodeType: recordGroup connector: KB RegenerateRequest: type: object additionalProperties: false description: | Request body for regenerating an AI response. All fields are optional; when omitted the model selection and execution context from the original message are reused. Supported fields: - `filters` — optional `{ apps?, kb? }` filter object - `chatMode` — optional non-empty chat mode string - `modelKey`, `modelName`, `modelFriendlyName` — optional non-empty model override fields - `timezone` — optional non-empty client timezone string - `currentTime` — optional ISO 8601 / RFC 3339 datetime string with UTC `Z` or a numeric offset - `tools` — optional array of non-empty tool identifiers properties: filters: $ref: '#/components/schemas/Filters' modelKey: type: string minLength: 1 description: | Identifier of the AI model configuration to use for regeneration. Typically a UUID returned by the model-management endpoints. When omitted, the model used for the original message is reused. example: 05438a37-68f2-4641-a8dc-6c47e63278ca modelName: type: string minLength: 1 description: Provider model name (e.g. the underlying LLM identifier). example: gpt-5.4-mini modelFriendlyName: type: string minLength: 1 description: Friendly display name of the selected model. example: mini chatMode: type: string minLength: 1 description: | Chat mode used for regeneration (for example `internal_search`, `web_search`, or an agent mode such as `agent:auto`). example: internal_search timezone: type: string minLength: 1 description: | IANA timezone identifier from the client. Used to provide time-aware context to the AI during regeneration. example: Asia/Calcutta currentTime: type: string format: date-time description: | ISO 8601 / RFC 3339 datetime from the client (UTC `Z` or numeric offset). Used to anchor any relative time references in the query. example: '2026-05-11T15:43:21+05:30' tools: type: array items: type: string minLength: 1 description: | Optional list of tool identifiers (fully-qualified action names such as `jira.create_issue`) the agent may invoke when regenerating. Applicable only in agent chat modes. example: - jira.create_issue - confluence.search_content AddMessageRequest: type: object description: Request body for adding a message to an existing conversation required: - query properties: query: type: string minLength: 1 description: The follow-up question or message content example: Can you elaborate on the revenue trends? filters: $ref: '#/components/schemas/Filters' appliedFilters: $ref: '#/components/schemas/AppliedFilters' attachments: type: array items: $ref: '#/components/schemas/ChatAttachmentRef' description: | Uploaded chat attachments for this follow-up turn (see `POST /conversations/attachments/upload`). modelKey: type: string description: Override the model for this specific message modelName: type: string description: Display name of the model modelFriendlyName: type: string description: Friendly display name of the model chatMode: type: string enum: - web_search - internal_search description: Chat mode for this message timezone: type: string minLength: 1 description: | IANA timezone identifier from the client (top-level field). Used to provide time-aware context to the AI. example: America/New_York currentTime: type: string format: date-time description: | ISO 8601 / RFC 3339 datetime from the client (top-level field; UTC `Z` or numeric offset). example: '2026-04-12T16:00:00+05:30' tools: type: array items: type: string minLength: 1 description: | Optional list of tool identifiers the agent may invoke for this follow-up message. Semantics are identical to the create-conversation tools field. example: - jira.create_issue - confluence.search_content AgentAddMessageStreamRequest: type: object additionalProperties: false description: | Request body for `POST /agents/{agentKey}/conversations/{conversationId}/messages/stream`. Only `query` is required; all other fields are optional overrides or routing hints. Unknown fields are stripped during validation. required: - query properties: query: type: string minLength: 1 description: | User follow-up prompt to append to the existing agent conversation. Saved as a new `user_query` message before the upstream AI stream starts. filters: allOf: - $ref: '#/components/schemas/Filters' description: | Optional retrieval scope (`apps` / `kb`) for this turn. Each id must be a UUID or a `knowledgeBase_` collection id. Omit to let the agent use its stored defaults; send `{ "apps": [], "kb": [] }` to force no knowledge sources for this turn. appliedFilters: allOf: - $ref: '#/components/schemas/AppliedFilters' description: | UI filter state persisted on the saved user message. Not used for retrieval and not forwarded to the upstream agent backend. attachments: type: array items: $ref: '#/components/schemas/ChatAttachmentRef' description: | Uploaded attachments to ground this turn. Each entry references a record id returned from the agent attachment upload endpoint. chatMode: type: string enum: - auto - quick - verification - deep description: | Chat mode hint forwarded to the agent backend. Defaults to `auto` in the upstream AI payload when omitted. - `auto` lets the agent pick its default strategy. - `quick` favors low-latency answers over depth. - `verification` runs additional grounding/verification passes. - `deep` performs deeper retrieval and reasoning. modelKey: type: string minLength: 1 description: | AI model configuration id override for this turn. Omit to use the agent's default model. modelName: type: string minLength: 1 description: Provider model name (the underlying LLM identifier). modelFriendlyName: type: string minLength: 1 description: Friendly UI label for the selected model. timezone: type: string minLength: 1 description: | Client IANA timezone, such as `America/New_York`. Helps the agent resolve relative date references in the prompt. currentTime: type: string format: date-time description: | Client time in ISO 8601 / RFC 3339 format (UTC `Z` or numeric offset). Sent alongside `timezone` for time-aware answers. tools: type: array items: type: string minLength: 1 description: | Allowed tool ids for this turn, such as `jira.create_issue`. Omit to let the agent use its default toolset; send `[]` to disable tools for this turn. example: query: can you elaborate on the latest headlines? modelKey: 5c1832f4-fa19-4167-b913-307fad3a6551 modelName: gpt-5.4-mini modelFriendlyName: GPT 5.4 mini chatMode: verification timezone: Asia/Kolkata currentTime: '2026-05-19T12:58:01+05:30' tools: [] filters: apps: - 2605c882-61d4-4aa2-b480-a68c957c151d - ed6d6cc4-70bd-4838-9aeb-488e910c833a kb: - 8747da12-4724-4a95-ac92-827b88d79647 appliedFilters: apps: - id: 2605c882-61d4-4aa2-b480-a68c957c151d name: US Headlines, abcnews nodeType: app connector: RSS - id: ed6d6cc4-70bd-4838-9aeb-488e910c833a name: ABC News RSS nodeType: app connector: RSS kb: - id: 8747da12-4724-4a95-ac92-827b88d79647 name: Siddhant Ota's Private nodeType: recordGroup connector: KB Message: type: object additionalProperties: false description: | A single message within a conversation. Messages can be user queries, AI responses, system messages, or error notifications. properties: _id: type: string format: objectId description: Unique message identifier messageType: type: string enum: - user_query - bot_response - error - feedback - system description: | Type of message: - `user_query` - User's question or input - `bot_response` - AI-generated response - `error` - Error message from the system - `feedback` - User feedback on a response - `system` - System notification or status content: type: string description: The message text content contentFormat: type: string enum: - MARKDOWN - JSON - HTML description: Format of the content for rendering default: MARKDOWN citations: type: array items: $ref: '#/components/schemas/CitationReference' description: References to source documents used in the response confidence: type: string nullable: true description: | AI confidence in the answer. Present only on `bot_response` messages, and only when the model emitted a trailing confidence block. This field is now optional and nullable; it was previously always present and non-nullable. Treat a missing or `null` value as "no confidence reported" and guard before using it. Change effective in SDK v1.3.0 (v1.2.0 and earlier always populated it). followUpQuestions: type: array items: $ref: '#/components/schemas/FollowUpQuestion' description: Suggested follow-up questions feedback: type: array items: $ref: '#/components/schemas/MessageFeedback' description: User feedback on this message metadata: type: object additionalProperties: false properties: processingTimeMs: type: number description: Time taken to generate response in milliseconds modelVersion: type: string description: Version of the AI model used aiTransactionId: type: string description: Transaction ID for tracking in AI backend reason: type: string description: Additional context or reasoning modelInfo: $ref: '#/components/schemas/ConversationModelInfo' appliedFilters: $ref: '#/components/schemas/AppliedFilters' referenceData: type: array description: | Reference identifiers extracted from tool responses, used to scope follow-up queries (for example Jira project keys or record IDs). items: type: object additionalProperties: false properties: name: type: string description: Display name shown to the user. id: type: string description: Technical identifier (numeric ID, UUID, etc.). type: type: string description: Item type (e.g. `project`, `issue`, `file`, `notebook`, `page`). app: type: string description: | Source application (e.g. `jira`, `confluence`, `sharepoint`, `slack`, `drive`, `gmail`). webUrl: type: string description: URL to open the item in a browser. metadata: type: object additionalProperties: type: string description: | App-specific fields keyed by name (e.g. `key` for a Jira project, `siteId` for a SharePoint document). attachments: type: array description: | Files uploaded for this message turn (see `POST /conversations/attachments/upload`). items: $ref: '#/components/schemas/ChatAttachmentRef' tools: type: array description: Tool call results invoked during this message turn. items: type: object additionalProperties: false properties: toolName: type: string toolResult: {} createdAt: type: string format: date-time updatedAt: type: string format: date-time CitationReference: type: object additionalProperties: false description: Reference to a source document cited in a response properties: citationId: type: string format: objectId description: ID of the citation record relevanceScore: type: number minimum: 0 maximum: 1 description: How relevant this citation is to the query (0-1) excerpt: type: string description: Relevant excerpt from the source document context: type: string description: Additional context around the citation Citation: type: object additionalProperties: false description: | A populated citation document. Represents a single chunk of source content (e.g. a passage from a document or record) referenced by an AI response, together with its provenance metadata. required: - _id - content - chunkIndex - citationType - metadata - createdAt - updatedAt properties: _id: type: string format: objectId content: type: string description: The cited text chunk chunkIndex: type: integer description: Index of this chunk within the source record citationType: type: string description: Source type identifier (e.g. `vectordb|document`) metadata: $ref: '#/components/schemas/PersistedSemanticSearchCitationMetadata' createdAt: type: string format: date-time updatedAt: type: string format: date-time ConversationModelInfo: type: object additionalProperties: false description: AI model configuration recorded against a conversation or message. properties: modelKey: type: string description: Stable identifier of the configured model record modelName: type: string description: Provider-facing model name (e.g. `gpt-4o-mini`) modelProvider: type: string description: Provider key (e.g. `openai`, `anthropic`) modelFriendlyName: type: string description: Human-readable display name chatMode: type: string description: Chat mode used for this turn (e.g. `quick`, `internal_search`) FollowUpQuestion: type: object additionalProperties: false description: AI-suggested follow-up question properties: question: type: string description: The suggested question text confidence: type: string description: Confidence level for this suggestion reasoning: type: string description: Why this question might be relevant MessageFeedbackSubmitRequest: type: object additionalProperties: false description: | Gateway request body for submitting message feedback (Zod `feedbackBodySchema`). All fields are optional; an empty object is accepted. Matches the first-party chat UI payload shape. properties: isHelpful: type: boolean description: Overall helpfulness signal (thumbs up/down). categories: type: array description: Issue or positive categories that apply to the response. items: type: string enum: - incorrect_information - missing_information - irrelevant_information - unclear_explanation - poor_citations - excellent_answer - helpful_citations - well_explained - other comments: type: object additionalProperties: false description: Free-text comments grouped by sentiment. properties: positive: type: string description: What was good about the response. negative: type: string description: What could be improved. MessageFeedback: type: object additionalProperties: false description: | Comprehensive feedback on an AI response. Feedback helps improve the AI's performance and response quality over time. properties: isHelpful: type: boolean description: Overall helpfulness rating ratings: type: object additionalProperties: false properties: accuracy: type: integer minimum: 1 maximum: 5 description: How accurate was the information (1-5) relevance: type: integer minimum: 1 maximum: 5 description: How relevant was the response (1-5) completeness: type: integer minimum: 1 maximum: 5 description: How complete was the answer (1-5) clarity: type: integer minimum: 1 maximum: 5 description: How clear was the explanation (1-5) categories: type: array items: type: string enum: - incorrect_information - missing_information - irrelevant_information - unclear_explanation - poor_citations - excellent_answer - helpful_citations - well_explained - other description: Categories of issues or positive attributes identified comments: type: object additionalProperties: false properties: positive: type: string description: What was good about the response negative: type: string description: What could be improved suggestions: type: string description: Specific suggestions for improvement citationFeedback: type: array items: type: object additionalProperties: false properties: _id: type: string format: objectId description: Auto-generated sub-document identifier citationId: type: string format: objectId isRelevant: type: boolean relevanceScore: type: integer minimum: 1 maximum: 5 comment: type: string description: Feedback on individual citations followUpQuestionsHelpful: type: boolean description: Were the suggested follow-up questions helpful unusedFollowUpQuestions: type: array items: type: string description: Follow-up questions that were suggested but not used by the user source: type: string enum: - user - system - admin - auto default: user description: Origin of the feedback. Always present in responses (server applies the default `user`). feedbackProvider: type: string format: objectId description: User who submitted the feedback timestamp: type: integer format: int64 description: | Time the feedback was created, stored as a Number (epoch milliseconds) with a server-side default of `Date.now`, so always present in responses. Not an ISO 8601 datetime. revisions: type: array description: Audit trail of edits to this feedback entry items: type: object additionalProperties: false properties: _id: type: string format: objectId description: Auto-generated sub-document identifier updatedFields: type: array items: type: string description: Names of feedback fields modified in this revision previousValues: type: object additionalProperties: true description: | Map of previously-set values for the fields named in `updatedFields`, keyed by field name. Stored as a Mongoose Map of Mixed values. updatedBy: type: string format: objectId updatedAt: type: integer format: int64 description: Time the revision was recorded, as epoch milliseconds. metrics: type: object additionalProperties: false description: Optional telemetry captured alongside the feedback properties: timeToFeedback: type: number description: Time from response delivery to feedback submission userInteractionTime: type: number description: Total time the user spent reviewing the response feedbackSessionId: type: string userAgent: type: string platform: type: string MessageFeedbackAppendMetrics: type: object additionalProperties: false required: - timeToFeedback description: | Telemetry recorded server-side alongside the feedback. Always present on append responses. properties: timeToFeedback: type: number description: | Milliseconds between message creation and feedback submission. Always present. userAgent: type: string description: Value of the `User-Agent` request header captured server-side. MessageFeedbackAppendEntry: type: object additionalProperties: false required: - feedbackProvider - timestamp - metrics description: | The feedback entry just appended to the message. Echoes the fields supplied in the request plus server-stamped `feedbackProvider`, `timestamp`, and `metrics`. properties: isHelpful: type: boolean description: Echoed from the request when supplied. categories: type: array description: Echoed categories from the request. items: type: string enum: - incorrect_information - missing_information - irrelevant_information - unclear_explanation - poor_citations - excellent_answer - helpful_citations - well_explained - other comments: type: object additionalProperties: false description: Echoed free-text comments from the request. properties: positive: type: string negative: type: string feedbackProvider: type: string format: objectId description: User who submitted the feedback. Always present. timestamp: type: integer format: int64 description: | Submission time as epoch milliseconds (not an ISO 8601 datetime). Always present. metrics: $ref: '#/components/schemas/MessageFeedbackAppendMetrics' MessageFeedbackUpdateResponse: type: object additionalProperties: false required: - conversationId - messageId - feedback - meta description: | Gateway response after appending feedback to a bot-response message. properties: conversationId: type: string format: objectId description: Conversation the feedback was attached to. messageId: type: string format: objectId description: Message the feedback was attached to. feedback: $ref: '#/components/schemas/MessageFeedbackAppendEntry' meta: type: object additionalProperties: false required: - requestId - timestamp - duration properties: requestId: type: string description: | Server-side request identifier. Read from the `X-Request-ID` header when supplied, otherwise auto-generated, so this field is always present. timestamp: type: string format: date-time duration: type: integer description: Server-side processing time in milliseconds. Conversation: type: object description: | A conversation represents a chat session between a user and the AI. Conversations maintain context across multiple messages and can be shared, archived, and organized. properties: _id: type: string format: objectId description: Unique conversation identifier userId: type: string format: objectId description: ID of the user who owns this conversation orgId: type: string format: objectId description: Organization this conversation belongs to title: type: string description: | Conversation title, auto-generated from first query or manually updated example: Q4 Financial Report Discussion initiator: type: string format: objectId description: User who started the conversation messages: type: array items: $ref: '#/components/schemas/Message' description: All messages in this conversation status: type: string enum: - None - Inprogress - Complete - Failed description: | Current status of the conversation: - `None` — no activity yet - `Inprogress` — AI is processing - `Complete` — response ready - `Failed` — error occurred failReason: type: string description: Error description, populated only when `status` is `Failed`. modelInfo: type: object properties: modelKey: type: string modelName: type: string modelFriendlyName: type: string description: Friendly display name of the selected model modelProvider: type: string chatMode: type: string description: AI model configuration used isShared: type: boolean default: false description: Whether this conversation is shared with others shareLink: type: string description: Shareable link if conversation is shared sharedWith: type: array items: type: object properties: userId: type: string format: objectId accessLevel: type: string enum: - read - write description: Users this conversation is shared with isArchived: type: boolean default: false description: Whether this conversation is archived archivedBy: type: string format: objectId nullable: true description: | User ID of the last user who archived this row, or `null` after unarchive cleared the archive state. Absent on rows that have never been archived. isDeleted: type: boolean default: false description: Whether this conversation has been soft-deleted. deletedBy: type: string format: objectId description: User who soft-deleted this conversation. conversationErrors: type: array description: Errors recorded against this conversation (e.g. failed message generations). items: type: object required: - message properties: message: type: string errorType: type: string timestamp: type: string format: date-time messageId: type: string format: objectId stack: type: string metadata: type: object additionalProperties: true metadata: type: object additionalProperties: true description: Free-form metadata attached to the conversation. lastActivityAt: type: integer description: Unix timestamp of last activity createdAt: type: string format: date-time updatedAt: type: string format: date-time isOwner: type: boolean description: | Computed per request. `true` when the requesting user is the conversation's `initiator`. readOnly: true accessLevel: type: string enum: - read - write description: | Computed per request. The requester's effective access level: their entry in `sharedWith`, or `read` by default. readOnly: true ConversationListItem: type: object description: | Conversation summary returned by list endpoints. Identical to `Conversation` but omits `messages` to keep list payloads small. Fetch a single conversation to retrieve its messages. properties: _id: type: string format: objectId userId: type: string format: objectId orgId: type: string format: objectId title: type: string initiator: type: string format: objectId status: type: string enum: - None - Inprogress - Complete - Failed failReason: type: string modelInfo: type: object properties: modelKey: type: string modelName: type: string modelFriendlyName: type: string modelProvider: type: string chatMode: type: string isShared: type: boolean shareLink: type: string sharedWith: type: array items: type: object properties: userId: type: string format: objectId accessLevel: type: string enum: - read - write isArchived: type: boolean archivedBy: type: string format: objectId nullable: true description: | User ID of the last user who archived this row, or `null` after unarchive cleared the archive state. Absent on rows that have never been archived. isDeleted: type: boolean deletedBy: type: string format: objectId conversationErrors: type: array items: type: object properties: message: type: string errorType: type: string timestamp: type: string format: date-time messageId: type: string format: objectId stack: type: string metadata: type: object additionalProperties: true metadata: type: object additionalProperties: true lastActivityAt: type: integer createdAt: type: string format: date-time updatedAt: type: string format: date-time isOwner: type: boolean readOnly: true accessLevel: type: string enum: - read - write readOnly: true SemanticSearchRequest: type: object description: | Request body for performing semantic search across the enterprise knowledge base. **How Semantic Search Works:** 1. Query is converted to vector embeddings 2. Similar content is found using vector similarity 3. Results are ranked by relevance score 4. Matching chunks with metadata are returned **Filtering:** Use filters to narrow search scope to specific apps or knowledge bases. required: - query properties: query: type: string minLength: 1 description: | Natural language search query. The system understands semantic meaning, not just keywords. example: employee onboarding procedures filters: $ref: '#/components/schemas/Filters' limit: type: integer minimum: 1 maximum: 100 default: 10 description: Maximum number of results to return SemanticSearchBoundingBox: type: object additionalProperties: false description: Normalized bounding region for a chunk (when available). properties: x: type: number y: type: number SemanticSearchHitMetadata: type: object additionalProperties: false description: | Per-hit metadata after retrieval enrichment (record + vector context). Listed fields are the documented contract; Qdrant or pipeline updates may add more keys over time—extend this schema when new stable fields appear. properties: orgId: type: string nullable: true recordId: type: string nullable: true virtualRecordId: type: string nullable: true recordName: type: string nullable: true recordType: type: string nullable: true recordVersion: nullable: true oneOf: - type: string - type: number origin: type: string nullable: true connector: type: string nullable: true connectorId: type: string nullable: true connectorName: type: string nullable: true blockText: type: string nullable: true blockType: type: string nullable: true description: | Block type for this hit. Common values: `text`, `image`, `table_row`, `table`, `record_summary` (whole-record semantic summary chunk — no block index). bounding_box: type: array nullable: true items: $ref: '#/components/schemas/SemanticSearchBoundingBox' pageNum: type: array nullable: true items: nullable: true type: integer extension: type: string nullable: true mimeType: type: string nullable: true blockNum: type: array nullable: true items: type: number chunkIndex: type: integer nullable: true sheetName: type: string nullable: true sheetNum: type: integer nullable: true webUrl: type: string nullable: true previewRenderable: type: boolean nullable: true hideWeburl: type: boolean nullable: true categories: type: array nullable: true items: type: string departments: type: array nullable: true items: type: string topics: type: array nullable: true items: type: string languages: type: array nullable: true items: type: string subcategoryLevel1: type: string nullable: true subcategoryLevel2: type: string nullable: true subcategoryLevel3: type: string nullable: true score: type: number nullable: true _id: type: string nullable: true _collection_name: type: string nullable: true blockIndex: type: integer nullable: true blockId: type: string nullable: true isBlock: type: boolean nullable: true isBlockGroup: type: boolean nullable: true isRecordSummary: type: boolean nullable: true description: | Set to `true` by the indexing pipeline when this vector chunk represents a whole-record semantic summary rather than an individual block. When true, `blockIndex` is absent and `block_type` on the parent hit is `record_summary`. kbId: type: string nullable: true description: Knowledge base id merged from graph record during retrieval (when present). point_id: description: Qdrant point identifier attached during vector lookup (shape varies by deployment). nullable: true oneOf: - type: string - type: integer - type: number SemanticSearchHit: type: object additionalProperties: false description: | One search hit returned by the retrieval service. Most hits use string `content`; table or grouped blocks may serialize structured payloads as JSON arrays. Listed fields are the documented contract; extend this schema when new stable top-level keys are introduced. properties: score: type: number nullable: true citationType: type: string nullable: true chunkIndex: type: integer nullable: true metadata: $ref: '#/components/schemas/SemanticSearchHitMetadata' content: type: string nullable: true virtual_record_id: type: string nullable: true block_type: type: string nullable: true description: | Block type for this hit. Common values: `text`, `image`, `table_row`, `table`, `record_summary` (whole-record semantic summary — `block_index` is `null` for these hits). block_index: type: integer nullable: true SemanticSearchGraphRecord: type: object description: | Graph record vertex returned in `records` and as values of `virtual_to_record_map`. All listed fields are optional in the schema so partial or evolving documents validate; typical Arango documents usually include `_key`, `_id`, `_rev`, `orgId`, `recordName`, `externalRecordId`, `recordType`, `origin`, `createdAtTimestamp`, and `connectorId`. Extend this schema when new stable fields appear on Record vertices. properties: _key: type: string nullable: true _id: type: string nullable: true _rev: type: string nullable: true recordName: type: string nullable: true externalRecordId: type: string nullable: true recordType: type: string nullable: true origin: type: string nullable: true createdAtTimestamp: type: number nullable: true connectorId: type: string nullable: true orgId: type: string nullable: true updatedAtTimestamp: type: number nullable: true externalGroupId: type: string nullable: true externalParentId: type: string nullable: true externalRevisionId: type: string nullable: true externalRootGroupId: type: string nullable: true recordGroupId: type: string nullable: true version: type: number nullable: true connectorName: type: string nullable: true mimeType: type: string nullable: true webUrl: type: string nullable: true lastSyncTimestamp: type: number nullable: true sourceCreatedAtTimestamp: type: number nullable: true sourceLastModifiedTimestamp: type: number nullable: true isDeleted: type: boolean nullable: true isArchived: type: boolean nullable: true isVLMOcrProcessed: type: boolean nullable: true deletedByUserId: type: string nullable: true indexingStatus: type: string nullable: true extractionStatus: type: string nullable: true isLatestVersion: type: boolean nullable: true isDirty: type: boolean nullable: true reason: type: string nullable: true lastIndexTimestamp: type: number nullable: true lastExtractionTimestamp: type: number nullable: true summaryDocumentId: type: string nullable: true virtualRecordId: type: string nullable: true previewRenderable: type: boolean nullable: true isShared: type: boolean nullable: true isDependentNode: type: boolean nullable: true parentNodeId: type: string nullable: true hideWeburl: type: boolean nullable: true isInternal: type: boolean nullable: true md5Checksum: type: string nullable: true sizeInBytes: type: number nullable: true definition: type: string nullable: true sourceTables: type: array nullable: true items: type: string rowCount: type: number nullable: true SemanticSearchAppliedFilters: type: object additionalProperties: false description: Present when KB filters were applied to the search request. required: - kb - kb_count properties: kb: type: array items: type: string kb_count: type: integer SemanticSearchAiResponse: type: object additionalProperties: false description: | Payload returned by the AI retrieval service for a semantic search (embedded in `searchResponse`). Optional `virtual_to_record_map` maps each virtual record id (string key) to one resolved graph record document. Empty responses from the retrieval layer omit `virtual_to_record_map`; success payloads may include it alongside hits and records. required: - searchResults - records - status - status_code - message properties: searchResults: type: array items: $ref: '#/components/schemas/SemanticSearchHit' records: type: array items: $ref: '#/components/schemas/SemanticSearchGraphRecord' status: type: string status_code: type: integer message: type: string appliedFilters: $ref: '#/components/schemas/SemanticSearchAppliedFilters' virtual_to_record_map: type: object description: Maps virtual record id (object property name) to the accessible graph record document for that id. additionalProperties: $ref: '#/components/schemas/SemanticSearchGraphRecord' SemanticSearchExecuteResponse: type: object additionalProperties: false description: | Immediate POST `/search` response: persisted search id plus the raw retrieval payload. SDK-oriented modeling: named fields only at this level; dynamic-key maps inside `searchResponse` use `additionalProperties` with a `$ref` (e.g. `virtual_to_record_map`) rather than boolean `additionalProperties: true`, so generated clients retain typed values where possible. required: - searchId - searchResponse properties: searchId: type: string format: objectId searchResponse: $ref: '#/components/schemas/SemanticSearchAiResponse' PersistedSemanticSearchBoundingBox: type: object additionalProperties: false description: | Bounding box subdocument embedded in persisted citation metadata. `boundingBoxSchema` does not set `_id: false`, so Mongoose auto-injects an `_id`. required: - _id - x - y properties: _id: type: string format: objectId x: type: number y: type: number PersistedSemanticSearchCitationMetadata: type: object additionalProperties: false description: | Citation metadata as persisted in MongoDB. Required fields mirror the Mongoose schema's `required: true` flags; the rest are optional and may come through as `null` because the AI retrieval service emits explicit nulls for absent fields. required: - orgId - mimeType - recordId - recordName - origin properties: orgId: type: string mimeType: type: string recordId: type: string recordName: type: string origin: type: string recordVersion: type: integer nullable: true extension: type: string nullable: true webUrl: type: string nullable: true previewRenderable: type: boolean nullable: true hideWeburl: type: boolean nullable: true connector: type: string nullable: true recordType: type: string nullable: true blockNum: type: array nullable: true items: type: number nullable: true pageNum: type: array nullable: true items: type: number nullable: true sheetNum: type: number nullable: true sheetName: type: string nullable: true bounding_box: type: array nullable: true items: $ref: '#/components/schemas/PersistedSemanticSearchBoundingBox' blockType: type: string nullable: true description: | Block type for this citation. Common values: `text`, `image`, `table_row`, `table`, `record_summary` (whole-record semantic summary chunk). blockText: type: string nullable: true departments: type: array nullable: true items: type: string languages: type: array nullable: true items: type: string topics: type: array nullable: true items: type: string PersistedSemanticSearchCitation: type: object additionalProperties: false description: | Populated citation document referenced from a persisted search. The controller strips `__v` via `populate({ select: '-__v' })`. required: - _id - content - chunkIndex - citationType - metadata - createdAt - updatedAt properties: _id: type: string format: objectId content: type: string chunkIndex: type: integer citationType: type: string metadata: $ref: '#/components/schemas/PersistedSemanticSearchCitationMetadata' createdAt: type: string format: date-time updatedAt: type: string format: date-time PersistedSemanticSearchSharedWithEntry: type: object additionalProperties: false description: | Entry inside `sharedWith[]`. The schema sets `_id: false` on these sub-docs, so no auto-injected `_id` is present. required: - userId - accessLevel properties: userId: type: string format: objectId accessLevel: type: string enum: - read - write PersistedSemanticSearch: type: object additionalProperties: false description: | Persisted search document as returned to clients. `records` is a string-valued map: each value is `JSON.stringify()`, keyed by the source record's `_id` or `_key`. Clients must `JSON.parse` each value to recover the underlying record object (whose shape resembles `SemanticSearchGraphRecord`). This intentionally differs from the `searchResponse.records` array on the POST `/search` response, which is passed through from the retrieval service untouched. required: - _id - __v - query - limit - orgId - userId - citationIds - records - isShared - sharedWith - isArchived - createdAt - updatedAt properties: _id: type: string format: objectId __v: type: integer query: type: string limit: type: integer orgId: type: string format: objectId userId: type: string format: objectId citationIds: type: array items: $ref: '#/components/schemas/PersistedSemanticSearchCitation' records: type: object description: | Map of source-record id (or `_key`) to a JSON-stringified record object. Clients must `JSON.parse` each value before reading fields. additionalProperties: type: string isShared: type: boolean shareLink: type: string description: Set once the search has been shared via `/search/{searchId}/share`. sharedWith: type: array items: $ref: '#/components/schemas/PersistedSemanticSearchSharedWithEntry' isArchived: type: boolean archivedBy: type: string format: objectId nullable: true description: | User ID of the last user who archived this row, or `null` after an unarchive cleared the archive state. Absent on rows that have never been archived. Currently-archived rows cannot reach this endpoint because `buildFilter` enforces `isArchived: false`. createdAt: type: string format: date-time updatedAt: type: string format: date-time PersistedSemanticSearchEnvelope: type: array description: | GET `/search/{searchId}` calls `Model.find()` (not `findOne()`) and sends the result as-is, so the wire format is an array of zero or one persisted search docs. A non-existent id returns `200 []`, **not** `404`. items: $ref: '#/components/schemas/PersistedSemanticSearch' SemanticSearchHistoryItem: type: object additionalProperties: false description: | One persisted search row as returned by `GET /search`. Mirrors the persisted search document except `citationIds` is an array of ObjectId strings (citations are not populated on the list endpoint, unlike `GET /search/{searchId}`). `shareLink` is absent from the JSON when the search has not been shared. `archivedBy` is `null` on rows that were previously archived and then unarchived, and absent on rows that have never been archived. The list endpoint already filters out currently-archived rows, so a string user-id value never appears here in practice. required: - _id - __v - query - limit - orgId - userId - citationIds - records - isShared - sharedWith - isArchived - createdAt - updatedAt properties: _id: type: string format: objectId __v: type: integer query: type: string limit: type: integer orgId: type: string format: objectId userId: type: string format: objectId citationIds: type: array items: type: string format: objectId records: type: object description: | Map of source-record id (or `_key`) to `JSON.stringify()`. Clients must `JSON.parse` each value to recover the underlying record object. Populated at write-time in the POST `/search` handler. additionalProperties: type: string isShared: type: boolean shareLink: type: string description: Set once the search has been shared via `/search/{searchId}/share`. sharedWith: type: array items: $ref: '#/components/schemas/PersistedSemanticSearchSharedWithEntry' isArchived: type: boolean archivedBy: type: string format: objectId nullable: true description: | User ID of the last user who archived this row, or `null` after an unarchive cleared the archive state. Absent on rows that have never been archived. createdAt: type: string format: date-time updatedAt: type: string format: date-time SemanticSearchHistoryPagination: type: object additionalProperties: false description: | Pagination block emitted by `buildPaginationMetadata` (utils.ts:417). `totalPages` is `Math.ceil(totalCount / limit)`, so an empty result has `totalPages: 0`, not `1`. required: - page - limit - totalCount - totalPages - hasNextPage - hasPrevPage properties: page: type: integer limit: type: integer totalCount: type: integer totalPages: type: integer hasNextPage: type: boolean hasPrevPage: type: boolean SemanticSearchHistoryAppliedDateRange: type: object additionalProperties: false description: | Echoed back only when the caller passed `startDate` and/or `endDate`. Each bound is an ISO 8601 string when set; the field is absent when the corresponding query param was omitted (utils.ts:480-486 reads `appliedFilters.createdAt.$gte?.toISOString()` directly, so missing bounds become `undefined` and drop out of the JSON). properties: start: type: string format: date-time end: type: string format: date-time SemanticSearchHistoryFiltersApplied: type: object additionalProperties: false description: | Echo of which filters the caller actually supplied, built by `buildFiltersMetadata` (utils.ts:430-486). `page` and `limit` always appear because they are normalised to defaults before being recorded, so `filters` is never empty and `values` always contains at least `{ page, limit }`. Other keys appear only when the matching query param was non-empty (or, for `dateRange`, when `createdAt` was set on the Mongo filter). `values` keys are scalar strings rather than typed primitives (`'true'`/`'false'`, `'5'`, etc.) because they are passed through from `req.query` as Express parsed them — only `page` and `limit` are coerced to integers via `safeParsePagination`. required: - filters - values properties: filters: type: array items: type: string enum: - page - limit - search - shared - tags - minMessages - sortBy - sortOrder - startDate - endDate - messageType - dateRange values: type: object additionalProperties: false properties: page: type: integer limit: type: integer search: type: string shared: type: string tags: type: string minMessages: type: string sortBy: type: string sortOrder: type: string startDate: type: string endDate: type: string messageType: type: string dateRange: $ref: '#/components/schemas/SemanticSearchHistoryAppliedDateRange' SemanticSearchHistoryFilterToggle: type: object additionalProperties: false description: | Generic "filter X is available, current value is Y" block used for `shared`, `tags`, `minMessages`, `search`, and `messageType`. Either `type` (free-form value) or `values` (enum of allowed strings) is present, not both. `current` is the caller-supplied value passed through from `req.query`, hence string-or-null even when `type` is `'number'`. required: - description - current - applied properties: type: type: string values: type: array items: type: string description: type: string current: type: string nullable: true applied: type: boolean SemanticSearchHistoryPaginationField: type: object additionalProperties: false required: - type - current - min - max - default - description - applied properties: type: type: string current: type: integer min: type: integer max: type: integer default: type: integer description: type: string applied: type: boolean SemanticSearchHistorySortField: type: object additionalProperties: false description: | Used for `available.sorting.{sortBy,sortOrder}` and `available.sortingMessages.{sortBy,sortOrder}`. The `applied` flag is present on `sorting.*` and absent on `sortingMessages.*`, so it is optional here. required: - values - default - description - current properties: values: type: array items: type: string default: type: string description: type: string current: type: string applied: type: boolean SemanticSearchHistoryDateRange: type: object additionalProperties: false required: - type - description - format - current - applied properties: type: type: string description: type: string format: type: string current: type: object additionalProperties: false required: - start - end properties: start: type: string nullable: true end: type: string nullable: true applied: type: boolean SemanticSearchHistoryFiltersAvailable: type: object additionalProperties: false description: | Catalogue of filters the endpoint supports, plus their current values and `applied` flags. Built by `buildFiltersMetadata` (utils.ts:430-624). required: - shared - tags - minMessages - search - pagination - sorting - dateFilters - messageFilters - sortingMessages properties: shared: $ref: '#/components/schemas/SemanticSearchHistoryFilterToggle' tags: $ref: '#/components/schemas/SemanticSearchHistoryFilterToggle' minMessages: $ref: '#/components/schemas/SemanticSearchHistoryFilterToggle' search: $ref: '#/components/schemas/SemanticSearchHistoryFilterToggle' pagination: type: object additionalProperties: false required: - page - limit properties: page: $ref: '#/components/schemas/SemanticSearchHistoryPaginationField' limit: $ref: '#/components/schemas/SemanticSearchHistoryPaginationField' sorting: type: object additionalProperties: false required: - sortBy - sortOrder properties: sortBy: $ref: '#/components/schemas/SemanticSearchHistorySortField' sortOrder: $ref: '#/components/schemas/SemanticSearchHistorySortField' dateFilters: type: object additionalProperties: false required: - dateRange properties: dateRange: $ref: '#/components/schemas/SemanticSearchHistoryDateRange' messageFilters: type: object additionalProperties: false required: - messageType properties: messageType: $ref: '#/components/schemas/SemanticSearchHistoryFilterToggle' sortingMessages: type: object additionalProperties: false required: - sortBy - sortOrder properties: sortBy: $ref: '#/components/schemas/SemanticSearchHistorySortField' sortOrder: $ref: '#/components/schemas/SemanticSearchHistorySortField' SemanticSearchHistoryFilters: type: object additionalProperties: false required: - applied - available properties: applied: $ref: '#/components/schemas/SemanticSearchHistoryFiltersApplied' available: $ref: '#/components/schemas/SemanticSearchHistoryFiltersAvailable' SemanticSearchHistoryMeta: type: object additionalProperties: false description: | `requestId` comes from `req.context?.requestId` and is omitted from the JSON when upstream middleware did not set it. required: - timestamp - duration properties: requestId: type: string timestamp: type: string format: date-time duration: type: integer SemanticSearchHistoryResponse: type: object additionalProperties: false description: | Envelope returned by `GET /search`. The handler runs `find()` plus `countDocuments()` in parallel and assembles `{ searchHistory, pagination, filters, meta }` (es_controller.ts:3925-3973). required: - searchHistory - pagination - filters - meta properties: searchHistory: type: array items: $ref: '#/components/schemas/SemanticSearchHistoryItem' pagination: $ref: '#/components/schemas/SemanticSearchHistoryPagination' filters: $ref: '#/components/schemas/SemanticSearchHistoryFilters' meta: $ref: '#/components/schemas/SemanticSearchHistoryMeta' AgentKnowledgeFiltersParsed: type: object additionalProperties: false description: | Indexed scope for a knowledge connector: record-group ids (collections / KB roots) and individual record ids. First-party create/update flows set `recordGroups` and `records`. On GET, `filtersParsed` is this shape parsed from the stored `filters` JSON string. properties: recordGroups: type: array items: type: string description: Record-group ids (e.g. knowledge-base roots) in scope. records: type: array items: type: string description: Individual record ids in scope. Toolset: type: object additionalProperties: false description: | Toolset instance linked to an agent, as projected by the graph store on `GET /agents/{agentKey}` and `GET /agents`. Multiple instances of the same integration type are distinguished by `instanceId` and optional `instanceName`. properties: _key: type: string description: Toolset instance node key in the backing graph store. name: allOf: - $ref: '#/components/schemas/AgentCreateToolsetName' description: Integration / toolset type key. displayName: type: string description: Human-readable toolset product label (for example `Jira` or `Slack`). type: type: string instanceId: type: string description: Admin-created toolset instance id instanceName: type: string description: Human-readable instance label (e.g. sidebar instance name) selectedTools: type: array nullable: true description: | Tool names explicitly selected for this toolset instance, when the instance was created with a subset selection. `null`/absent when the instance exposes all of the toolset's tools. items: type: string tools: type: array items: type: object additionalProperties: false properties: _key: type: string description: Tool node key in the backing graph store. name: type: string fullName: type: string toolsetName: type: string description: Toolset type key the tool belongs to. description: type: string deprecated: type: boolean readOnly: true description: | Server-stamped on `GET /agents/{agentKey}`: `true` when the tool's `fullName` is no longer in the runtime tool registry (its `@tool` was removed). Read-only; ignored on create/update bodies. Not stamped on the `GET /agents` list projection. AgentFilters: description: | Knowledge scope filter as stored on the graph edge. The Node `getAgent` handler proxies this field unchanged from the AI service (only `agent.id` is stripped). May be a JSON string (typical graph storage) or an object. Prefer `filtersParsed` on GET for a guaranteed parsed object with the same keys as the object branch below. oneOf: - $ref: '#/components/schemas/AgentKnowledgeFiltersParsed' - type: string description: JSON-encoded filter object (graph storage format). Knowledge: type: object additionalProperties: false description: | Knowledge connector / indexed scope linked to an agent, as projected by the graph store on `GET /agents/{agentKey}` and `GET /agents`. properties: _key: type: string connectorId: type: string name: type: string type: type: string displayName: type: string filters: $ref: '#/components/schemas/AgentFilters' filtersParsed: readOnly: true description: | Server-derived read-only object parsed from the stored `filters` JSON by the graph provider on GET (Neo4j / Arango). Empty object when `filters` is missing or invalid JSON. allOf: - $ref: '#/components/schemas/AgentKnowledgeFiltersParsed' Agent: type: object additionalProperties: false description: | Detailed agent projection returned by agent detail-style endpoints such as `GET /agents/{agentKey}`. properties: _id: type: string description: Full document id in the backing graph store. example: agentInstances/e6f848ca-e2ab-4594-9925-e1136629f474 _key: type: string description: Stable agent key used in route params. example: e6f848ca-e2ab-4594-9925-e1136629f474 _rev: type: string description: Backend document revision token. example: _lkNlcOm--- name: type: string description: Display name of the agent example: Customer Support Assistant description: type: string description: What this agent is designed to do systemPrompt: type: string description: System instructions that define agent behavior createdBy: type: string format: objectId description: MongoDB user ID of the agent creator startMessage: type: string description: Initial greeting shown when a conversation with this agent starts instructions: type: string nullable: true description: Additional agent execution instructions models: type: array description: | Configured model entries for this agent. example: - modelType: llm provider: azureOpenAI modelName: gpt-5.4-mini modelKey: f3a4b5b6-5b6c-4e85-9097-3202cfe696fc isMultimodal: true isReasoning: true isDefault: true modelFriendlyName: GPT 5.4 mini items: oneOf: - type: string - type: object additionalProperties: false properties: modelKey: type: string modelName: type: string provider: type: string isReasoning: type: boolean isMultimodal: type: boolean isDefault: type: boolean modelType: type: string description: | Model category. Must be `llm` for agent model entries (same value as `ModelType` for LLMs; string only — enum is not used here). example: llm modelFriendlyName: type: string toolsets: type: array description: | Toolset instances linked to the agent (GET /agents/{agentKey} graph projection). Multiple instances of the same integration type are distinguished by `instanceId` and optional `instanceName`. items: $ref: '#/components/schemas/Toolset' knowledge: type: array description: Knowledge connectors and indexed scopes linked to the agent items: $ref: '#/components/schemas/Knowledge' shareWithOrg: type: boolean description: Whether the agent is shared with the whole organization webSearch: type: object additionalProperties: false nullable: true description: Web search provider attached to this agent. Null when none is configured. properties: provider: type: string description: Provider identifier (e.g. "tavily", "serper", "exa", "duckduckgo") providerKey: type: string providerLabel: type: string required: - provider example: provider: serper tags: type: array items: type: string description: Free-form agent tags. createdAtTimestamp: type: integer format: int64 description: Unix epoch timestamp in milliseconds when the agent was created. updatedAtTimestamp: type: integer format: int64 description: Unix epoch timestamp in milliseconds when the agent was last updated. updatedBy: type: string nullable: true description: User id of the last updater, if present. isActive: type: boolean description: Whether the agent is active. isDeleted: type: boolean description: Whether the agent has been soft-deleted. isServiceAccount: type: boolean description: Whether this agent is a service-account agent. access_type: type: string description: How the user can access this agent. example: INDIVIDUAL user_role: type: string description: Effective role of the current user on this agent. example: OWNER can_view: type: boolean description: Effective permission to view the agent. can_share: type: boolean description: Effective permission to share the agent. can_edit: type: boolean description: Effective permission to edit the agent. can_delete: type: boolean description: Effective permission to delete the agent. required: - _id - _key - createdAtTimestamp - createdBy - isActive - isDeleted - isServiceAccount - models - name - tags - updatedAtTimestamp - shareWithOrg - knowledge - toolsets - can_view - can_share - can_edit - can_delete - user_role - access_type AgentListItem: type: object additionalProperties: false description: | Agent projection returned by `GET /agents`. This is the list-view envelope item emitted by the Python backend and forwarded by the Node gateway. It is not the full detail projection used by `GET /agents/{agentKey}`. properties: _id: type: string description: Full document id in the backing graph store. example: agentInstances/e6f848ca-e2ab-4594-9925-e1136629f474 _key: type: string description: Stable agent key used in route params. example: e6f848ca-e2ab-4594-9925-e1136629f474 _rev: type: string description: Backend document revision token. example: _lkNlcOm--- createdAtTimestamp: type: integer format: int64 description: Unix epoch timestamp in milliseconds when the agent was created. createdBy: type: string description: MongoDB user ID of the agent creator description: type: string nullable: true description: Short human-readable description of the agent. instructions: type: string nullable: true description: Additional execution instructions stored on the agent. isActive: type: boolean description: Whether the agent is active. isDeleted: type: boolean description: Whether the agent has been soft-deleted. isServiceAccount: type: boolean description: Whether this agent is a service-account agent. models: type: array description: | Model entries configured on the agent. For `GET /agents`, the backend returns the stored normalized string representation, typically `modelKey_modelName`. items: type: string name: type: string description: Display name of the agent. startMessage: type: string nullable: true description: Greeting shown at conversation start. systemPrompt: type: string nullable: true description: System prompt stored on the agent. tags: type: array items: type: string description: Free-form agent tags. updatedAtTimestamp: type: integer format: int64 description: Unix epoch timestamp in milliseconds when the agent was last updated. updatedBy: type: string nullable: true description: User id of the last updater, if present. webSearch: type: object additionalProperties: false nullable: true description: | Web-search provider attachment for this agent, or `null` when none is attached. For `GET /agents`, the response formatter always emits `provider`. It may also emit `providerKey` and `providerLabel` when those values were present on the stored attachment. It does not emit `iconPath` on this response path. properties: provider: type: string providerKey: type: string providerLabel: type: string shareWithOrg: type: boolean description: Whether the agent is shared with the organization. toolsets: type: array description: | Toolset instances linked to the agent. Same projection as `GET /agents/{agentKey}`; the backend builds it from the graph edges for each agent on the returned page. items: $ref: '#/components/schemas/Toolset' knowledge: type: array description: | Knowledge connectors and indexed scopes linked to the agent. Same projection as `GET /agents/{agentKey}`; the backend builds it from the graph edges for each agent on the returned page. items: $ref: '#/components/schemas/Knowledge' can_view: type: boolean description: Effective permission to view the agent. can_share: type: boolean description: Effective permission to share the agent. can_edit: type: boolean description: Effective permission to edit the agent. can_delete: type: boolean description: Effective permission to delete the agent. user_role: type: string description: Effective role of the current user on this agent. example: OWNER access_type: type: string description: How the user can access this agent. example: INDIVIDUAL required: - _id - _key - createdAtTimestamp - createdBy - isActive - isDeleted - isServiceAccount - models - name - tags - updatedAtTimestamp - shareWithOrg - toolsets - knowledge - can_view - can_share - can_edit - can_delete - user_role - access_type AgentListPagination: type: object additionalProperties: false description: Pagination block returned by `GET /agents`. required: - currentPage - limit - totalItems - totalPages - hasNext - hasPrev properties: currentPage: type: integer description: Current 1-based page number. example: 1 limit: type: integer description: Page size actually applied by the backend. example: 20 totalItems: type: integer description: Total number of matching agents across all pages. example: 2 totalPages: type: integer description: Total number of pages for the current query. example: 1 hasNext: type: boolean description: Whether a later page exists. example: false hasPrev: type: boolean description: Whether an earlier page exists. example: false AgentListResponse: type: object additionalProperties: false description: | Paginated response returned by `GET /agents`. The Node gateway forwards the Python backend response on success. If the backend returns a non-200 response, the gateway still returns HTTP 200 with `success: true`, an empty `agents` array, and a zeroed pagination block derived from the requested `page` / `limit`. required: - success - agents - pagination properties: success: type: boolean example: true agents: type: array items: $ref: '#/components/schemas/AgentListItem' pagination: $ref: '#/components/schemas/AgentListPagination' GetAgentResponse: type: object additionalProperties: false description: | Success envelope returned by `GET /agents/{agentKey}`. The Node gateway forwards the backend response as an envelope with a top-level status/message and the detailed agent projection nested under `agent`. required: - status - message - agent properties: status: type: string example: success message: type: string example: Agent retrieved successfully agent: $ref: '#/components/schemas/Agent' AgentCreateModelEntry: description: | Accepted model entry for `POST /agents/create`. The gateway accepts either a non-empty string model entry or an object entry with a required `modelKey`. The `models` array must include at least one object entry with `isReasoning: true`. String-only entries are schema-valid but are rejected at the gateway with HTTP 400. oneOf: - type: string minLength: 1 - type: object additionalProperties: false required: - modelKey properties: modelKey: type: string minLength: 1 modelName: type: string provider: type: string isReasoning: type: boolean AgentCreateToolRef: type: object additionalProperties: false required: - name properties: name: type: string fullName: type: string description: type: string maxLength: 10000 AgentCreateToolsetName: type: string description: Registered toolset name (lowercase) accepted by the create-agent gateway. enum: - calendar - clickup - confluence - drive - github - gmail - jira - lumos - mariadb - onedrive - outlook - redshift - salesforce - sharepoint - slack - teams - zoom AgentCreateToolset: type: object additionalProperties: false required: - name properties: name: $ref: '#/components/schemas/AgentCreateToolsetName' displayName: type: string maxLength: 200 type: type: string maxLength: 100 instanceId: type: string maxLength: 256 instanceName: type: string maxLength: 200 tools: type: array items: $ref: '#/components/schemas/AgentCreateToolRef' AgentCreateKnowledge: type: object additionalProperties: false required: - connectorId properties: connectorId: type: string filters: oneOf: - $ref: '#/components/schemas/AgentKnowledgeFiltersParsed' - type: string - type: array items: {} AgentCreateWebSearch: description: | Accepted web-search attachment for `POST /agents/create`. The gateway accepts either a provider string or an object with at least a `provider` field. anyOf: - type: string - type: object additionalProperties: false properties: provider: type: string providerKey: type: string maxLength: 256 providerLabel: type: string maxLength: 200 iconPath: type: string maxLength: 500 required: - provider - type: 'null' AgentCreateRequest: type: object additionalProperties: false required: - name - models properties: name: type: string minLength: 1 maxLength: 200 description: Agent display name example: Product Support Agent description: type: string maxLength: 100000 description: What the agent does startMessage: type: string maxLength: 100000 description: Initial greeting shown when conversation starts systemPrompt: type: string maxLength: 100000 description: System instructions for the agent instructions: type: string maxLength: 100000 description: Additional agent execution instructions models: type: array minItems: 1 description: | Agent model configuration entries. The gateway requires at least one object entry with `isReasoning: true`. String-only arrays are schema-valid but rejected at runtime with HTTP 400. items: $ref: '#/components/schemas/AgentCreateModelEntry' tags: type: array maxItems: 50 items: type: string maxLength: 100 shareWithOrg: type: boolean default: false description: Share agent with the organization isServiceAccount: type: boolean default: false description: Create the agent as a service-account agent toolsets: type: array maxItems: 100 description: Toolsets attached to the agent (instance-aware) items: $ref: '#/components/schemas/AgentCreateToolset' knowledge: type: array maxItems: 100 description: Knowledge sources connected to the agent items: $ref: '#/components/schemas/AgentCreateKnowledge' webSearch: $ref: '#/components/schemas/AgentCreateWebSearch' AgentCreateWarning: type: object additionalProperties: false properties: name: type: string error: type: string AgentCreateResponseTool: type: object additionalProperties: false required: - name - fullName - key properties: name: type: string fullName: type: string key: type: string AgentCreateResponseToolset: type: object additionalProperties: false required: - name - displayName - key - tools properties: name: $ref: '#/components/schemas/AgentCreateToolsetName' displayName: type: string description: Human-readable toolset product label (for example `Jira` or `Slack`). key: type: string tools: type: array items: $ref: '#/components/schemas/AgentCreateResponseTool' AgentCreateResponseKnowledge: type: object additionalProperties: false required: - connectorId - key - filters properties: connectorId: type: string key: type: string filters: oneOf: - type: object additionalProperties: true - type: string - type: array items: {} AgentCreateResponseAgent: type: object additionalProperties: false required: - _key - name - description - startMessage - systemPrompt - instructions - models - tags - webSearch - isActive - isServiceAccount - createdBy - updatedBy - createdAtTimestamp - updatedAtTimestamp - isDeleted - toolsets - knowledge properties: _key: type: string name: type: string description: type: string startMessage: type: string systemPrompt: type: string instructions: type: string nullable: true models: type: array items: type: string tags: type: array items: type: string webSearch: anyOf: - type: object additionalProperties: false properties: provider: type: string providerKey: type: string providerLabel: type: string - type: 'null' isActive: type: boolean isServiceAccount: type: boolean createdBy: type: string updatedBy: type: string nullable: true createdAtTimestamp: type: integer updatedAtTimestamp: type: integer isDeleted: type: boolean toolsets: type: array items: $ref: '#/components/schemas/AgentCreateResponseToolset' knowledge: type: array items: $ref: '#/components/schemas/AgentCreateResponseKnowledge' AgentCreateResponse: type: object additionalProperties: false required: - status - message - agent properties: status: type: string enum: - success - partial_success message: type: string agent: $ref: '#/components/schemas/AgentCreateResponseAgent' warnings: anyOf: - type: array items: $ref: '#/components/schemas/AgentCreateWarning' - type: 'null' AgentUpdateRequest: type: object additionalProperties: false description: | Partial update payload for `PUT /agents/{agentKey}`. Every field is optional — only the fields present in the request body are updated. When `models` is included, the gateway Zod middleware (mirroring the Python backend) requires at least one model entry and at least one object entry with `isReasoning: true`. properties: name: type: string minLength: 1 maxLength: 200 description: Agent display name example: Renamed Agent description: type: string maxLength: 100000 description: What the agent does startMessage: type: string maxLength: 100000 description: Initial greeting shown when conversation starts systemPrompt: type: string maxLength: 100000 description: System instructions for the agent instructions: type: string maxLength: 100000 description: Additional agent execution instructions models: type: array minItems: 1 description: | Agent model configuration entries. When present, the Zod middleware requires at least one object entry with `isReasoning: true`. String-only arrays are schema-valid but rejected at runtime with HTTP 400. items: $ref: '#/components/schemas/AgentCreateModelEntry' tags: type: array maxItems: 50 items: type: string maxLength: 100 shareWithOrg: type: boolean default: false description: Share agent with the organization isServiceAccount: type: boolean default: false description: Mark agent as a service account toolsets: type: array maxItems: 100 description: Toolsets attached to the agent (instance-aware) items: $ref: '#/components/schemas/AgentCreateToolset' knowledge: type: array maxItems: 100 description: Knowledge sources connected to the agent items: $ref: '#/components/schemas/AgentCreateKnowledge' webSearch: $ref: '#/components/schemas/AgentCreateWebSearch' AgentUpdateResponse: type: object additionalProperties: false required: - status - message properties: status: type: string enum: - success message: type: string example: Agent updated successfully AgentDeleteResponse: type: object additionalProperties: false required: - status - message - deleted properties: status: type: string enum: - success message: type: string example: Agent deleted successfully deleted: type: object additionalProperties: false required: - agents - toolsets - tools - knowledge - edges properties: agents: type: integer minimum: 0 example: 1 toolsets: type: integer minimum: 0 example: 0 tools: type: integer minimum: 0 example: 0 knowledge: type: integer minimum: 0 example: 0 edges: type: integer minimum: 0 example: 0 AgentConversationListItem: type: object additionalProperties: false description: | Conversation summary returned by `GET /agents/{agentKey}/conversations`. The handler excludes `messages` and `__v` from both result sets. Rows in `sharedWithMeConversations` also omit `sharedWith` because the secondary query explicitly deselects that field before serialization. properties: _id: type: string format: objectId agentKey: type: string description: Agent identifier from the route path userId: type: string format: objectId orgId: type: string format: objectId title: type: string initiator: type: string format: objectId status: type: string enum: - None - Inprogress - Complete - Failed failReason: type: string modelInfo: $ref: '#/components/schemas/ConversationModelInfo' isShared: type: boolean shareLink: type: string sharedWith: type: array items: type: object additionalProperties: false properties: userId: type: string format: objectId accessLevel: type: string enum: - read - write isArchived: type: boolean archivedBy: type: string format: objectId nullable: true archivedAt: type: string format: date-time description: | Present on archived conversation endpoints. Derived from the document `updatedAt` timestamp when the archive response is built. isDeleted: type: boolean deletedBy: type: string format: objectId nullable: true conversationErrors: type: array items: type: object additionalProperties: false properties: message: type: string errorType: type: string timestamp: type: string format: date-time messageId: type: string format: objectId stack: type: string metadata: type: object additionalProperties: true conversationSource: type: string enum: - agent_chat lastActivityAt: type: integer format: int64 description: Epoch milliseconds of the latest activity on the thread createdAt: type: string format: date-time updatedAt: type: string format: date-time isOwner: type: boolean readOnly: true description: | Computed per request. `true` when the conversation `initiator` matches the authenticated user. accessLevel: type: string enum: - read - write readOnly: true description: | Computed per request from `sharedWith`; defaults to `read` when no explicit share grant is attached to the serialized row. AgentConversationListResponse: type: object additionalProperties: false description: | Envelope returned by `GET /agents/{agentKey}/conversations`. `conversations` contains rows owned by the caller for the agent; `sharedWithMeConversations` contains rows shared with the caller for the same agent. Both arrays use the same pagination and sort inputs, but `pagination.totalCount` and `totalPages` are computed only from `conversations` because the handler counts the owned-query filter only. required: - conversations - sharedWithMeConversations - pagination - filters - meta properties: conversations: type: array items: $ref: '#/components/schemas/AgentConversationListItem' sharedWithMeConversations: type: array items: $ref: '#/components/schemas/AgentConversationListItem' pagination: $ref: '#/components/schemas/SemanticSearchHistoryPagination' filters: $ref: '#/components/schemas/SemanticSearchHistoryFilters' meta: $ref: '#/components/schemas/SemanticSearchHistoryMeta' AgentArchivedConversationGroup: type: object additionalProperties: false description: | Archived conversations for a single agent, sliced to the first page of the per-agent archive query (limit 5, sorted newest first). required: - agentKey - conversations - pagination properties: agentKey: type: string description: Agent identifier the conversations belong to. conversations: type: array items: $ref: '#/components/schemas/AgentConversationListItem' pagination: $ref: '#/components/schemas/SemanticSearchHistoryPagination' AgentArchivedGroupsResponse: type: object additionalProperties: false description: | Response from `GET /agents/conversations/show/archives` — archived agent conversations grouped by `agentKey`, with agent-level pagination over the groups and a fixed slice of conversations under each agent. required: - groups - agentPagination - meta properties: groups: type: array items: $ref: '#/components/schemas/AgentArchivedConversationGroup' agentPagination: $ref: '#/components/schemas/SemanticSearchHistoryPagination' meta: $ref: '#/components/schemas/RequestMeta' AgentArchivedConversationSummary: type: object additionalProperties: false description: | Archive counts and bounds for the current result page returned by `GET /agents/{agentKey}/conversations/show/archives`. properties: totalArchived: type: integer description: Total archived conversations matching the filter oldestArchive: type: string format: date-time description: Archive timestamp of the first item in the current page. Omitted when the page is empty. newestArchive: type: string format: date-time description: Archive timestamp of the last item in the current page. Omitted when the page is empty. AgentArchivedConversationListResponse: type: object additionalProperties: false description: | Envelope returned by `GET /agents/{agentKey}/conversations/show/archives`. required: - conversations - pagination - filters - summary - meta properties: conversations: type: array items: $ref: '#/components/schemas/AgentConversationListItem' pagination: $ref: '#/components/schemas/SemanticSearchHistoryPagination' filters: $ref: '#/components/schemas/SemanticSearchHistoryFilters' summary: $ref: '#/components/schemas/AgentArchivedConversationSummary' meta: $ref: '#/components/schemas/SemanticSearchHistoryMeta' RequestMeta: type: object additionalProperties: false description: Basic request metadata returned by the API. required: - timestamp - duration properties: requestId: type: string timestamp: type: string format: date-time duration: type: integer ConversationTitleUpdateRequest: type: object additionalProperties: false required: - title properties: title: type: string minLength: 1 maxLength: 200 description: New title for the conversation example: ABC News Follow-up StoredAgentConversation: type: object additionalProperties: false description: | Stored agent conversation document returned by non-list endpoints. properties: _id: type: string format: objectId agentKey: type: string userId: type: string format: objectId orgId: type: string format: objectId title: type: string initiator: type: string format: objectId messages: type: array items: $ref: '#/components/schemas/Message' status: type: string enum: - None - Inprogress - Complete - Failed failReason: type: string modelInfo: $ref: '#/components/schemas/ConversationModelInfo' isShared: type: boolean shareLink: type: string sharedWith: type: array items: type: object additionalProperties: false properties: userId: type: string format: objectId accessLevel: type: string enum: - read - write isArchived: type: boolean archivedBy: type: string format: objectId nullable: true isDeleted: type: boolean deletedBy: type: string format: objectId nullable: true conversationErrors: type: array items: type: object additionalProperties: false properties: _id: type: string format: objectId message: type: string errorType: type: string timestamp: type: string format: date-time messageId: type: string format: objectId stack: type: string metadata: type: object additionalProperties: true conversationSource: type: string enum: - agent_chat lastActivityAt: type: integer format: int64 createdAt: type: string format: date-time updatedAt: type: string format: date-time __v: type: integer AgentConversationTitleUpdateResponse: type: object additionalProperties: false required: - conversation - meta properties: conversation: $ref: '#/components/schemas/StoredAgentConversation' meta: $ref: '#/components/schemas/RequestMeta' AgentConversationDeleteResponse: type: object additionalProperties: false description: | Envelope returned by `DELETE /agents/{agentKey}/conversations/{conversationId}`. When the conversation does not exist, belongs to a different agent, or was already deleted, the API still returns HTTP 200 with `conversation: null`. required: - message - conversation properties: message: type: string enum: - Conversation deleted successfully conversation: nullable: true $ref: '#/components/schemas/StoredAgentConversation' AgentConversationDetailMessageCitation: type: object additionalProperties: false description: | Citation entry returned inside a conversation message after the handler populates `messages.citations.citationId` and rewrites each item to `{ citationId, citationData }`. properties: citationId: type: string format: objectId citationData: $ref: '#/components/schemas/Citation' AgentConversationDetailMessage: type: object additionalProperties: false description: | Message shape returned by `GET /agents/{agentKey}/conversations/{conversationId}`. The response spreads the stored message document and replaces `citations` with populated citation objects. properties: _id: type: string format: objectId messageType: type: string enum: - user_query - bot_response - error - feedback - system content: type: string contentFormat: type: string enum: - MARKDOWN - JSON - HTML citations: type: array items: $ref: '#/components/schemas/AgentConversationDetailMessageCitation' confidence: type: string enum: - Very High - High - Medium - Low - Unknown nullable: true description: | AI confidence in the answer. Present only on `bot_response` messages, and only when the model emitted a trailing confidence block. This field is now optional and nullable; it was previously always present and non-nullable. Treat a missing or `null` value as "no confidence reported" and guard before using it. Change effective in SDK v1.3.0 (v1.2.0 and earlier always populated it). followUpQuestions: type: array items: $ref: '#/components/schemas/FollowUpQuestion' feedback: type: array items: $ref: '#/components/schemas/MessageFeedback' referenceData: type: array description: | Reference identifiers surfaced from tool responses, used to scope follow-up queries. items: type: object additionalProperties: false properties: name: type: string description: Display name shown to the user. id: type: string description: Technical identifier (numeric ID, UUID, etc.). type: type: string description: Item type (e.g. `project`, `issue`, `file`, `notebook`, `page`). app: type: string description: | Source application (e.g. `jira`, `confluence`, `sharepoint`, `slack`, `drive`, `gmail`). webUrl: type: string description: URL to open the item in a browser. metadata: type: object additionalProperties: type: string description: | App-specific fields keyed by name (e.g. `key` for a Jira project, `siteId` for a SharePoint document). attachments: type: array description: | Files uploaded for this message turn (see `POST /agents/{agentKey}/conversations/attachments/upload`). items: $ref: '#/components/schemas/ChatAttachmentRef' tools: type: array description: Tool call results invoked during this message turn. items: type: object additionalProperties: false properties: toolName: type: string toolResult: {} modelInfo: $ref: '#/components/schemas/ConversationModelInfo' appliedFilters: $ref: '#/components/schemas/AppliedFilters' metadata: type: object additionalProperties: false properties: processingTimeMs: type: number modelVersion: type: string aiTransactionId: type: string createdAt: type: string format: date-time updatedAt: type: string format: date-time AgentConversationDetailPagination: type: object additionalProperties: false description: | Message pagination returned inside the `conversation` object. The handler paginates backwards from the end of the stored message array, then sorts the selected page in memory before serialization. required: - page - limit - totalCount - totalPages - hasNextPage - hasPrevPage - messageRange properties: page: type: integer limit: type: integer totalCount: type: integer totalPages: type: integer hasNextPage: type: boolean description: True when older messages exist outside the returned page hasPrevPage: type: boolean description: True when newer messages exist outside the returned page messageRange: type: object additionalProperties: false required: - start - end properties: start: type: integer end: type: integer AgentConversationDetailAccess: type: object additionalProperties: false properties: isOwner: type: boolean accessLevel: type: string enum: - read - write AgentConversationDetail: type: object additionalProperties: false description: | Reduced conversation view returned by the by-id GET route. This is not the raw `AgentConversation` document shape: fields like `agentKey`, `userId`, `orgId`, `conversationSource`, and root-level `messages` metadata outside the selected slice are omitted. required: - id - createdAt - isShared - sharedWith - messages - pagination - access properties: id: type: string format: objectId title: type: string initiator: type: string format: objectId createdAt: type: string format: date-time isShared: type: boolean sharedWith: type: array items: type: object additionalProperties: false properties: userId: type: string format: objectId accessLevel: type: string enum: - read - write status: type: string enum: - None - Inprogress - Complete - Failed failReason: type: string messages: type: array items: $ref: '#/components/schemas/AgentConversationDetailMessage' modelInfo: $ref: '#/components/schemas/ConversationModelInfo' pagination: $ref: '#/components/schemas/AgentConversationDetailPagination' access: $ref: '#/components/schemas/AgentConversationDetailAccess' AgentConversationDetailMeta: type: object additionalProperties: false description: | Request-scoped metadata returned by the by-id GET route. `requestId` is omitted when upstream middleware did not attach one. required: - timestamp - duration - conversationId - messageCount properties: requestId: type: string timestamp: type: string format: date-time duration: type: integer conversationId: type: string format: objectId messageCount: type: integer AgentConversationDetailResponse: type: object additionalProperties: false description: | Envelope returned by `GET /agents/{agentKey}/conversations/{conversationId}`. required: - conversation - filters - meta properties: conversation: $ref: '#/components/schemas/AgentConversationDetail' filters: $ref: '#/components/schemas/SemanticSearchHistoryFilters' meta: $ref: '#/components/schemas/AgentConversationDetailMeta' AgentConversationArchiveMeta: type: object additionalProperties: false description: | Request-scoped metadata returned by the archive route. `requestId` is omitted when upstream middleware did not attach one. required: - timestamp - duration properties: requestId: type: string timestamp: type: string format: date-time duration: type: integer AgentConversationArchiveResponse: type: object additionalProperties: false description: | Envelope returned by `POST /agents/{agentKey}/conversations/{conversationId}/archive`. required: - id - status - archivedBy - archivedAt - meta properties: id: type: string format: objectId status: type: string enum: - archived archivedBy: type: string format: objectId archivedAt: type: string format: date-time meta: $ref: '#/components/schemas/AgentConversationArchiveMeta' AgentConversationUnarchiveMeta: type: object additionalProperties: false description: | Request-scoped metadata returned by the unarchive route. `requestId` is omitted when upstream middleware did not attach one. required: - timestamp - duration properties: requestId: type: string timestamp: type: string format: date-time duration: type: integer AgentConversationUnarchiveResponse: type: object additionalProperties: false description: | Envelope returned by `POST /agents/{agentKey}/conversations/{conversationId}/unarchive`. required: - id - status - unarchivedBy - unarchivedAt - meta properties: id: type: string format: objectId status: type: string enum: - unarchived unarchivedBy: type: string format: objectId unarchivedAt: type: string format: date-time meta: $ref: '#/components/schemas/AgentConversationUnarchiveMeta' AgentRegenerateSSEEvent: type: object additionalProperties: false description: | SSE event envelope for `POST /agents/{agentKey}/conversations/{conversationId}/message/{messageId}/regenerate`. Stable events: - `connected` confirms the stream is open. - `complete` returns the updated conversation plus request metadata after the regenerated bot response is persisted. - `error` returns a failure message. Conversation lookup failures, unauthorized conversation access, and regenerate rule failures such as "not the last message" are reported here after the stream starts. Other events are forwarded from the agent backend and should be treated as informational updates. properties: event: type: string enum: - connected - status - tool_calls - tool_call - tool_success - tool_error - tool_result - tool_execution_complete - answer_chunk - restreaming - metadata - complete - error data: type: string description: JSON-encoded event payload. Shape depends on `event`. SSEEvent: type: object description: | Server-Sent Event envelope for streaming chat responses. `data` is a JSON-encoded string whose shape depends on `event`. Three events are emitted by the API layer and have stable shapes documented on the streaming routes: - `connected` — fired once on connection. Carries the newly created `conversationId` and `title` so the client can link the stream to a row before any tokens arrive. - `complete` — fired once after the AI backend finishes. Carries the full persisted `conversation` and a `meta` block with `requestId`, `timestamp` and `duration`. - `error` — fired when the stream fails. Carries an `error` message and optional `details`. The conversation row is marked FAILED before the stream closes. All other events are forwarded verbatim from the AI backend; their payloads are AI-backend defined and may evolve. Currently observed names include `status`, `answer_chunk`, `tool_call`, `tool_calls`, `tool_result`, `tool_success`, `tool_error`, `tool_execution_complete`, `restreaming`, and `metadata`. properties: event: type: string enum: - connected - status - answer_chunk - tool_call - tool_calls - tool_result - tool_success - tool_error - tool_execution_complete - restreaming - metadata - complete - error data: type: string description: JSON-encoded event payload. Shape depends on `event`. AssistantStreamSSEEvent: type: object description: | Server-Sent Event envelope for non-agent assistant chat streams (`internal_search` / `web_search` chat modes). `data` is a JSON-encoded string whose shape depends on `event`. Three events are emitted by the API layer with stable, server-defined shapes: - `connected` — `{ "message": string, "conversationId": string, "title": string }`. Fired once on connection so the client can link the stream to the new row before any tokens arrive. - `complete` — `{ "conversation": Conversation, "meta": { "requestId": string, "timestamp": string, "duration": number } }`. Fired once after the AI backend finishes. - `error` — `{ "error": string, "details"?: string }`. Fired when the stream fails; the conversation row is marked FAILED before close. The remaining events are forwarded from the Python query service. Their payloads are AI-backend defined and may evolve: - `status` — progress message describing the current pipeline stage (for example `started`, `searching`, `processing`, `checking_tools`, `generating_answer`, `transforming`). - `answer_chunk` — incremental token batch with running `accumulated` text and any new `citations`. - `tool_calls` — the assistant requested one or more tool calls. Carries the assistant message that triggered the tool round. - `tool_call` — emitted once per individual tool invocation as it starts. Payload includes `tool_name`, `tool_args`, and `call_id`. - `tool_success` — a tool finished successfully. Payload includes `tool_name`, `summary`, `call_id`, and any `record_info`. - `tool_error` — a tool invocation failed. Payload includes `tool_name`, `error`, and `call_id`. - `restreaming` — the LLM is being restarted with new context, for example before a citation-verification pass. Clients should ignore unknown event names rather than treating them as errors. properties: event: type: string enum: - connected - status - answer_chunk - tool_calls - tool_call - tool_success - tool_error - restreaming - complete - error data: type: string description: JSON-encoded event payload. Shape depends on `event`. AssistantMessageStreamSSEEvent: type: object description: | Server-Sent Event envelope for non-agent assistant follow-up message streams (`internal_search` / `web_search` chat modes) on an existing conversation. `data` is a JSON-encoded string whose shape depends on `event`. Same event vocabulary as the conversation-creation stream — only the `connected` and `complete` payloads differ because the conversation already exists when this route is called. Three events are emitted by the API layer with stable, server-defined shapes: - `connected` — `{ "message": string }`. Fired once on connection. No `conversationId` or `title` is included because the caller already passed the conversation ID in the URL. - `complete` — `{ "conversation": Conversation, "recordsUsed": number, "meta": { "requestId": string, "timestamp": string, "duration": number, "recordsUsed": number } }`. Fired once after the AI backend finishes. `recordsUsed` is the count of citations attached to the new assistant message. - `error` — `{ "error": string, "details"?: string }`. Fired when the stream fails; the conversation row is marked FAILED before close. The remaining events are forwarded from the Python query service. Their payloads are AI-backend defined and may evolve: - `status` — progress message describing the current pipeline stage (for example `started`, `transforming`, `searching`, `processing`, `checking_tools`, `generating_answer`). `transforming` is common on this route because follow-up turns always have prior history to rewrite the query against. - `answer_chunk` — incremental token batch with running `accumulated` text and any new `citations`. - `tool_calls` — the assistant requested one or more tool calls. Carries the assistant message that triggered the tool round. - `tool_call` — emitted once per individual tool invocation as it starts. Payload includes `tool_name`, `tool_args`, and `call_id`. - `tool_success` — a tool finished successfully. Payload includes `tool_name`, `summary`, `call_id`, and any `record_info`. - `tool_error` — a tool invocation failed. Payload includes `tool_name`, `error`, and `call_id`. - `restreaming` — the LLM is being restarted with new context, for example before a citation-verification pass. Clients should ignore unknown event names rather than treating them as errors. properties: event: type: string enum: - connected - status - answer_chunk - tool_calls - tool_call - tool_success - tool_error - restreaming - complete - error data: type: string description: JSON-encoded event payload. Shape depends on `event`. AgentStreamSSEEvent: type: object description: | SSE event envelope for `POST /agents/{agentKey}/conversations/stream`. Event names are listed in `event`; payload JSON is carried in `data`. properties: event: type: string description: | SSE event name. See the enum for possible values. enum: - connected - status - tool_calls - tool_call - tool_success - tool_error - tool_result - tool_execution_complete - answer_chunk - restreaming - metadata - complete - error data: type: string description: | JSON-encoded event payload. Shape depends on `event`. AgentMessageStreamSSEEvent: type: object description: | Server-Sent Event envelope for `POST /agents/{agentKey}/conversations/{conversationId}/messages/stream`. `data` is a JSON-encoded string whose shape depends on `event`. Three events have stable API-defined payloads: - `connected` — `{ "message": "SSE connection established" }`. Fired once after the SSE stream opens. No `conversationId` is included because it is already present in the request path. - `complete` — `{ "conversation": AgentConversation, "recordsUsed": number, "meta": { "requestId": string, "timestamp": string, "duration": number, "recordsUsed": number } }`. Fired once after the upstream AI `complete` payload is parsed, citations are saved, and the updated conversation is persisted. - `error` — `{ "error": string, "details"?: string }`. Fired for runtime failures after the stream has already started, including conversation lookup failures, upstream AI startup failures, save failures, and stream transport errors. All other events are forwarded from the upstream agent backend. Common event names: - `status` — progress update for the current agent phase. - `answer_chunk` — incremental token batch with running accumulated text. - `tool_calls` / `tool_call` / `tool_success` / `tool_error` / `tool_result` / `tool_execution_complete` — tool lifecycle events emitted by the upstream agent. - `restreaming` — the upstream agent restarted generation with refreshed context. - `metadata` — auxiliary metadata or keep-alive payload from the upstream agent. Important wire behavior: - The upstream agent's `complete` event is consumed server-side and replaced with the API-defined `complete` event above. - If the upstream `complete` payload cannot be parsed as JSON, the raw upstream `complete` frame is forwarded unchanged instead. - Unknown future event names may appear and should be ignored by clients. properties: event: type: string enum: - connected - status - tool_calls - tool_call - tool_success - tool_error - tool_result - tool_execution_complete - answer_chunk - restreaming - metadata - complete - error data: type: string description: JSON-encoded event payload. Shape depends on `event`. ModelType: type: string enum: - llm - embedding - ocr - slm - reasoning - multiModal - imageGeneration - tts - stt description: Type of AI model WebSearchProviderType: type: string enum: - duckduckgo - serper - tavily - exa description: Supported web search provider WebSearchProviderItem: type: object additionalProperties: false description: Web search provider configuration item returned by getWebSearchProviders required: - provider - providerKey - configuration - isDefault properties: provider: $ref: '#/components/schemas/WebSearchProviderType' providerKey: type: string description: Unique key for the provider configuration configuration: type: object description: | Provider-specific configuration as stored and returned by the gateway (open record). Serper, Tavily, and Exa typically include `apiKey`; additional keys may be present. additionalProperties: true isDefault: type: boolean WebSearchSettings: type: object additionalProperties: false description: Normalized web search global settings returned by getWebSearchProviders required: - includeImages properties: includeImages: type: boolean description: Whether to include images in search results maxImages: type: integer minimum: 1 maximum: 500 description: Maximum number of images to return when includeImages is true WebSearchProvidersResponse: type: object additionalProperties: false description: Response for getWebSearchProviders required: - status - providers - settings - message properties: status: type: string enum: - success providers: type: array items: $ref: '#/components/schemas/WebSearchProviderItem' settings: $ref: '#/components/schemas/WebSearchSettings' message: type: string description: Human-readable status (empty list vs populated providers) security: - bearerAuth: [] - oauth2: [] paths: /oauth2/token: post: tags: - OAuth Provider summary: Exchange authorization code for tokens description: | OAuth 2.0 Token Endpoint (RFC 6749 Section 4.1.3). Exchanges an authorization code, client credentials, or refresh token for access tokens. **Grant Types:** - `authorization_code`: Exchange auth code for tokens (user-based) - `client_credentials`: Get tokens for machine-to-machine auth - `refresh_token`: Get new access token using refresh token For **`client_credentials`**, access tokens represent the **OAuth app creator** (the user who registered the client). The JWT may encode **`userId === client_id`**; the **Node API gateway** resolves the creator (**`createdBy`** claim or OAuth app lookup) — see **OAuth Provider** tag. **Client Authentication:** Can be provided via: - HTTP Basic auth: `Authorization: Basic base64(client_id:client_secret)` - Request body: `client_id` and `client_secret` parameters **PKCE Verification:** If authorization used PKCE, the `code_verifier` must be provided and will be verified against the stored code challenge. operationId: oauthToken security: [] requestBody: description: Request payload content: application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/OAuthTokenRequest' application/json: schema: $ref: '#/components/schemas/OAuthTokenRequest' required: true responses: '200': description: Tokens issued successfully content: application/json: schema: $ref: '#/components/schemas/OAuthTokenResponse' example: access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... token_type: Bearer expires_in: 3600 refresh_token: dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4... scope: openid profile email id_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... '400': description: Invalid request (missing parameters, invalid code, etc.) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Client authentication failed content: application/json: schema: $ref: '#/components/schemas/OAuthErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /oauth2/revoke: post: tags: - OAuth Provider summary: Revoke an access or refresh token description: | OAuth 2.0 Token Revocation Endpoint (RFC 7009). Revokes an access token or refresh token, preventing further use. Revoking a refresh token also invalidates associated access tokens. **Use Cases:** - User logs out of third-party app - User revokes app access from account settings - Security incident response **Note:** Returns 200 OK even if token was already revoked or invalid (per RFC 7009, to prevent token enumeration). operationId: oauthRevoke security: [] requestBody: description: Request payload content: application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/OAuthRevokeRequest' application/json: schema: $ref: '#/components/schemas/OAuthRevokeRequest' required: true responses: '200': description: Token revoked (or was already invalid) '401': description: Client authentication failed content: application/json: schema: $ref: '#/components/schemas/OAuthErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /oauth2/introspect: post: tags: - OAuth Provider summary: Introspect a token description: | OAuth 2.0 Token Introspection Endpoint (RFC 7662). Check if a token is active and retrieve its metadata. **Use Cases:** - Resource servers validating tokens - Debugging token issues - Checking token scopes before processing requests **Response:** - Active token: Returns `active: true` with token metadata - Invalid/expired/revoked token: Returns only `active: false` operationId: oauthIntrospect security: [] requestBody: description: Request payload content: application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/OAuthIntrospectRequest' application/json: schema: $ref: '#/components/schemas/OAuthIntrospectRequest' required: true responses: '200': description: Token introspection result content: application/json: schema: $ref: '#/components/schemas/OAuthIntrospectResponse' examples: active: summary: Active token value: active: true scope: openid profile email client_id: abc123 username: user@example.com token_type: Bearer exp: 1735686000 iat: 1735682400 user_id: user-id-123 iss: https://api.pipeshub.com inactive: summary: Inactive/invalid token value: active: false '401': description: Client authentication failed content: application/json: schema: $ref: '#/components/schemas/OAuthErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /oauth2/userinfo: get: tags: - OpenID Connect summary: Get authenticated user information description: | OpenID Connect UserInfo Endpoint. Returns claims about the authenticated user. Requires a valid access token with the `openid` scope. **Available Claims:** - `user_id` - User identifier - `name`, `given_name`, `family_name` - Name claims (with `profile` scope) - `email`, `email_verified` - Email claims (with `email` scope) **Authentication:** Pass the access token as a Bearer token: `Authorization: Bearer {access_token}` operationId: oauthUserInfo security: - bearerAuth: [] responses: '200': description: User information content: application/json: schema: $ref: '#/components/schemas/OAuthUserInfoResponse' example: user_id: user-id-123 name: John Doe given_name: John family_name: Doe email: john.doe@example.com email_verified: true '401': description: Invalid or missing access token '403': description: Token does not have openid scope /oauth-clients: get: tags: - OAuth Apps summary: List OAuth apps description: | Returns a paginated list of OAuth apps registered by the signed-in user. Access is creator-scoped — even org admins only see apps they created themselves, so this endpoint is safe to use for per-user developer dashboards without leaking org-wide app metadata. Each entry carries the full app configuration except the client secret, which is only ever returned at creation time and immediately after a regeneration. Use the `status` query parameter to filter by lifecycle state (`active`, `suspended`, `revoked`) and `search` for a case-insensitive substring match against `name` or `description`. operationId: listOAuthApps security: - bearerAuth: [] parameters: - name: page in: query schema: type: integer minimum: 1 default: 1 description: | Page number (matches `listAppsQuerySchema`: defaults to `1` when omitted or empty). - name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 20 description: | Items per page (defaults to `20` when omitted or empty; max 100). - name: status in: query schema: type: string enum: - active - suspended - revoked description: Filter by status - name: search in: query schema: type: string description: Search by app name or description (case-insensitive) responses: '200': description: List of OAuth apps content: application/json: schema: $ref: '#/components/schemas/OAuthAppListResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — insufficient workspace permission to list OAuth apps content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' post: tags: - OAuth Apps summary: Create OAuth app description: | Register a new OAuth app for the organization. Any authenticated org member may create apps; the creator is recorded as the app's owner and is the only user who can subsequently read, update, suspend, activate, regenerate the secret of, or delete it. The `clientSecret` is returned in this response **only** — it is stored hashed server-side and cannot be retrieved later. Persist it before exiting the create flow; if it is ever lost, rotate via `POST /oauth-clients/{appId}/regenerate-secret`. `allowedScopes` is validated against the caller's role-aware scope set (see `GET /oauth-clients/scopes`). Org admins may include admin-only scopes; non-admins requesting a restricted scope receive `400`. All `/oauth-clients/*` routes share a per-user rate limiter (default 1000 req/min, configurable via the `MAX_OAUTH_CLIENT_REQUESTS_PER_MINUTE` env var). operationId: createOAuthApp security: - bearerAuth: [] requestBody: description: Request body for Create OAuth app content: application/json: schema: $ref: '#/components/schemas/CreateOAuthAppRequest' required: true responses: '201': description: OAuth app created successfully content: application/json: schema: $ref: '#/components/schemas/CreateOAuthAppResponse' '400': description: Invalid request (validation error) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — insufficient workspace permission to create OAuth apps content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /oauth-clients/scopes: get: tags: - OAuth Apps summary: List available scopes description: | Returns the OAuth scopes the signed-in user is permitted to register on new or updated apps, grouped by category. Use this to populate scope-picker UIs and to validate `allowedScopes` client-side before submitting to `createOAuthApp` / `updateOAuthApp`. The result is role-aware. Org admins (members of an admin user group) receive every registered scope; everyone else is filtered to exclude admin-only scopes: `org:write`, `org:admin`, `user:invite`, `user:delete`, `usergroup:write`, `team:write`, `config:write`, `crawl:write`, `crawl:delete`. Each key in the `scopes` map matches the `category` field on the `OAuthScopeInfo` entries it contains. A category may appear with an empty array when every scope it contains is restricted for the caller — treat empty buckets as "no permitted scopes in this group", not as a missing category. Shares the per-user rate limiter applied to every `/oauth-clients/*` route (default 1000 req/min, `MAX_OAUTH_CLIENT_REQUESTS_PER_MINUTE`). operationId: listOAuthScopes security: - bearerAuth: [] responses: '200': description: List of available scopes content: application/json: schema: $ref: '#/components/schemas/OAuthScopesGroupedResponse' example: scopes: Identity: - name: openid description: OpenID Connect authentication category: Identity requiresUserConsent: false - name: profile description: User profile information (name, picture) category: Identity requiresUserConsent: true Knowledge Base: - name: kb:read description: Read knowledge bases and records category: Knowledge Base requiresUserConsent: true '401': description: Unauthorized — missing/invalid token, or session invalidated (e.g. password change after token issuance) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded for OAuth client management routes content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' example: error: code: TOO_MANY_REQUESTS message: Too many OAuth client requests. Please try again later. retryAfter: 45 /oauth-clients/{appId}: get: tags: - OAuth Apps summary: Get OAuth app details description: | Returns the full configuration of an OAuth app you registered. The `clientSecret` is never echoed back here; if you need a new one, call `POST /oauth-clients/{appId}/regenerate-secret`. Access is creator-scoped: even org admins receive `404` for apps owned by other users. This avoids leaking app metadata across org members and keeps the read surface symmetric with `listOAuthApps`. operationId: getOAuthApp security: - bearerAuth: [] parameters: - name: appId in: path required: true schema: type: string pattern: ^[a-fA-F0-9]{24}$ description: OAuth app ID (MongoDB ObjectId) responses: '200': description: OAuth app details content: application/json: schema: $ref: '#/components/schemas/OAuthAppResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — caller cannot access this OAuth app (creator-only; see OAuth Apps tag). content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '404': description: OAuth app not found or not visible to this caller (each user only sees apps they created) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' put: tags: - OAuth Apps summary: Update OAuth app description: | Update an OAuth app's configuration. All body fields are optional — supply only what should change. URL fields (`homepageUrl`, `privacyPolicyUrl`, `termsOfServiceUrl`) accept `null` to clear them. Creator-only: even org admins cannot edit apps owned by other users. When modifying `allowedScopes`, the new set must remain a subset of the caller's role-aware scope list (same rule as `GET /oauth-clients/scopes`). When adding `authorization_code` to `allowedGrantTypes`, `redirectUris` becomes required and must contain at least one URI; otherwise the request is rejected with `400` by the Zod refine on `updateAppSchema`. This endpoint never rotates the client secret — use `POST /oauth-clients/{appId}/regenerate-secret` for that. operationId: updateOAuthApp security: - bearerAuth: [] parameters: - name: appId in: path required: true schema: type: string pattern: ^[a-fA-F0-9]{24}$ description: OAuth app ID requestBody: description: Request payload content: application/json: schema: $ref: '#/components/schemas/UpdateOAuthAppRequest' required: true responses: '200': description: OAuth app updated content: application/json: schema: $ref: '#/components/schemas/UpdateOAuthAppResponse' '400': description: Validation error content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — caller cannot access this OAuth app (creator-only; see OAuth Apps tag). content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '404': description: OAuth app not found or not visible to this caller (each user only sees apps they created) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' delete: tags: - OAuth Apps summary: Delete OAuth app description: | Soft-deletes an OAuth app. The app is flagged `isDeleted=true` on the `OAuthApp` document, removed from list/get responses for every caller, and all of its access and refresh tokens are revoked in the same operation. There is no restore endpoint — deletion is final. Creator-only: even org admins cannot delete apps owned by other users. operationId: deleteOAuthApp security: - bearerAuth: [] parameters: - name: appId in: path required: true schema: type: string pattern: ^[a-fA-F0-9]{24}$ description: OAuth app ID responses: '200': description: OAuth app deleted content: application/json: schema: type: object properties: message: type: string example: OAuth app deleted successfully '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — caller cannot access this OAuth app (creator-only; see OAuth Apps tag). content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '404': description: OAuth app not found or not visible to this caller (each user only sees apps they created) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /oauth-clients/{appId}/regenerate-secret: post: tags: - OAuth Apps summary: Regenerate client secret description: | Generates a fresh client secret for an OAuth app. The previous secret is invalidated immediately — any client still presenting it will fail token exchange at `POST /oauth2/token` until updated. The new secret is returned in this response **only** and cannot be retrieved later. Pair this call with credential propagation to every integration that uses the app. If the rotation was triggered by a suspected leak, also call `POST /oauth-clients/{appId}/revoke-all-tokens` to invalidate already-issued access and refresh tokens instead of waiting for their natural expiry. Creator-only: even org admins cannot rotate secrets for other users' apps. operationId: regenerateOAuthAppSecret security: - bearerAuth: [] parameters: - name: appId in: path required: true schema: type: string pattern: ^[a-fA-F0-9]{24}$ description: OAuth app ID responses: '200': description: New client secret generated content: application/json: schema: $ref: '#/components/schemas/RegenerateOAuthAppSecretResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — caller cannot access this OAuth app (creator-only; see OAuth Apps tag). content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '404': description: OAuth app not found or not visible to this caller (each user only sees apps they created) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /oauth-clients/{appId}/suspend: post: tags: - OAuth Apps summary: Suspend OAuth app description: | Moves an OAuth app to `status: "suspended"`, blocking new token issuance at `POST /oauth2/token` and the authorization-code consent flow. Tokens that have already been issued remain valid until their natural expiry — call `POST /oauth-clients/{appId}/revoke-all-tokens` immediately afterwards if you need an immediate lockout. Use this for temporary suspensions where you intend to reactivate later. For permanent removal, use `DELETE /oauth-clients/{appId}`. Suspending an app that is already suspended returns `400`. Creator-only. operationId: suspendOAuthApp security: - bearerAuth: [] parameters: - name: appId in: path required: true schema: type: string pattern: ^[a-fA-F0-9]{24}$ description: OAuth app ID responses: '200': description: OAuth app suspended content: application/json: schema: $ref: '#/components/schemas/SuspendOAuthAppResponse' '400': description: Bad request — e.g. OAuth app is already suspended content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — caller cannot access this OAuth app (creator-only; see OAuth Apps tag). content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '404': description: OAuth app not found or not visible to this caller (each user only sees apps they created) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /oauth-clients/{appId}/activate: post: tags: - OAuth Apps summary: Activate suspended OAuth app description: | Moves a suspended OAuth app back to `status: "active"`, restoring its ability to authenticate and obtain new tokens via `POST /oauth2/token`. A revoked app cannot be reactivated (returns `400`); the only path back is to register a new app. Activating an app that is already active also returns `400`. Creator-only. operationId: activateOAuthApp security: - bearerAuth: [] parameters: - name: appId in: path required: true schema: type: string pattern: ^[a-fA-F0-9]{24}$ description: OAuth app ID responses: '200': description: OAuth app activated content: application/json: schema: $ref: '#/components/schemas/ActivateOAuthAppResponse' '400': description: Bad request — e.g. app is already active, or cannot activate a revoked app content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — caller cannot access this OAuth app (creator-only; see OAuth Apps tag). content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '404': description: OAuth app not found or not visible to this caller (each user only sees apps they created) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /oauth-clients/{appId}/tokens: get: tags: - OAuth Apps summary: List app tokens description: | Lists active access and refresh tokens currently issued to an OAuth app, sorted newest first. Useful for auditing app usage and picking specific tokens to investigate before a targeted revocation. Each entry includes the token type (`access` or `refresh`), the user the token was issued for (omitted for client-credentials access tokens), the granted scopes, the issuance and expiry timestamps, and the revocation flag. Each type is capped at 100 most-recent rows server-side (`listTokensForApp` in `oauth_token.service.ts`); revoked and expired tokens are excluded. Creator-only. operationId: listOAuthAppTokens security: - bearerAuth: [] parameters: - name: appId in: path required: true schema: type: string pattern: ^[a-fA-F0-9]{24}$ description: OAuth app ID responses: '200': description: List of tokens content: application/json: schema: $ref: '#/components/schemas/OAuthAppTokensListResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — caller cannot access this OAuth app (creator-only; see OAuth Apps tag). content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '404': description: OAuth app not found or not visible to this caller (each user only sees apps they created) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /oauth-clients/{appId}/revoke-all-tokens: post: tags: - OAuth Apps summary: Revoke all app tokens description: | Revokes every access and refresh token currently issued to an OAuth app, in a single operation. Use this for emergency credential rotation, suspected secret leaks, or as a follow-up to `POST /oauth-clients/{appId}/regenerate-secret` when you want existing sessions invalidated immediately rather than letting them expire naturally. The response `count` is the total number of tokens revoked across both types. Clients of this app must then obtain new tokens via the standard OAuth flow. Creator-only. operationId: revokeAllOAuthAppTokens security: - bearerAuth: [] parameters: - name: appId in: path required: true schema: type: string pattern: ^[a-fA-F0-9]{24}$ description: OAuth app ID responses: '200': description: All tokens revoked content: application/json: schema: type: object properties: message: type: string example: All tokens revoked successfully count: type: integer description: Number of tokens revoked '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '403': description: Forbidden — caller cannot access this OAuth app (creator-only; see OAuth Apps tag). content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '404': description: OAuth app not found or not visible to this caller (each user only sees apps they created) content: application/json: schema: $ref: '#/components/schemas/ApplicationJsonErrorResponse' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/OAuthClientManagementRateLimitError' /userAccount/initAuth: post: tags: - User Account summary: Initialize authentication session description: | Start a server-side authentication session and discover which sign-in methods are configured for the organization. This is the first step in the multi-step login flow. **Request body (optional)** - You may omit the body, send an empty JSON object `{}`, or send `{ "email": "..." }`. - `email` in the body is optional and kept for legacy reasons; omitting it does not prevent initialization. The web client typically calls this endpoint without a body and sends `email` on `/authenticate` instead. - When provided, `email` is stored on the session for correlation with subsequent steps. **Flow:** 1. Call this endpoint (optional JSON body as above). 2. Receive a session token in the `x-session-token` response header. 3. Send that token on subsequent `/authenticate` requests (`x-session-token` header). 4. Use `allowedMethods` and `authProviders` from the response to render the login UI. **Session token** - Returned as header `x-session-token`. - Required for `/authenticate` (and related steps) until it expires. **Multi-factor authentication** If the organization has MFA, complete multiple authentication steps; each step may return the next step's allowed methods. operationId: initAuth security: [] requestBody: description: | Optional. Omit entirely or send `{}`. You may include `email` for legacy compatibility (pre-fills the session); invalid `email` format is rejected when the field is present. content: application/json: schema: $ref: '#/components/schemas/InitAuthRequest' required: false responses: '200': description: Authentication session initialized successfully headers: x-session-token: schema: type: string description: Session token for subsequent authentication requests. Store this securely. content: application/json: schema: $ref: '#/components/schemas/InitAuthResponse' '400': description: Invalid request (e.g. malformed `email` when that property is sent) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /userAccount/authenticate: post: tags: - User Account summary: Authenticate user with credentials description: | Authenticate a user using the specified method and credentials. Requires a valid session token from `/initAuth`. **Credential Formats by Method:** - `password`: `{ "credentials": { "password": "your-password" } }` - `otp`: `{ "credentials": { "otp": "123456" } }` (6-digit code, valid for 10 minutes) - `google`: `{ "credentials": "google-id-token-string" }` - `microsoft`: `{ "credentials": { "accessToken": "...", "idToken": "..." } }` - `azureAd`: `{ "credentials": { "accessToken": "...", "idToken": "..." } }` - `oauth`: `{ "credentials": { "accessToken": "...", "idToken": "..." } }` - `samlSso`: Handled via redirect flow (use `/saml/signIn` instead) **Multi-Step Response:** If organization uses MFA, successful authentication returns: - `status: "success"` with `nextStep` and `allowedMethods` for next step **Fully Authenticated Response:** After completing all steps: - `message: "Fully authenticated"` with `accessToken` (1hr) and `refreshToken` (7d) **Security:** - Account locks after 5 consecutive failed attempts - CAPTCHA may be required if enabled (pass `cf-turnstile-response`) operationId: authenticate security: [] parameters: - name: x-session-token in: header required: true description: Session token received from `/initAuth` endpoint schema: type: string requestBody: description: Request payload content: application/json: schema: $ref: '#/components/schemas/AuthenticateRequest' required: true responses: '200': description: Authentication step successful or fully authenticated content: application/json: schema: $ref: '#/components/schemas/AuthenticateResponse' '400': description: Invalid request, method not allowed, invalid credential format or Account blocked due to too many failed attempts (5 attempts max) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid credentials (wrong password, expired OTP, etc.) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Session expired or user not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '410': description: OTP has expired (valid for 10 minutes) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /userAccount/refresh/token: post: tags: - User Account summary: Refresh access token description: | Get a new access token using a valid refresh token. **Usage:** - Pass the refresh token as a Bearer token in the Authorization header - Returns a new access token and basic user information **Token Lifetimes:** - Access token: 24 hours (configurable via `ACCESS_TOKEN_EXPIRY` environment variable) - Refresh token: 30 days (configurable via `REFRESH_TOKEN_EXPIRY` environment variable) **Best Practices:** - Call this endpoint before the access token expires - Store the new access token and continue using it for authenticated requests - If refresh fails with 401, redirect user to login flow operationId: refreshToken security: - scopedToken: [] responses: '200': description: Token refreshed successfully content: application/json: schema: $ref: '#/components/schemas/RefreshTokenResponse' '400': description: Disabled user account content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid or expired refresh token - user must re-authenticate content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: User not found (account may have been deleted), User credentials not found, or Organization not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /userAccount/password/reset: post: tags: - User Account summary: Reset password description: | Reset the password for the currently authenticated user. **Overview:** Allows a logged-in user to change their password by providing the current password and a new password. operationId: resetPassword security: - bearerAuth: [] requestBody: required: true description: Request payload content: application/json: schema: type: object additionalProperties: false required: - currentPassword - newPassword properties: currentPassword: type: string format: password newPassword: type: string format: password cf-turnstile-response: type: string description: Cloudflare Turnstile CAPTCHA token (required when Turnstile is configured server-side) responses: '200': description: Password reset successfully - returns new access token content: application/json: schema: $ref: '#/components/schemas/AuthenticatedPasswordResetResponse' '400': description: | Bad request. Possible causes: - `currentPassword` or `newPassword` missing from request body - Current and new password are the same (plain-text comparison) - New password does not meet strength requirements (min 8 chars, uppercase, lowercase, number, special character) - Old and new password are the same (hash comparison against stored password) - Account is blocked due to too many incorrect login attempts content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: | Unauthorized. Possible causes: - Invalid or expired access token - Current password is incorrect - Invalid CAPTCHA verification (when Turnstile is configured) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: | Not found. Possible causes: - Auth container not found - User credentials not found (no password set for account) - User not found in IAM service - Organization not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /orgAuthConfig/authMethods: get: tags: - Organization Auth Config summary: Get organization authentication methods description: | Retrieve the configured authentication methods for the organization. **Response Structure:** Returns an array of authentication steps, each containing: - `order`: Step number (1-3) - `allowedMethods`: Array of methods allowed for that step **Example Response:** ```json { "authMethods": [ { "order": 1, "allowedMethods": [{ "type": "password" }, { "type": "google" }] }, { "order": 2, "allowedMethods": [{ "type": "otp" }] } ] } ``` **Admin Access Required:** Only organization admins can view auth configuration. operationId: getAuthMethods security: - bearerAuth: [] responses: '200': description: Authentication methods retrieved successfully content: application/json: schema: $ref: '#/components/schemas/AuthConfig' '400': description: | Bad request. Possible causes: - User is not an organization admin - User not authenticated (token decoded but `req.user` is null) - Organization ID missing from token payload content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - invalid or expired access token content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: | Not found. Possible causes: - Auth container not found - Account not found (userId or orgId missing) - Admin check failed in IAM service - Organization auth configuration not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /orgAuthConfig/updateAuthMethod: post: tags: - Organization Auth Config summary: Update organization authentication methods description: | Update the authentication methods configuration for an organization. This allows admins to configure single or multi-factor authentication. **Validation Rules:** - Minimum 1 step, maximum 3 steps - Each step must have a unique order (1, 2, or 3) - No duplicate methods within the same step - No method can appear in multiple steps - Each step must have at least one allowed method **Available Methods:** - `password`: Email/password authentication - `otp`: One-time password via email - `google`: Google OAuth 2.0 - `microsoft`: Microsoft OAuth 2.0 - `azureAd`: Azure Active Directory - `samlSso`: SAML 2.0 Single Sign-On - `oauth`: Generic OAuth 2.0 provider **Example - Single Factor (Password or Google):** ```json { "authMethod": [ { "order": 1, "allowedMethods": [{ "type": "password" }, { "type": "google" }] } ] } ``` **Example - Two Factor (Password + OTP):** ```json { "authMethod": [ { "order": 1, "allowedMethods": [{ "type": "password" }] }, { "order": 2, "allowedMethods": [{ "type": "otp" }] } ] } ``` **Admin Access Required:** Only organization admins can update auth configuration. operationId: updateAuthMethod security: - bearerAuth: [] requestBody: description: Request payload required: true content: application/json: schema: type: object additionalProperties: false required: - authMethod properties: authMethod: type: array description: Authentication steps to set for the organization (1-3 steps) minItems: 1 maxItems: 3 items: $ref: '#/components/schemas/AuthStep' responses: '200': description: Authentication methods updated successfully content: application/json: schema: $ref: '#/components/schemas/UpdateAuthMethodResponse' '400': description: | Bad request. Possible causes: - User is not an organization admin - `authMethod` field missing from request body - Validation failure (duplicate steps, duplicate methods, out-of-range order, empty methods array) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: | Unauthorized. Possible causes: - Invalid or expired access token - User not authenticated (token decoded but `req.user` is null) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: | Not found. Possible causes: - Auth container not found - Account not found (userId or orgId missing) - Admin check failed in IAM service - Organization auth configuration not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /orgAuthConfig: post: tags: - Organization Auth Config summary: Set up auth configuration description: | Set up or initialize the organization's authentication configuration. operationId: setUpAuthConfig security: - bearerAuth: [] requestBody: required: true description: Organization setup details content: application/json: schema: $ref: '#/components/schemas/OrgAuthConfigCreateRequest' responses: '200': description: Auth configuration already exists for this deployment content: application/json: schema: $ref: '#/components/schemas/OrgAuthConfigSetupResponse' '201': description: Auth configuration created successfully content: application/json: schema: $ref: '#/components/schemas/OrgAuthConfigSetupResponse' '400': description: | Bad request. Possible causes: - User is not an organization admin content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - invalid or expired access token content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: | Not found. Possible causes: - Auth container not found - Account not found (userId or orgId missing) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /org: get: tags: - Organizations summary: Get current organization description: | Retrieve details about the authenticated user's organization. **Overview:** This endpoint returns the organization document for the current user's org, including profile data and configuration. **Response Includes:** - Organization profile (registeredName, shortName, contactEmail, domain) - Account type - Onboarding status - Permanent address - Creation and modification timestamps **Use Cases:** - Organization profile pages - Settings and configuration screens operationId: getCurrentOrganization security: - bearerAuth: [] - oauth2: - org:read responses: '200': description: Organization details retrieved successfully content: application/json: schema: $ref: '#/components/schemas/Organization' '401': description: Unauthorized - Valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Organization not found - User's organization does not exist content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error - Database query failure content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase: post: tags: - Knowledge Base summary: Create a new knowledge base description: | Create a new knowledge base for organizing and managing documents within your organization. **Overview:** A knowledge base is a container for organizing related documents, files, and content. It provides a central location for teams to collaborate on shared information. **Features:** - Hierarchical folder structure support - Role-based access control (OWNER, WRITER, READER) - Full-text search across all records - Integration with external connectors (Google Drive, OneDrive, etc.) - Automatic content indexing for AI-powered search **Naming Rules:** - Name must be 1-255 characters - Special characters and HTML tags are sanitized - Names don't need to be unique within organization **Creator Permissions:** The user creating the KB automatically becomes the OWNER with full administrative rights. operationId: createKnowledgeBase security: - bearerAuth: [] - oauth2: - kb:write requestBody: required: true description: Request payload content: application/json: schema: type: object properties: kbName: type: string minLength: 1 maxLength: 255 description: Name of the knowledge base example: Product Documentation required: - kbName responses: '200': description: Knowledge base created successfully content: application/json: schema: $ref: '#/components/schemas/KnowledgeBaseCreateResponse' '400': description: | **Invalid request:** - Name too short or too long - Invalid characters in name content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Possible reasons: - OAuth token lacks the `kb:write` scope - Connector service denied the request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: User not found - Authenticated user does not exist in the graph database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error - Knowledge base creation failed in connector or database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Service unavailable - Connector service is unreachable content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' get: tags: - Knowledge Base summary: List all knowledge bases description: | Retrieve a paginated list of all knowledge bases accessible to the authenticated user. **Overview:** Returns knowledge bases where the user has at least READER permission. Results include the user's role for each KB. **Filtering:** - **search:** Full-text search on KB names (max 1000 chars) - **permissions:** Filter by user's role (comma-separated: OWNER, WRITER, READER) **Sorting Options:** - `name` — Alphabetical by KB name - `createdAtTimestamp` — By creation date - `updatedAtTimestamp` — By last modification - `userRole` — By permission level **Performance:** Uses efficient pagination with limit/offset. For large result sets, use smaller page sizes. **Query parameters:** Only `page`, `limit`, `search`, `permissions`, `sortBy`, and `sortOrder` are allowed; unknown query keys are rejected. operationId: listKnowledgeBases security: - bearerAuth: [] - oauth2: - kb:read parameters: - name: page in: query required: false description: Page number (1-indexed). Omitted values default to 1. schema: type: integer minimum: 1 default: 1 - name: limit in: query required: false description: Results per page (max 100). Omitted values default to 20. schema: type: integer minimum: 1 maximum: 100 default: 20 - name: search in: query required: false description: | Search KB names (max 1000 chars). Rejected if it contains HTML/script tags, event handlers, `javascript:`, or format specifiers (validated in Zod + controller). schema: type: string maxLength: 1000 - name: permissions in: query required: false description: | Comma-separated permission roles to filter by. Each token must be one of: OWNER, WRITER, READER. schema: type: string example: OWNER,WRITER - name: sortBy in: query required: false description: Field to sort by. schema: type: string enum: - name - createdAtTimestamp - updatedAtTimestamp - userRole default: name - name: sortOrder in: query required: false description: Sort direction. schema: type: string enum: - asc - desc default: asc responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/GetAllKnowledgeBaseResponseSchema' '400': description: | **Invalid query parameters:** - `page` not a positive integer - `limit` not between 1 and 100 - Unknown query parameter (only `page`, `limit`, `search`, `permissions`, `sortBy`, `sortOrder` allowed) - Invalid `sortBy` or `sortOrder` - Invalid `permissions` role token - `search` too long, or contains HTML/scripts/format specifiers - Connector returned a 400 error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized — valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Possible reasons: - OAuth token lacks the `kb:read` scope - Connector service denied the request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: User not found — authenticated user does not exist in the graph database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error — listing knowledge bases failed in connector or database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Service unavailable — connector service is unreachable content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/{kbId}: get: tags: - Knowledge Base summary: Get knowledge base by ID description: | Retrieve detailed information about a specific knowledge base. **Overview:** Returns complete KB metadata including name, timestamps, root-level folders, and the requesting user's role. **Access Control:** User must have at least READER permission to view KB details. operationId: getKnowledgeBase security: - bearerAuth: [] - oauth2: - kb:read parameters: - name: kbId in: path required: true description: Knowledge base ID (non-empty string) schema: type: string minLength: 1 example: 8a095180-2989-4018-b448-70eb75fba1c7 responses: '200': description: Knowledge base retrieved successfully content: application/json: schema: $ref: '#/components/schemas/GetKnowledgeBaseById' '401': description: Unauthorized — valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Possible reasons: - OAuth token lacks the `kb:read` scope - User does not have permission to access this knowledge base - Connector service denied the request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: | Not found. Possible reasons: - Knowledge base does not exist - Authenticated user does not exist in the graph database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error — retrieving knowledge base failed in connector or database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Service unavailable — connector service is unreachable content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' put: tags: - Knowledge Base summary: Update knowledge base description: | Update a knowledge base's name. **Required permission:** User must have one of `OWNER` or `WRITER` on the knowledge base. **Validation:** - `kbId` path parameter must be a valid UUID (`updateKBSchema`) - When provided, `kbName` must be 1–255 characters - XSS and format-specifier checks are applied to `kbName` in the gateway controller operationId: updateKnowledgeBase security: - bearerAuth: [] - oauth2: - kb:write parameters: - name: kbId in: path required: true description: Knowledge base ID (UUID) schema: type: string format: uuid example: 8a095180-2989-4018-b448-70eb75fba1c7 requestBody: required: true description: Fields to update. `kbName` is optional; an empty object is valid. content: application/json: schema: type: object additionalProperties: false properties: kbName: type: string minLength: 1 maxLength: 255 description: New name for the knowledge base example: Updated Documentation Hub responses: '200': description: Knowledge base updated successfully content: application/json: schema: $ref: '#/components/schemas/UpdateKnowledgeBaseById' '400': description: | Invalid request. Possible reasons: - `kbId` is not a valid UUID (gateway `updateKBSchema`) - `kbName` is empty or longer than 255 characters - `kbName` fails XSS or format-specifier validation in the gateway controller - Invalid JSON request body at the connector (`Invalid request body`) - Connector rejected the update payload content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized — valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Possible reasons: - OAuth token lacks the `kb:write` scope - User has no permission on this knowledge base - User role is insufficient (`READER`; requires `OWNER` or `WRITER`) - Connector service denied the request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: | Not found. Possible reasons: - Knowledge base does not exist - Authenticated user does not exist in the graph database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error — updating knowledge base failed in connector or database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Service unavailable — connector service is unreachable content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' delete: tags: - Knowledge Base summary: Delete knowledge base description: | Permanently delete a knowledge base and all its contents. **Required permission:** User must have `OWNER` role on the knowledge base. **What gets deleted:** - All folders within the KB - All records and their indexed content - All permission grants - Associated storage files **Warning:** This action is irreversible. Consider exporting data before deletion. operationId: deleteKnowledgeBase security: - bearerAuth: [] - oauth2: - kb:delete parameters: - name: kbId in: path required: true description: Knowledge base ID (non-empty string) schema: type: string minLength: 1 example: 8a095180-2989-4018-b448-70eb75fba1c7 responses: '200': description: Knowledge base deleted successfully content: application/json: schema: $ref: '#/components/schemas/DeleteKnowledgeBaseById' '401': description: Unauthorized — valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Possible reasons: - OAuth token lacks the `kb:delete` scope - User has no permission on this knowledge base - User is not `OWNER` (only KB owners can delete) - Connector service denied the request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: | Not found. Possible reasons: - Knowledge base does not exist - Authenticated user does not exist in the graph database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error — deleting knowledge base failed in connector or database content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Service unavailable — connector service is unreachable content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/record/{recordId}: get: tags: - Knowledge Base summary: Get record by ID description: | Retrieve detailed information about a specific record. **Overview:** Returns complete record metadata including name, type, indexing status, storage information, and version history. **File conversion:** Use the optional `convertTo` parameter to request file format conversion (e.g., PDF to text). Supported conversions include PPT to PDF and PPTX to PDF. operationId: getRecordById security: - bearerAuth: [] - oauth2: - kb:read parameters: - name: recordId in: path required: true description: Record ID schema: type: string - name: convertTo in: query description: Optional format to convert the file to (e.g., PDF to text). Supported conversions include PPT to PDF and PPTX to PDF. schema: type: string example: txt responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/GetRecordByIdResponseSchema' '400': description: Invalid request parameters or query shape content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Missing, invalid, expired, or revoked authentication content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: OAuth token is missing the required kb:read scope content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Record not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: | Internal server error while retrieving record details. Current API behavior includes record-access lookup failures returning `HTTP_INTERNAL_SERVER_ERROR` with messages such as `Failed to check record access`, including cases where callers might otherwise expect a not-found style response. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Connector service unavailable or connection refused content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' put: tags: - Knowledge Base summary: Update record description: | Update a record's name and/or file content. **Overview:** Allows updating the display name and optionally replacing the file content. Triggers re-indexing when content changes. **Required permission:** WRITER or higher **Updating file content:** Include a new file in the request to replace the existing content. The file extension must match the original. **Side effects:** - Updates `updatedAtTimestamp` - Increments version if file content changed - Triggers re-indexing for content changes operationId: updateRecord security: - bearerAuth: [] - oauth2: - kb:write parameters: - name: recordId in: path required: true description: Record ID schema: type: string requestBody: description: Request payload content: multipart/form-data: schema: type: object properties: recordName: type: string description: New name for the record maxLength: 255 file: type: string format: binary description: Replacement file content responses: '200': description: Record updated successfully content: application/json: schema: allOf: - type: object properties: success: type: boolean message: type: string record: $ref: '#/components/schemas/Record' - $ref: '#/components/schemas/UpdateRecordEnrichment' '400': description: Invalid request parameters content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Missing, invalid, expired, or revoked authentication content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: OAuth token is missing the required kb:write scope content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Record not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error while updating record content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Connector service unavailable or connection refused content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' delete: tags: - Knowledge Base summary: Delete record description: | Permanently delete a record from the knowledge base. **Required permission:** WRITER or higher **What gets deleted:** - Record metadata - Associated storage file - Indexed content and embeddings **Warning:** This action is irreversible. operationId: deleteRecord security: - bearerAuth: [] - oauth2: - kb:delete parameters: - name: recordId in: path required: true description: Record ID schema: type: string responses: '200': description: Record deleted successfully content: application/json: schema: $ref: '#/components/schemas/DeleteRecordResponseSchema' '400': description: Invalid request parameters content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Missing, invalid, expired, or revoked authentication content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: OAuth token is missing the required kb:delete scope content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Record not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error while deleting record content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Connector service unavailable or connection refused content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/stream/record/{recordId}: get: tags: - Knowledge Base summary: Stream record content description: | Stream the binary content of a record's file. **Overview:** Returns the raw file content with appropriate `Content-Type` and `Content-Disposition` headers for download or inline viewing. **Use cases:** - File downloads - Inline document preview - Content extraction pipelines **Format conversion:** Use the `convertTo` parameter to convert between formats (e.g. DOCX to PDF). operationId: streamRecordBuffer security: - bearerAuth: [] - oauth2: - kb:read parameters: - name: recordId in: path required: true description: Record ID schema: type: string - name: convertTo in: query description: Target format for conversion schema: type: string responses: '200': description: File content stream content: '*/*': schema: type: string format: binary '400': description: Invalid record ID or query parameters content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Missing, invalid, expired, or revoked authentication content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Returned either when the OAuth token is missing the required `kb:read` scope or when the authenticated user does not have access to the record. content: application/json: schema: oneOf: - $ref: '#/components/schemas/ErrorResponse' - $ref: '#/components/schemas/StreamRecordErrorResponse' '404': description: Record, organization, or backing connector not found content: application/json: schema: $ref: '#/components/schemas/StreamRecordErrorResponse' '409': description: | Conflict - the connector instance for this record is disabled. Enable it from Connector Settings and try again. content: application/json: schema: $ref: '#/components/schemas/StreamRecordErrorResponse' '500': description: | Internal streaming failure, downstream conversion failure, or connector/backend error proxied by the gateway. content: application/json: schema: $ref: '#/components/schemas/StreamRecordErrorResponse' /knowledgeBase/{kbId}/folder: post: tags: - Knowledge Base summary: Create folder description: | Create a folder in a knowledge base. Omit `folderId` to create at the KB root; pass `folderId` as a query parameter to create a nested subfolder inside an existing parent folder. **Required permission:** WRITER or higher **Folder features:** - Organize records hierarchically - Support nested subfolders (unlimited depth) - Inherit parent KB permissions **Naming rules:** - 1–255 characters - XSS protection applied - Spaces and special characters allowed - Duplicate names rejected within the same parent (`409`) **Response:** Returns `id` and `name` for the created folder. operationId: createFolder security: - bearerAuth: [] - oauth2: - kb:write parameters: - name: kbId in: path required: true description: Knowledge base ID schema: type: string - name: folderId in: query required: false description: Parent folder ID. Omit to create at the knowledge base root. schema: type: string requestBody: required: true description: Request payload content: application/json: schema: type: object properties: folderName: type: string minLength: 1 maxLength: 255 description: Name of the folder example: Project Documents required: - folderName responses: '200': description: Folder created successfully content: application/json: schema: $ref: '#/components/schemas/FolderCreateResponseSchema' '400': description: | Invalid request. Possible reasons: - Missing or empty folder name - Folder name exceeds 255 characters - XSS or invalid characters in folder name content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Possible reasons: - OAuth token lacks the `kb:write` scope - User lacks WRITER or higher permission on the knowledge base content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Knowledge base or parent folder not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '409': description: Folder with this name already exists at the knowledge base root or within the parent folder content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error while creating folder content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Connector service unavailable or connection refused content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/{kbId}/folder/{folderId}: put: tags: - Knowledge Base summary: Update folder description: | Rename a folder. **Required permission:** WRITER or higher operationId: updateFolder security: - bearerAuth: [] - oauth2: - kb:write parameters: - name: kbId in: path required: true schema: type: string - name: folderId in: path required: true schema: type: string requestBody: required: true description: Request payload content: application/json: schema: type: object properties: folderName: type: string minLength: 1 maxLength: 255 required: - folderName responses: '200': description: Folder updated successfully content: application/json: schema: $ref: '#/components/schemas/FolderUpdateResponseSchema' '400': description: | Invalid request. Possible reasons: - Missing or empty folder name - Folder name exceeds 255 characters - XSS or invalid characters in folder name content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Possible reasons: - OAuth token lacks the `kb:write` scope - User lacks WRITER or higher permission on the knowledge base content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Knowledge base or folder not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '409': description: Folder with this name already exists at the knowledge base root content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error while updating folder content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Connector service unavailable or connection refused content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' delete: tags: - Knowledge Base summary: Delete folder description: | Delete a folder and all its contents. **Required permission:** WRITER or higher **Cascade delete:** All subfolders and records within will be permanently deleted. **Warning:** This action is irreversible. operationId: deleteFolder security: - bearerAuth: [] - oauth2: - kb:delete parameters: - name: kbId in: path required: true schema: type: string - name: folderId in: path required: true schema: type: string responses: '200': description: Folder deleted successfully content: application/json: schema: $ref: '#/components/schemas/FolderDeleteResponseSchema' '400': description: Invalid request parameters content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Possible reasons: - OAuth token lacks the `kb:delete` scope - User lacks OWNER permission on the knowledge base content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Knowledge base or folder not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/{kbId}/upload: post: tags: - Knowledge Base summary: Upload files to knowledge base or folder description: | Upload one or more files to a knowledge base root or to a specific folder. **Overview** Batch upload multiple files in a single request. Each file becomes a new record with automatic content indexing. Omit the `folderId` query parameter to upload to the KB root; include it to upload into that folder. **Upload Limits** - **Max files per request:** 1000 - **Default max file size:** 30MB (configurable via platform settings) - Use `GET /knowledgeBase/limits` to check current limits **Supported File Types** Documents (PDF, DOCX, DOC, XLS, XLSX, PPT, PPTX, TXT, CSV, MD), Images (PNG, JPG, JPEG, SVG, WebP), Web (HTML, HTM), and Google Workspace formats. **File Metadata** Use `files_metadata` to provide additional info like file paths and last modified timestamps. **Versioning** Set `isVersioned: true` to enable version tracking for uploaded files. **Streaming response** This endpoint responds with `Content-Type: text/event-stream`. The upload and its per-file progress are a single request: the body streams a `file:succeeded` or `file:failed` event per file (including files rejected up front for size/type), followed by a final `done` summary, then closes. See the `UploadStreamSSEEvent` schema for the event/payload contract. operationId: uploadRecords security: - bearerAuth: [] - oauth2: - kb:upload parameters: - name: kbId in: path required: true description: Knowledge base ID schema: type: string - name: folderId in: query required: false description: Target folder ID. Omit to upload to the KB root. schema: type: string requestBody: required: true description: Request payload content: multipart/form-data: schema: type: object properties: files: type: array items: type: string format: binary description: Files to upload (max 1000) files_metadata: type: string description: JSON array with file_path and last_modified for each file example: '[{"file_path":"/docs/report.pdf","last_modified":"2024-01-15T10:30:00Z"}]' isVersioned: type: boolean default: true description: Enable version tracking recordType: type: string default: FILE description: Type of records to create required: - files responses: '200': description: | SSE stream (`text/event-stream`) of per-file upload outcomes. The stream emits `file:succeeded` / `file:failed` per file and a final `done` summary, then closes. See `UploadStreamSSEEvent`. content: text/event-stream: schema: $ref: '#/components/schemas/UploadStreamSSEEvent' '400': description: Invalid request - Check file types and sizes content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: Insufficient permissions (requires WRITER or higher) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Knowledge base or folder not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '413': description: File size exceeds maximum allowed content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '429': description: Too many upload requests, or too many concurrent uploads for this user content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Failed to verify knowledge base or folder access content: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/limits: get: tags: - Knowledge Base summary: Get knowledge base upload limits description: | Retrieve current upload constraints for the organization. **Use case:** Call this before uploads to validate file sizes on the client side and display appropriate limits to users. operationId: getUploadLimits security: - bearerAuth: [] - oauth2: - kb:read responses: '200': description: Upload limits retrieved content: application/json: schema: $ref: '#/components/schemas/UploadLimitsResponseSchema' '401': description: Unauthorized - Valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/reindex/record/{recordId}: post: tags: - Knowledge Base summary: Reindex single record description: | Trigger reindexing for a specific record. **Overview:** Reprocesses the record's content to update search indexes and AI embeddings. Useful after content changes or to fix indexing failures. **Depth parameter:** Controls processing depth for complex documents (`-1` for full depth, `0`–`100` for limited). **Status filters:** Optional `statusFilters` array limits reindex to records in matching indexing states (e.g. `FAILED`, `AUTO_INDEX_OFF`). operationId: reindexRecord security: - bearerAuth: [] - oauth2: - kb:write parameters: - name: recordId in: path required: true schema: type: string requestBody: description: Request payload content: application/json: schema: $ref: '#/components/schemas/ReindexRecordRequestBody' responses: '200': description: Reindexing triggered successfully content: application/json: schema: $ref: '#/components/schemas/reIndexRecordResponseSchema' '400': description: Invalid request body or parameters content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Missing, invalid, expired, or revoked authentication content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: OAuth token is missing the required kb:write scope content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Record not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '409': description: Conflict — the connector instance for this record is disabled. Enable it from Connector Settings and try again. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error while reindexing the record content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Connector service unavailable or connection refused content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/reindex/record-group/{recordGroupId}: post: tags: - Knowledge Base summary: Reindex record group description: | Trigger reindexing for all records in a folder or knowledge base. **Overview:** Batch reindex operation for entire containers. The `recordGroupId` can be a folder ID or KB ID. **Status filters:** Optional `statusFilters` limit which child records are queued (e.g. failed-only or manual-indexing). operationId: reindexRecordGroup security: - bearerAuth: [] - oauth2: - kb:write parameters: - name: recordGroupId in: path required: true description: Folder ID or KB ID schema: type: string requestBody: description: Request payload content: application/json: schema: $ref: '#/components/schemas/ReindexRecordGroupRequestBody' responses: '200': description: Reindexing triggered for all records in group content: application/json: schema: $ref: '#/components/schemas/ReIndexRecordGroupResponseSchema' '400': description: Invalid request body or parameters content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Missing, invalid, expired, or revoked authentication content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: OAuth token is missing the required kb:write scope content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Record group not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '409': description: Conflict - the connector instance is disabled. Enable it from Connector Settings and try again. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error while reindexing the record group content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Connector service unavailable or connection refused content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/{kbId}/record/{recordId}/move: put: tags: - Knowledge Base summary: Move record to another location description: | Move a file or folder record to a different location within the same knowledge base. Set `newParentId` to a folder ID to move the record into that folder, or `null` to move it to the knowledge base root. **Required Permission:** OWNER or WRITER operationId: moveRecord security: - bearerAuth: [] - oauth2: - kb:write parameters: - name: kbId in: path required: true schema: type: string format: uuid description: Knowledge base UUID - name: recordId in: path required: true schema: type: string minLength: 1 description: Record identifier (file or folder) requestBody: required: true description: Target location for the record content: application/json: schema: $ref: '#/components/schemas/KnowledgeBaseMoveRecordRequestBody' responses: '200': description: Record moved successfully content: application/json: schema: $ref: '#/components/schemas/KnowledgeBaseMoveRecordResponse' '400': description: | Invalid request. Possible reasons: - Missing `newParentId` in the request body - Invalid `kbId` (must be a UUID) - Empty `recordId` - Cannot move a folder into itself - Cannot move a folder into one of its own sub-folders (circular reference) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Valid bearer token required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: | Forbidden. Possible reasons: - OAuth token lacks the `kb:write` scope - User lacks OWNER or WRITER permission on the knowledge base content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: | Not found. Possible reasons: - Knowledge base does not exist - Record does not exist in the knowledge base - Target folder does not exist in the knowledge base content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error while moving record content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: Connector service unavailable or connection refused content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /knowledgeBase/knowledge-hub/nodes: get: deprecated: true x-speakeasy-deprecation-message: Use the Knowledge Base API instead. This grouping will be removed in a future release tags: - Knowledge Base - Knowledge Hub summary: Get knowledge hub root nodes description: | Returns root-level nodes (connector apps and Collection apps) or, when filters or search are applied, a flat list of matching nodes across the entire knowledge hub tree. **Overview** The Knowledge Hub provides a unified view across all knowledge sources: - **Collection** — locally uploaded knowledge bases (`origin: COLLECTION`) - **Connector app** — external connector instances such as Google Drive, Slack, Confluence, Jira (`origin: CONNECTOR`) Use this endpoint to build file-browser UIs and sidebar navigation trees. **Browsing vs. searching** When no filters or search query are provided, only top-level app nodes are returned. Adding `nodeTypes`, `q`, or other filter params triggers a search across the full tree, returning matching nodes regardless of depth. For children of a specific node, use `GET /knowledgeBase/knowledge-hub/nodes/{parentType}/{parentId}`. **Pagination and sorting** Results are always paginated. Default sort is `updatedAt` descending. The `pagination` object in the response contains `hasNext` / `hasPrev` flags suitable for infinite-scroll or page-based navigation. **Expanding the response** Use the `include` parameter to request additional sections: - `availableFilters` — adds `filters.available` with all filter options - `counts` — adds a `counts` summary broken down by node type - `breadcrumbs` — adds the breadcrumb trail (empty at root level) - `permissions` — adds the caller's permission flags **Access control** Requires a valid bearer token. For OAuth tokens the `kb:read` scope must be present; regular JWT bearer tokens pass through without scope enforcement. operationId: getKnowledgeHubRootNodes security: - bearerAuth: [] - oauth2: - kb:read parameters: - name: onlyContainers in: query required: false description: | When `true`, only nodes that have children are returned (useful for building sidebar / tree navigation). Leaf nodes are excluded. schema: type: boolean default: false - name: page in: query required: false description: | Page number (1-indexed). Combined with `limit` to paginate results. schema: type: integer minimum: 1 default: 1 - name: limit in: query required: false description: | Maximum number of items to return per page. schema: type: integer minimum: 1 maximum: 200 default: 50 - name: sortBy in: query required: false description: | Field to sort results by. Omitted → default `updatedAt`. Unknown value → silently falls back to `name`. schema: type: string enum: - name - createdAt - updatedAt - size - type default: updatedAt - name: sortOrder in: query required: false description: | Sort direction. Omitted → default `desc`. Unknown value → silently falls back to `asc`. schema: type: string enum: - asc - desc default: desc - name: q in: query required: false description: | Full-text search query. Must be between 2 and 500 characters (inclusive). When provided, the endpoint searches across the entire node tree regardless of the current browse level. schema: type: string minLength: 2 maxLength: 500 example: quarterly report - name: nodeTypes in: query required: false description: | Comma-separated list of node types to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `folder`, `app`, `recordGroup`, `record` schema: type: string example: app,recordGroup - name: recordTypes in: query required: false description: | Comma-separated list of record types to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `FILE`, `DRIVE`, `WEBPAGE`, `DATABASE`, `DATASOURCE`, `MESSAGE`, `MAIL`, `GROUP_MAIL`, `TICKET`, `COMMENT`, `INLINE_COMMENT`, `CONFLUENCE_PAGE`, `CONFLUENCE_BLOGPOST`, `SHAREPOINT_PAGE`, `SHAREPOINT_LIST`, `SHAREPOINT_LIST_ITEM`, `SHAREPOINT_DOCUMENT_LIBRARY`, `LINK`, `PROJECT`, `PULL_REQUEST`, `MEETING`, `PRODUCT`, `DEAL`, `CASE`, `TASK`, `ARTIFACT`, `CODE_FILE`, `SQL_TABLE`, `SQL_VIEW`, `OTHERS` schema: type: string example: FILE,CONFLUENCE_PAGE - name: origins in: query required: false description: | Comma-separated list of origin types to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `COLLECTION`, `CONNECTOR` schema: type: string example: CONNECTOR - name: connectorIds in: query required: false description: | Comma-separated list of connector instance IDs (UUIDs) to filter by. Maximum 100 items. No enum validation — any string is accepted, but non-existent IDs simply yield zero results. schema: type: string example: f3a4b5b6-5b6c-4e85-9097-3202cfe696fc - name: indexingStatus in: query required: false description: | Comma-separated list of indexing statuses to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `NOT_STARTED`, `PAUSED`, `IN_PROGRESS`, `COMPLETED`, `FAILED`, `FILE_TYPE_NOT_SUPPORTED`, `AUTO_INDEX_OFF`, `EMPTY`, `ENABLE_MULTIMODAL_MODELS`, `QUEUED` schema: type: string example: COMPLETED,FAILED - name: createdAt in: query required: false description: | Created-date range filter. Format: `gte:,lte:`. Both bounds are optional (you may send just `gte:...` or just `lte:...`). Timestamps must be in the range 0 to 9999999999999 and `gte` must be less than or equal to `lte` when both are present. schema: type: string example: gte:1700000000000,lte:1710000000000 - name: updatedAt in: query required: false description: | Updated-date range filter. Same format and constraints as `createdAt`. schema: type: string example: gte:1700000000000,lte:1710000000000 - name: size in: query required: false description: | File-size range filter in bytes. Format: `gte:,lte:`. Both bounds are optional. Values must be non-negative and at most 1099511627776 (1 TB). `gte` must be less than or equal to `lte` when both are present. schema: type: string example: gte:0,lte:10485760 - name: include in: query required: false description: | Comma-separated list of additional response sections to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `breadcrumbs`, `counts`, `availableFilters`, `permissions` schema: type: string example: availableFilters,counts responses: '200': description: | Paginated list of root hub nodes (connector apps and Collections). HTTP 200 returns `success: true` and `error: null`. Field-level detail and required keys are defined on `KnowledgeHubNodesResponse`. Use `include` for optional sections: `availableFilters`, `counts`, `permissions` — each stays JSON `null` when not asked for. `breadcrumbs` stays `null` at this route (no parent in the path), even if `include` lists `breadcrumbs`; use the child route for trails. `id`, `currentNode`, and `parentNode` are `null` here. content: application/json: schema: $ref: '#/components/schemas/KnowledgeHubNodesResponse' examples: root_apps: summary: Root-level apps with availableFilters included value: success: true error: null id: null currentNode: null parentNode: null items: - id: knowledgeBase_org123 name: Collections nodeType: app parentId: null origin: COLLECTION connector: null recordType: null recordGroupType: null indexingStatus: null reason: null createdAt: 1700000000000 updatedAt: 1710000000000 sizeInBytes: null mimeType: null extension: null webUrl: /app/knowledgeBase_org123 hasChildren: true previewRenderable: null permission: null sharingStatus: workspace isInternal: false - id: f3a4b5b6-5b6c-4e85-9097-3202cfe696fc name: Google Drive nodeType: app parentId: null origin: CONNECTOR connector: drive recordType: null recordGroupType: null indexingStatus: null reason: null createdAt: 1700000000000 updatedAt: 1709000000000 sizeInBytes: null mimeType: null extension: null webUrl: /app/f3a4b5b6-5b6c-4e85-9097-3202cfe696fc hasChildren: true previewRenderable: null permission: null sharingStatus: null isInternal: false pagination: page: 1 limit: 20 totalItems: 2 totalPages: 1 hasNext: false hasPrev: false filters: applied: q: null nodeTypes: null recordTypes: null origins: null connectorIds: null indexingStatus: null createdAt: null updatedAt: null size: null sortBy: updatedAt sortOrder: desc available: nodeTypes: - id: app label: Apps - id: recordGroup label: Record Groups recordTypes: [] origins: - id: COLLECTION label: Collection - id: CONNECTOR label: Connector connectors: - id: f3a4b5b6-5b6c-4e85-9097-3202cfe696fc label: Google Drive connectorType: drive indexingStatus: [] sortBy: - id: name label: Name - id: updatedAt label: Updated sortOrder: - id: asc label: Ascending - id: desc label: Descending breadcrumbs: null counts: null permissions: null '400': description: | Invalid request parameters. The backend's validation message is returned verbatim in `error.message`. See the examples below for the common triggers. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_BAD_REQUEST example: HTTP_BAD_REQUEST message: type: string example: Search query must be at least 2 characters examples: query_too_short: summary: Search query shorter than 2 characters value: error: code: HTTP_BAD_REQUEST message: Search query must be at least 2 characters comma_list_too_long: summary: Comma-separated parameter exceeds 100 items value: error: code: HTTP_BAD_REQUEST message: 'Too many items in comma-separated list (max: 100, got: 142)' date_range_inverted: summary: Date range with gte > lte value: error: code: HTTP_BAD_REQUEST message: 'Date range invalid: gte must be <= lte' size_exceeds_max: summary: Size filter exceeds the 1 TB cap value: error: code: HTTP_BAD_REQUEST message: 'Size exceeds maximum (1TB): 2199023255552' '401': description: | Missing or invalid authentication token. The bearer token was absent, expired, malformed, or could not be verified by the auth middleware. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_UNAUTHORIZED example: HTTP_UNAUTHORIZED message: type: string example: Invalid token example: error: code: HTTP_UNAUTHORIZED message: Invalid token '403': description: | Insufficient OAuth scope. Only applies to OAuth tokens. The token did not carry the `kb:read` scope required by this endpoint. Regular (non-OAuth) JWT bearer tokens are not subject to scope enforcement and will not receive this error. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_FORBIDDEN example: HTTP_FORBIDDEN message: type: string example: 'Insufficient scope. Required: kb:read' example: error: code: HTTP_FORBIDDEN message: 'Insufficient scope. Required: kb:read' '500': description: An unexpected error occurred on the server. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_INTERNAL_SERVER_ERROR example: HTTP_INTERNAL_SERVER_ERROR message: type: string example: An unexpected error occurred example: error: code: HTTP_INTERNAL_SERVER_ERROR message: An unexpected error occurred /knowledgeBase/knowledge-hub/nodes/{parentType}/{parentId}: get: deprecated: true x-speakeasy-deprecation-message: Use the Knowledge Base API instead. This grouping will be removed in a future release tags: - Knowledge Base - Knowledge Hub summary: Get knowledge hub child nodes description: | Returns the children of a specific node in the knowledge hub tree. Use this endpoint to drill down into Collections, connector app hierarchies, folders, and record groups. **Navigation hierarchy** The typical drill-down path is: 1. Root apps (`GET /knowledgeBase/knowledge-hub/nodes`) 2. Record groups / folders within an app (`parentType=app`) 3. Records within a record group (`parentType=recordGroup`) 4. Sub-records or attachments within a record (`parentType=record`) **Parent identification** - `parentType` must be one of: `app`, `recordGroup`, `folder`, `record` - `parentId` is either a standard UUID or the Collection app sentinel `knowledgeBase_` (e.g. `knowledgeBase_org123`) **Filtering and searching** All query-param filters from the root endpoint are available here and operate within the scope of the parent node's subtree. When `q` is provided, the search spans all descendants of the parent node. **Response extras** When `include=breadcrumbs` is set, the response contains a `breadcrumbs` array tracing the path from the root to the current node. The `currentNode` and `parentNode` objects are always populated for non-root requests. **Access control** Requires a valid bearer token. For OAuth tokens the `kb:read` scope must be present; regular JWT bearer tokens pass through without scope enforcement. operationId: getKnowledgeHubChildNodes security: - bearerAuth: [] - oauth2: - kb:read parameters: - name: parentType in: path required: true description: | Type of the parent node whose children to retrieve. Must be one of: `app`, `recordGroup`, `folder`, `record`. Any other value returns a 400 error. schema: type: string enum: - app - recordGroup - folder - record - name: parentId in: path required: true description: | Identifier of the parent node. Accepts two formats: - A standard UUID (e.g. `f3a4b5b6-5b6c-4e85-9097-3202cfe696fc`) - The Collection app sentinel `knowledgeBase_` (e.g. `knowledgeBase_org123`) Any value that does not match either format returns a 400 error. schema: type: string pattern: ^(knowledgeBase_[a-zA-Z0-9_-]+|[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})$ - name: onlyContainers in: query required: false description: | When `true`, only nodes that have children are returned (useful for building sidebar / tree navigation). Leaf nodes are excluded. schema: type: boolean default: false - name: page in: query required: false description: | Page number (1-indexed). Combined with `limit` to paginate results. schema: type: integer minimum: 1 default: 1 - name: limit in: query required: false description: | Maximum number of items to return per page. schema: type: integer minimum: 1 maximum: 200 default: 50 - name: sortBy in: query required: false description: | Field to sort results by. Omitted → default `updatedAt`. Unknown value → silently falls back to `name`. schema: type: string enum: - name - createdAt - updatedAt - size - type default: updatedAt - name: sortOrder in: query required: false description: | Sort direction. Omitted → default `desc`. Unknown value → silently falls back to `asc`. schema: type: string enum: - asc - desc default: desc - name: q in: query required: false description: | Full-text search query. Must be between 2 and 500 characters (inclusive). When provided, the endpoint searches across all descendants of the parent node. schema: type: string minLength: 2 maxLength: 500 example: quarterly report - name: nodeTypes in: query required: false description: | Comma-separated list of node types to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `folder`, `app`, `recordGroup`, `record` schema: type: string example: recordGroup - name: recordTypes in: query required: false description: | Comma-separated list of record types to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `FILE`, `DRIVE`, `WEBPAGE`, `DATABASE`, `DATASOURCE`, `MESSAGE`, `MAIL`, `GROUP_MAIL`, `TICKET`, `COMMENT`, `INLINE_COMMENT`, `CONFLUENCE_PAGE`, `CONFLUENCE_BLOGPOST`, `SHAREPOINT_PAGE`, `SHAREPOINT_LIST`, `SHAREPOINT_LIST_ITEM`, `SHAREPOINT_DOCUMENT_LIBRARY`, `LINK`, `PROJECT`, `PULL_REQUEST`, `MEETING`, `PRODUCT`, `DEAL`, `CASE`, `TASK`, `ARTIFACT`, `CODE_FILE`, `SQL_TABLE`, `SQL_VIEW`, `OTHERS` schema: type: string example: FILE,CONFLUENCE_PAGE - name: origins in: query required: false description: | Comma-separated list of origin types to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `COLLECTION`, `CONNECTOR` schema: type: string example: CONNECTOR - name: connectorIds in: query required: false description: | Comma-separated list of connector instance IDs (UUIDs) to filter by. Maximum 100 items. No enum validation — any string is accepted, but non-existent IDs simply yield zero results. schema: type: string example: f3a4b5b6-5b6c-4e85-9097-3202cfe696fc - name: indexingStatus in: query required: false description: | Comma-separated list of indexing statuses to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `NOT_STARTED`, `PAUSED`, `IN_PROGRESS`, `COMPLETED`, `FAILED`, `FILE_TYPE_NOT_SUPPORTED`, `AUTO_INDEX_OFF`, `EMPTY`, `ENABLE_MULTIMODAL_MODELS`, `QUEUED` schema: type: string example: COMPLETED,FAILED - name: createdAt in: query required: false description: | Created-date range filter. Format: `gte:,lte:`. Both bounds are optional (you may send just `gte:...` or just `lte:...`). Timestamps must be in the range 0 to 9999999999999 and `gte` must be less than or equal to `lte` when both are present. schema: type: string example: gte:1700000000000,lte:1710000000000 - name: updatedAt in: query required: false description: | Updated-date range filter. Same format and constraints as `createdAt`. schema: type: string example: gte:1700000000000,lte:1710000000000 - name: size in: query required: false description: | File-size range filter in bytes. Format: `gte:,lte:`. Both bounds are optional. Values must be non-negative and at most 1099511627776 (1 TB). `gte` must be less than or equal to `lte` when both are present. schema: type: string example: gte:0,lte:10485760 - name: include in: query required: false description: | Comma-separated list of additional response sections to include. Invalid values are silently ignored. Maximum 100 items. Valid values: `breadcrumbs`, `counts`, `availableFilters`, `permissions` schema: type: string example: breadcrumbs,availableFilters responses: '200': description: | Paginated children of `{parentType}/{parentId}`. HTTP 200 returns `success: true` and `error: null`; see `KnowledgeHubNodesResponse` for the full shape. `id` and `currentNode` reflect the parent being browsed; `parentNode` is set when a grandparent exists. Optional sections (`availableFilters`, `counts`, `permissions`, `breadcrumbs`) are JSON `null` unless listed in `include` and populated by the server. content: application/json: schema: $ref: '#/components/schemas/KnowledgeHubNodesResponse' examples: collection_record_groups: summary: Record groups inside the Collection app with breadcrumbs value: success: true error: null id: knowledgeBase_org123 currentNode: id: knowledgeBase_org123 name: Collections nodeType: app subType: null parentNode: null items: - id: a1b2c3d4-e5f6-7890-abcd-ef1234567890 name: Engineering Docs nodeType: recordGroup parentId: knowledgeBase_org123 origin: COLLECTION connector: null recordType: null recordGroupType: KNOWLEDGE_BASE indexingStatus: null reason: null createdAt: 1700000000000 updatedAt: 1709500000000 sizeInBytes: null mimeType: null extension: null webUrl: null hasChildren: true previewRenderable: null permission: null sharingStatus: workspace isInternal: false - id: b2c3d4e5-f6a7-8901-bcde-f12345678901 name: HR Policies nodeType: recordGroup parentId: knowledgeBase_org123 origin: COLLECTION connector: null recordType: null recordGroupType: KNOWLEDGE_BASE indexingStatus: null reason: null createdAt: 1700100000000 updatedAt: 1709400000000 sizeInBytes: null mimeType: null extension: null webUrl: null hasChildren: true previewRenderable: null permission: null sharingStatus: private isInternal: false pagination: page: 1 limit: 20 totalItems: 2 totalPages: 1 hasNext: false hasPrev: false filters: applied: q: null nodeTypes: - recordGroup recordTypes: null origins: null connectorIds: null indexingStatus: null createdAt: null updatedAt: null size: null sortBy: name sortOrder: asc available: null breadcrumbs: - id: knowledgeBase_org123 name: Collections nodeType: app subType: null counts: null permissions: null '400': description: | Invalid request parameters or path values. The backend's validation message is returned verbatim in `error.message`. See the examples below for the common triggers. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_BAD_REQUEST example: HTTP_BAD_REQUEST message: type: string example: 'Invalid parent_type. Must be one of: app, recordGroup, folder, record' examples: invalid_parent_type: summary: parentType outside the allowed set value: error: code: HTTP_BAD_REQUEST message: 'Invalid parent_type. Must be one of: app, recordGroup, folder, record' invalid_parent_id: summary: parentId is neither a UUID nor knowledgeBase_ value: error: code: HTTP_BAD_REQUEST message: 'Invalid UUID format for parent_id: abc' query_too_short: summary: Search query shorter than 2 characters value: error: code: HTTP_BAD_REQUEST message: Search query must be at least 2 characters comma_list_too_long: summary: Comma-separated parameter exceeds 100 items value: error: code: HTTP_BAD_REQUEST message: 'Too many items in comma-separated list (max: 100, got: 142)' date_range_inverted: summary: Date range with gte > lte value: error: code: HTTP_BAD_REQUEST message: 'Date range invalid: gte must be <= lte' '401': description: | Missing or invalid authentication token. The bearer token was absent, expired, malformed, or could not be verified by the auth middleware. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_UNAUTHORIZED example: HTTP_UNAUTHORIZED message: type: string example: Invalid token example: error: code: HTTP_UNAUTHORIZED message: Invalid token '403': description: | Insufficient OAuth scope. Only applies to OAuth tokens. The token did not carry the `kb:read` scope required by this endpoint. Regular (non-OAuth) JWT bearer tokens are not subject to scope enforcement and will not receive this error. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_FORBIDDEN example: HTTP_FORBIDDEN message: type: string example: 'Insufficient scope. Required: kb:read' example: error: code: HTTP_FORBIDDEN message: 'Insufficient scope. Required: kb:read' '404': description: | Parent node not found. The `parentId` does not correspond to an existing node of the specified `parentType`, or the node has been deleted. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_NOT_FOUND example: HTTP_NOT_FOUND message: type: string example: Parent node not found example: error: code: HTTP_NOT_FOUND message: Parent node not found '500': description: An unexpected error occurred on the server. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_INTERNAL_SERVER_ERROR example: HTTP_INTERNAL_SERVER_ERROR message: type: string example: An unexpected error occurred example: error: code: HTTP_INTERNAL_SERVER_ERROR message: An unexpected error occurred /conversations/stream: post: tags: - Conversations summary: Create conversation with streaming response description: | Start a new conversation and stream the AI response over Server-Sent Events (SSE). Behaves like `POST /conversations` but emits tokens, tool activity, and status updates incrementally instead of returning a single JSON response at the end. **Lifecycle** 1. The server validates `query`, persists an in-progress conversation, then opens the SSE stream with HTTP `200`. 2. A `connected` event is emitted immediately with the new `conversationId` so the client can link the stream (sidebar, parallel tabs, deep links) without an extra request. 3. AI-backend events stream through (token chunks, tool calls, status, etc.). 4. On success a single `complete` event is emitted carrying the full persisted conversation. 5. On failure an `error` event is emitted and the conversation is marked FAILED before the stream closes. **Event vocabulary** Three events have stable, server-defined `data` shapes: - `connected` — `{ "message": string, "conversationId": string, "title": string }` - `complete` — `{ "conversation": Conversation, "meta": { "requestId": string, "timestamp": string, "duration": number } }` - `error` — `{ "error": string, "details"?: string }` The forwarded events are `status`, `answer_chunk`, `tool_calls`, `restreaming`, `metadata`, and `tool_execution_complete`. Their payloads come from the Python query service and may evolve. Note that raw `tool_call` / `tool_success` / `tool_error` / `tool_result` events emitted by the LLM tool runtime are rewrapped as `status` by the upstream wrapper before they reach this route, so clients on `/conversations/stream` never see those names directly. Clients should ignore unknown event names rather than treating them as errors. **Agent mode** When `chatMode` selects an agent mode (for example `agent:auto`), the optional `tools` list restricts which tools the agent may invoke for this turn. Outside agent modes the `tools` field is ignored. operationId: streamChat security: - bearerAuth: [] - oauth2: - conversation:chat requestBody: required: true description: Request payload content: application/json: schema: $ref: '#/components/schemas/CreateConversationRequest' responses: '200': description: | SSE stream established. The body is a sequence of `text/event-stream` frames using the event vocabulary described above. content: text/event-stream: schema: $ref: '#/components/schemas/AssistantStreamSSEEvent' '400': description: | Invalid request — `query` is missing, empty, or exceeds the 100000-character limit, or another field fails validation (for example a malformed `recordIds` or `currentTime`). '401': description: Unauthorized — valid bearer token required. '403': description: | Forbidden — the caller's token does not include the `conversation:chat` OAuth scope. '500': description: | Internal error before the SSE stream is established (for example, the initial conversation row could not be persisted). Once the stream is open, terminal failures are surfaced as an `error` SSE event instead of an HTTP status change. /conversations: get: tags: - Conversations summary: List all conversations description: | Retrieve paginated conversations for the authenticated user. **Overview:** Use the optional `source` query parameter to choose which list to return: `owned` — only conversations you own (`userId` matches the current user). `shared` — conversations where you have recipient access (`isShared` and your user appears in `sharedWith`), without the owner-only branch. Defaults to `owned` when omitted. Each call returns one list; call twice if you need both. **Filtering:** - Only non-archived conversations are returned by default - Use `/conversations/show/archives` for archived conversations **Sorting:** Conversations are sorted by last activity timestamp (most recent first) by default. operationId: getAllConversations security: - bearerAuth: [] - oauth2: - conversation:read parameters: - name: source in: query required: false description: | `owned` — owner list (`userId` filter only). `shared` — explicit share grant list (`isShared` + `sharedWith`). Defaults to `owned` when omitted. schema: type: string enum: - owned - shared default: owned - name: page in: query required: false description: Page number (1-based). Defaults to 1. schema: type: integer minimum: 1 - name: limit in: query required: false description: Page size. Defaults to 20; capped by the server (max 100). schema: type: integer minimum: 1 - name: sortBy in: query required: false description: Sort field. Invalid values fall back to `lastActivityAt`. schema: type: string enum: - createdAt - lastActivityAt - title - name: sortOrder in: query required: false description: Sort direction. Defaults to `desc` unless set to `asc`. schema: type: string enum: - asc - desc - name: conversationId in: query required: false description: When set, restricts results to that conversation ID (if visible under the chosen `source`). schema: type: string - name: search in: query required: false description: Case-insensitive match on title and message content (max 1000 characters). schema: type: string - name: startDate in: query required: false description: Filter by `createdAt` ≥ this ISO date. schema: type: string format: date-time - name: endDate in: query required: false description: Filter by `createdAt` ≤ this ISO date. schema: type: string format: date-time - name: shared in: query required: false description: | When set, filters by `isShared`. Accepts case-insensitive `true`/`false`, or `1`/`0`. schema: type: string responses: '200': description: List of conversations for the requested source content: application/json: schema: type: object required: - conversations - source - pagination - filters - meta properties: conversations: type: array items: $ref: '#/components/schemas/ConversationListItem' source: type: string enum: - owned - shared description: Echoes the requested `source` query value. pagination: type: object properties: page: type: integer limit: type: integer totalCount: type: integer totalPages: type: integer hasNextPage: type: boolean hasPrevPage: type: boolean filters: type: object additionalProperties: false description: | Filter introspection block. `applied` summarises the filters active on this request; `available` catalogues every supported filter with its current value and whether it is applied. required: - applied - available properties: applied: type: object additionalProperties: false required: - filters - values properties: filters: type: array description: Names of filters currently applied. items: type: string values: type: object additionalProperties: false description: | Current value for each applied filter. Only keys present in `filters` are populated; others are omitted. properties: search: type: string shared: type: string tags: type: string minMessages: type: string sortBy: type: string sortOrder: type: string startDate: type: string endDate: type: string messageType: type: string page: type: integer limit: type: integer dateRange: type: object additionalProperties: false properties: start: type: string nullable: true end: type: string nullable: true available: type: object additionalProperties: false required: - shared - tags - minMessages - search - pagination - sorting - dateFilters - messageFilters - sortingMessages properties: shared: type: object additionalProperties: false properties: values: type: array items: type: string description: Accepted values for the `shared` query param. description: type: string current: type: string nullable: true applied: type: boolean tags: type: object additionalProperties: false properties: type: type: string description: type: string current: type: string nullable: true applied: type: boolean minMessages: type: object additionalProperties: false properties: type: type: string description: type: string current: type: number nullable: true applied: type: boolean search: type: object additionalProperties: false properties: type: type: string description: type: string current: type: string nullable: true applied: type: boolean pagination: type: object additionalProperties: false properties: page: type: object additionalProperties: false properties: type: type: string current: type: integer min: type: integer max: type: integer default: type: integer description: type: string applied: type: boolean limit: type: object additionalProperties: false properties: type: type: string current: type: integer min: type: integer max: type: integer default: type: integer description: type: string applied: type: boolean sorting: type: object additionalProperties: false properties: sortBy: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string applied: type: boolean sortOrder: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string applied: type: boolean dateFilters: type: object additionalProperties: false properties: dateRange: type: object additionalProperties: false properties: type: type: string description: type: string format: type: string current: type: object additionalProperties: false properties: start: type: string nullable: true end: type: string nullable: true applied: type: boolean messageFilters: type: object additionalProperties: false properties: messageType: type: object additionalProperties: false properties: values: type: array items: type: string description: type: string current: type: string nullable: true applied: type: boolean sortingMessages: type: object additionalProperties: false properties: sortBy: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string sortOrder: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string meta: type: object properties: requestId: type: string timestamp: type: string format: date-time duration: type: integer '400': description: | Bad request — for example, missing or invalid `source` (must be `owned` or `shared`), invalid date query params, invalid `search` shape, or search text over the length limit. '401': description: Unauthorized - Valid bearer token required /conversations/show/archives: get: tags: - Conversations summary: List archived conversations description: | Retrieve all archived conversations for the authenticated user. **Overview:** Archived conversations are hidden from the main list but preserved for reference. This endpoint returns only conversations where `isArchived: true` and `archivedBy` is set. Results include conversations the caller owns and those shared with them. **Filtering and sorting:** Results can be narrowed using `search`, `shared`, `startDate`, `endDate`, and `conversationId`. Sorting is controlled by `sortBy` and `sortOrder`. Pagination is controlled by `page` and `limit`. **Unarchiving:** Use `PATCH /conversations/{conversationId}/unarchive` to restore a conversation to the active list. operationId: getArchivedConversations security: - bearerAuth: [] - oauth2: - conversation:read parameters: - name: page in: query required: false description: Page number (1-indexed) schema: type: integer minimum: 1 maximum: 1000 default: 1 - name: limit in: query required: false description: Items per page schema: type: integer minimum: 1 maximum: 100 default: 20 - name: sortBy in: query required: false description: Field to sort by schema: type: string enum: - createdAt - lastActivityAt - title default: lastActivityAt - name: sortOrder in: query required: false description: Sort direction schema: type: string enum: - asc - desc default: desc - name: search in: query required: false description: Case-insensitive substring match against title and message content (max 1000 chars) schema: type: string maxLength: 1000 - name: shared in: query required: false description: Filter by shared status schema: type: boolean - name: startDate in: query required: false description: Include conversations created on or after this timestamp schema: type: string format: date-time - name: endDate in: query required: false description: Include conversations created on or before this timestamp schema: type: string format: date-time - name: conversationId in: query required: false description: Restrict results to a single conversation by identifier schema: type: string format: objectId responses: '200': description: List of archived conversations content: application/json: schema: type: object additionalProperties: false properties: conversations: type: array description: Archived conversations matching the filter items: allOf: - $ref: '#/components/schemas/Conversation' - type: object properties: archivedAt: type: string format: date-time description: Timestamp when the conversation was archived pagination: type: object additionalProperties: false properties: page: type: integer description: Current page number limit: type: integer description: Items per page totalCount: type: integer description: Total archived conversations matching the filter totalPages: type: integer description: Total pages at the current limit hasNextPage: type: boolean description: Whether a next page exists hasPrevPage: type: boolean description: Whether a previous page exists filters: type: object additionalProperties: false description: Filters applied to this request and filters available for clients to use properties: applied: type: object additionalProperties: false properties: filters: type: array description: Names of filters that were applied items: type: string values: type: object additionalProperties: true description: Map of applied filter name to its current value available: type: object additionalProperties: false description: Describes filters supported by this endpoint and their current values properties: shared: type: object additionalProperties: false properties: values: type: array items: type: string description: Allowed values for the `shared` filter description: type: string current: type: string nullable: true description: Current value supplied by the caller, or null applied: type: boolean description: Whether this filter was applied on the request tags: type: object additionalProperties: false properties: type: type: string description: Expected value type description: type: string current: type: string nullable: true applied: type: boolean minMessages: type: object additionalProperties: false properties: type: type: string description: type: string current: type: integer nullable: true applied: type: boolean search: type: object additionalProperties: false properties: type: type: string description: type: string current: type: string nullable: true applied: type: boolean pagination: type: object additionalProperties: false properties: page: type: object additionalProperties: false properties: type: type: string current: type: integer min: type: integer max: type: integer default: type: integer description: type: string applied: type: boolean limit: type: object additionalProperties: false properties: type: type: string current: type: integer min: type: integer max: type: integer default: type: integer description: type: string applied: type: boolean sorting: type: object additionalProperties: false properties: sortBy: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string applied: type: boolean sortOrder: type: object additionalProperties: false properties: values: type: array items: type: string enum: - asc - desc default: type: string enum: - asc - desc description: type: string current: type: string enum: - asc - desc applied: type: boolean dateFilters: type: object additionalProperties: false properties: dateRange: type: object additionalProperties: false properties: type: type: string description: type: string format: type: string description: Expected date format for `startDate` and `endDate` inputs current: type: object additionalProperties: false properties: start: type: string format: date-time nullable: true end: type: string format: date-time nullable: true applied: type: boolean messageFilters: type: object additionalProperties: false properties: messageType: type: object additionalProperties: false properties: values: type: array items: type: string description: type: string current: type: string nullable: true applied: type: boolean sortingMessages: type: object additionalProperties: false properties: sortBy: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string sortOrder: type: object additionalProperties: false properties: values: type: array items: type: string enum: - asc - desc default: type: string enum: - asc - desc description: type: string current: type: string enum: - asc - desc summary: type: object additionalProperties: false properties: totalArchived: type: integer description: Total archived conversations matching the filter oldestArchive: type: string format: date-time description: Archive timestamp of the first item in the current page newestArchive: type: string format: date-time description: Archive timestamp of the last item in the current page meta: type: object additionalProperties: false properties: requestId: type: string description: Request correlation identifier timestamp: type: string format: date-time description: Response generation timestamp duration: type: integer description: Server processing time in milliseconds '401': description: Unauthorized /conversations/show/archives/search: get: tags: - Conversations summary: Search archived conversations description: | Search across all archived conversations (assistant and agent) for the authenticated user. **Overview:** Performs a case-insensitive substring match against conversation titles and message content across both assistant (`Conversation`) and agent (`AgentConversation`) archived collections. Results are merged server-side and sorted by `lastActivityAt` descending. **Search parameter:** The `search` query parameter is required, must be a non-empty string, and is capped at 1000 characters. Requests that omit it or exceed the cap return `400`. **Pagination:** Results are paginated using `page` and `limit`. The response includes a `pagination` block with total counts and a `summary` block that breaks matches down by source. **Item shape:** Each item is a conversation list entry (no `messages` payload — that field is omitted for performance) tagged with `source`, plus computed `isOwner`, `accessLevel`, `archivedAt`, and `archivedBy`. `agentKey` is present only when `source` is `agent`. operationId: searchArchivedConversations security: - bearerAuth: [] - oauth2: - conversation:read parameters: - name: search in: query required: true description: Search term to match against conversation titles and message content (max 1000 chars) schema: type: string minLength: 1 maxLength: 1000 - name: page in: query required: false description: Page number (1-indexed) schema: type: integer minimum: 1 maximum: 1000 default: 1 - name: limit in: query required: false description: Items per page schema: type: integer minimum: 1 maximum: 100 default: 20 responses: '200': description: Search results across archived conversations content: application/json: schema: type: object additionalProperties: false properties: conversations: type: array description: Archived conversations (assistant and agent) matching the search term items: allOf: - $ref: '#/components/schemas/ConversationListItem' - type: object properties: source: type: string enum: - assistant - agent description: Origin collection of the conversation agentKey: type: string description: Agent identifier — present only when `source` is `agent` archivedAt: type: string format: date-time description: Timestamp when the conversation was archived pagination: type: object additionalProperties: false properties: page: type: integer description: Current page number limit: type: integer description: Items per page totalCount: type: integer description: Total matches across assistant and agent archives totalPages: type: integer description: Total pages at the current limit hasNextPage: type: boolean description: Whether a next page exists hasPrevPage: type: boolean description: Whether a previous page exists summary: type: object additionalProperties: false properties: totalMatches: type: integer description: Combined match count across both collections assistantMatches: type: integer description: Match count in the assistant (`Conversation`) collection agentMatches: type: integer description: Match count in the agent (`AgentConversation`) collection searchQuery: type: string description: Trimmed search term that was applied meta: type: object additionalProperties: false properties: requestId: type: string description: Request correlation identifier timestamp: type: string format: date-time description: Response generation timestamp duration: type: integer description: Server processing time in milliseconds '400': description: Search parameter missing, empty, not a string, or longer than 1000 characters '401': description: Unauthorized /conversations/{conversationId}: get: tags: - Conversations summary: Get conversation by ID description: | Retrieve a specific conversation with its full message history. **Overview:** Returns the complete conversation including all messages, citations, feedback, and metadata. Messages can be paginated for long conversations. **Message Pagination:** For conversations with many messages, use pagination parameters: - `page`: Page number (default: 1) - `limit`: Messages per page (default: 10) - `sortBy`: Sort field (default: createdAt) - `sortOrder`: 'asc' or 'desc' (default: desc) **Access Control:** Users can access conversations they own or that have been shared with them. operationId: getConversationById security: - bearerAuth: [] - oauth2: - conversation:read parameters: - name: conversationId in: path required: true description: Unique conversation identifier schema: type: string format: objectId example: 507f1f77bcf86cd799439011 - name: page in: query description: Page number for message pagination schema: type: integer minimum: 1 default: 1 - name: limit in: query description: Number of messages per page schema: type: integer minimum: 1 maximum: 100 default: 20 - name: sortBy in: query description: Field to sort messages by schema: type: string enum: - createdAt - messageType - content default: createdAt - name: sortOrder in: query description: Sort direction schema: type: string enum: - asc - desc default: desc - name: search in: query description: Case-insensitive search across conversation title and message content schema: type: string maxLength: 1000 - name: startDate in: query description: Filter messages created on or after this date (ISO 8601) schema: type: string format: date-time - name: endDate in: query description: Filter messages created on or before this date (ISO 8601) schema: type: string format: date-time - name: shared in: query description: Filter by shared status of the conversation schema: type: boolean - name: messageType in: query description: Filter messages by type schema: type: string enum: - user_query - bot_response - error - feedback - system responses: '200': description: Conversation with paginated messages, applied filter metadata, and request metadata content: application/json: schema: type: object additionalProperties: false properties: conversation: type: object additionalProperties: false properties: id: type: string format: objectId description: Unique conversation identifier title: type: string description: Conversation title initiator: type: string format: objectId description: User who started the conversation createdAt: type: string format: date-time isShared: type: boolean sharedWith: type: array items: type: object additionalProperties: false properties: userId: type: string format: objectId accessLevel: type: string enum: - read - write status: type: string enum: - None - Inprogress - Complete - Failed failReason: type: string description: Populated only when `status` is `Failed` messages: type: array description: Page of messages, sliced by `pagination` and ordered by `sortingMessages` items: type: object additionalProperties: false properties: _id: type: string format: objectId messageType: type: string enum: - user_query - bot_response - error - feedback - system content: type: string contentFormat: type: string enum: - MARKDOWN - JSON - HTML confidence: type: string enum: - Very High - High - Medium - Low - Unknown nullable: true description: | AI confidence in the answer. Present only on `bot_response` messages, and only when the model emitted a trailing confidence block. This field is now optional and nullable; it was previously always present and non-nullable. Treat a missing or `null` value as "no confidence reported" and guard before using it. Change effective in SDK v1.2.0 (v1.1.0 and earlier always populated it). citations: type: array description: Citations attached to this message. `citationData` is the populated citation document. items: type: object additionalProperties: false properties: citationId: type: string format: objectId citationData: $ref: '#/components/schemas/Citation' followUpQuestions: type: array items: $ref: '#/components/schemas/FollowUpQuestion' feedback: type: array items: $ref: '#/components/schemas/MessageFeedback' referenceData: type: array description: Reference IDs surfaced from tool responses, used for follow-up queries items: type: object additionalProperties: false properties: name: type: string description: Display name shown to the user. id: type: string description: Technical identifier (numeric ID, UUID, etc.). type: type: string description: Item type (e.g. `project`, `issue`, `file`, `notebook`, `page`). app: type: string description: | Source application (e.g. `jira`, `confluence`, `sharepoint`, `slack`, `drive`, `gmail`). webUrl: type: string description: URL to open the item in a browser. metadata: type: object additionalProperties: type: string description: | App-specific fields keyed by name (e.g. `key` for a Jira project, `siteId` for a SharePoint document). modelInfo: $ref: '#/components/schemas/ConversationModelInfo' appliedFilters: type: object additionalProperties: false properties: apps: type: array items: $ref: '#/components/schemas/AppliedFilterNode' kb: type: array items: $ref: '#/components/schemas/AppliedFilterNode' attachments: type: array description: | Files uploaded for this message turn (see `POST /conversations/attachments/upload`). items: $ref: '#/components/schemas/ChatAttachmentRef' metadata: type: object additionalProperties: false properties: processingTimeMs: type: number modelVersion: type: string aiTransactionId: type: string createdAt: type: string format: date-time updatedAt: type: string format: date-time modelInfo: $ref: '#/components/schemas/ConversationModelInfo' pagination: type: object additionalProperties: false description: | Pagination over the conversation's messages. Messages are paginated backwards (newest first), so `messageRange.start`/`messageRange.end` refer to 1-based positions within the full message list. properties: page: type: integer limit: type: integer totalCount: type: integer description: Total number of messages in the conversation totalPages: type: integer hasNextPage: type: boolean description: True if there are older messages available hasPrevPage: type: boolean description: True if there are newer messages available messageRange: type: object additionalProperties: false properties: start: type: integer end: type: integer access: type: object additionalProperties: false properties: isOwner: type: boolean accessLevel: type: string enum: - read - write filters: type: object additionalProperties: false description: Summary of which filter/sort/pagination parameters were applied to this request, plus the catalog of options available on this endpoint. properties: applied: type: object additionalProperties: false properties: filters: type: array description: Names of the filters/parameters that were actually applied items: type: string values: type: object additionalProperties: true description: Map of applied filter name to the value that was applied available: type: object additionalProperties: false properties: shared: type: object additionalProperties: false properties: values: type: array items: type: string description: type: string current: type: string nullable: true applied: type: boolean tags: type: object additionalProperties: false description: Advertised in the `available` catalog but not currently applied as a filter by the server. properties: type: type: string description: type: string current: type: string nullable: true applied: type: boolean minMessages: type: object additionalProperties: false description: Advertised in the `available` catalog but not currently applied as a filter by the server. properties: type: type: string description: type: string current: type: string nullable: true applied: type: boolean search: type: object additionalProperties: false properties: type: type: string description: type: string current: type: string nullable: true applied: type: boolean pagination: type: object additionalProperties: false properties: page: type: object additionalProperties: false properties: type: type: string current: type: integer min: type: integer max: type: integer default: type: integer description: type: string applied: type: boolean limit: type: object additionalProperties: false properties: type: type: string current: type: integer min: type: integer max: type: integer default: type: integer description: type: string applied: type: boolean sorting: type: object additionalProperties: false description: Sort applied to the conversation list. Field set echoes back the original list-endpoint sort options even though this endpoint returns a single conversation. properties: sortBy: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string applied: type: boolean sortOrder: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string applied: type: boolean dateFilters: type: object additionalProperties: false properties: dateRange: type: object additionalProperties: false properties: type: type: string description: type: string format: type: string current: type: object additionalProperties: false properties: start: type: string nullable: true end: type: string nullable: true applied: type: boolean messageFilters: type: object additionalProperties: false properties: messageType: type: object additionalProperties: false properties: values: type: array items: type: string description: type: string current: type: string nullable: true applied: type: boolean sortingMessages: type: object additionalProperties: false description: Sort applied to messages within the conversation (separate from the conversation-list `sorting` block). properties: sortBy: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string sortOrder: type: object additionalProperties: false properties: values: type: array items: type: string default: type: string description: type: string current: type: string meta: type: object additionalProperties: false properties: requestId: type: string timestamp: type: string format: date-time duration: type: integer description: Server processing time in milliseconds conversationId: type: string format: objectId messageCount: type: integer description: Total number of messages in the conversation '401': description: Unauthorized '403': description: Forbidden - No access to this conversation '404': description: Conversation not found delete: tags: - Conversations summary: Delete conversation description: | Delete a conversation by its ID. **Overview:** Performs a soft delete by setting `isDeleted: true`. The conversation is removed from listings but preserved in the database. All citations referenced by messages in the conversation are also soft-deleted. **Permissions:** The conversation initiator can always delete. Users the conversation has been shared with may delete it only when their `sharedWith.accessLevel` is `write`. operationId: deleteConversationById security: - bearerAuth: [] - oauth2: - conversation:write parameters: - name: conversationId in: path required: true description: Unique conversation identifier schema: type: string format: objectId responses: '200': description: Conversation deleted successfully content: application/json: schema: type: object additionalProperties: false properties: id: type: string format: objectId description: Identifier of the conversation that was deleted status: type: string enum: - deleted description: Outcome of the operation deletedAt: type: string format: date-time description: Timestamp when the conversation was marked deleted deletedBy: type: string format: objectId description: Identifier of the user who performed the delete citationsDeleted: type: integer description: Number of citations soft-deleted alongside the conversation meta: type: object additionalProperties: false properties: requestId: type: string description: Server-assigned identifier for the request timestamp: type: string format: date-time description: Server time the response was produced duration: type: integer description: Server processing time in milliseconds '400': description: Invalid `conversationId` path parameter '401': description: Unauthorized '403': description: Forbidden - token is missing the `conversation:write` scope '404': description: Conversation not found, already deleted, or caller has no delete access '500': description: Internal server error while deleting the conversation /conversations/{conversationId}/messages/stream: post: tags: - Conversations summary: Add message to a conversation with streaming response description: | Add a follow-up message to an existing conversation and stream the assistant's response over Server-Sent Events. Functionally equivalent to `POST /conversations/{conversationId}/messages` but the response is delivered as an SSE stream so clients can render the answer incrementally. The wire vocabulary is described by `AssistantMessageStreamSSEEvent`. It is the same event set as `/conversations/stream`; only the `connected` and `complete` payloads differ because the conversation already exists when this route is called. operationId: addMessageStream security: - bearerAuth: [] - oauth2: - conversation:chat parameters: - name: conversationId in: path required: true description: | Identifier of the conversation to append the message to. The conversation must belong to the caller and must not be deleted. schema: type: string format: objectId requestBody: required: true description: Request payload content: application/json: schema: $ref: '#/components/schemas/AddMessageRequest' responses: '200': description: | SSE stream established. The body is a sequence of `text/event-stream` frames using the event vocabulary described on the schema below. content: text/event-stream: schema: $ref: '#/components/schemas/AssistantMessageStreamSSEEvent' '400': description: | Invalid request — `query` is missing or empty, or another field fails validation (for example a malformed `currentTime`). '401': description: Unauthorized — valid bearer token required. '403': description: | Forbidden — the caller's token does not include the `conversation:chat` OAuth scope. '404': description: | The conversation does not exist, is deleted, or does not belong to the caller. '500': description: | Internal error before the SSE stream is established (for example, the user message could not be persisted to the conversation). Once the stream is open, terminal failures are surfaced as an `error` SSE event instead of an HTTP status change. /conversations/{conversationId}/title: patch: tags: - Conversations summary: Update conversation title description: | Update the title of a conversation. **Overview:** Conversation titles are auto-generated from the first query by default. Use this endpoint to set a custom, more descriptive title. **Title limits:** - Minimum: 1 character - Maximum: 200 characters **Permissions:** The conversation must exist, belong to the calling user's organization, be owned by the caller (matched on `userId`), and not be soft-deleted. operationId: updateConversationTitle security: - bearerAuth: [] - oauth2: - conversation:write parameters: - name: conversationId in: path required: true description: Unique conversation identifier schema: type: string format: objectId requestBody: required: true description: Request payload content: application/json: schema: type: object additionalProperties: false required: - title properties: title: type: string minLength: 1 maxLength: 200 description: New conversation title example: Q4 Sales Analysis Discussion responses: '200': description: Title updated successfully content: application/json: schema: type: object additionalProperties: false required: - conversation - meta properties: conversation: type: object additionalProperties: false description: | The full conversation document after the title update, returned as stored in MongoDB. required: - _id - userId - orgId - initiator - messages - isShared - isDeleted - isArchived - sharedWith - conversationErrors - lastActivityAt - createdAt - updatedAt - __v properties: _id: type: string format: objectId description: Unique conversation identifier userId: type: string format: objectId description: ID of the user who owns this conversation orgId: type: string format: objectId description: Organization this conversation belongs to title: type: string description: | Conversation title. Present and equal to the value submitted in the request body after a successful update. initiator: type: string format: objectId description: User who started the conversation messages: type: array description: All messages stored on this conversation. items: type: object additionalProperties: false required: - _id - messageType - content - contentFormat - citations - followUpQuestions - feedback - referenceData - createdAt - updatedAt properties: _id: type: string format: objectId messageType: type: string enum: - user_query - bot_response - error - feedback - system content: type: string contentFormat: type: string enum: - MARKDOWN - JSON - HTML default: MARKDOWN confidence: type: string nullable: true description: | AI confidence in the answer. Present only on `bot_response` messages, and only when the model emitted a trailing confidence block. This field is now optional and nullable; it was previously always present and non-nullable. Treat a missing or `null` value as "no confidence reported" and guard before using it. Change effective in SDK v1.3.0 (v1.2.0 and earlier always populated it). citations: type: array description: | References to source documents used in the response, stored as raw citation pointers (not populated on this endpoint). items: $ref: '#/components/schemas/CitationReference' followUpQuestions: type: array items: $ref: '#/components/schemas/FollowUpQuestion' feedback: type: array items: $ref: '#/components/schemas/MessageFeedback' referenceData: type: array description: | Reference IDs surfaced from tool responses, used for follow-up queries. items: type: object additionalProperties: false properties: name: type: string description: Display name shown to the user. id: type: string description: Technical identifier (numeric ID, UUID, etc.). type: type: string description: Item type (e.g. `project`, `issue`, `file`, `notebook`, `page`). app: type: string description: | Source application (e.g. `jira`, `confluence`, `sharepoint`, `slack`, `drive`, `gmail`). webUrl: type: string description: URL to open the item in a browser. metadata: type: object additionalProperties: type: string description: | App-specific fields keyed by name (e.g. `key` for a Jira project, `siteId` for a SharePoint document). modelInfo: $ref: '#/components/schemas/ConversationModelInfo' appliedFilters: type: object additionalProperties: false properties: apps: type: array items: $ref: '#/components/schemas/AppliedFilterNode' kb: type: array items: $ref: '#/components/schemas/AppliedFilterNode' attachments: type: array description: | Files uploaded for this message turn (see `POST /conversations/attachments/upload`). items: $ref: '#/components/schemas/ChatAttachmentRef' metadata: type: object additionalProperties: false properties: processingTimeMs: type: number modelVersion: type: string aiTransactionId: type: string reason: type: string createdAt: type: string format: date-time updatedAt: type: string format: date-time status: type: string enum: - None - Inprogress - Complete - Failed description: | Current status of the conversation: - `None` — no activity yet - `Inprogress` — AI is processing - `Complete` — response ready - `Failed` — error occurred failReason: type: string description: | Error description, populated only when `status` is `Failed`. modelInfo: $ref: '#/components/schemas/ConversationModelInfo' isShared: type: boolean default: false description: Whether this conversation is shared with others shareLink: type: string description: Shareable link if the conversation is shared sharedWith: type: array description: Users this conversation is shared with items: type: object additionalProperties: false required: - userId - accessLevel properties: userId: type: string format: objectId accessLevel: type: string enum: - read - write default: read isArchived: type: boolean default: false description: Whether this conversation is archived archivedBy: type: string format: objectId nullable: true description: | User ID of the last user who archived this row, or `null` after unarchive cleared the archive state. Absent on rows that have never been archived. isDeleted: type: boolean default: false description: Whether this conversation has been soft-deleted. deletedBy: type: string format: objectId description: User who soft-deleted this conversation. conversationErrors: type: array description: | Errors recorded against this conversation (e.g. failed message generations). items: type: object additionalProperties: false required: - _id - message - timestamp properties: _id: type: string format: objectId description: Sub-document identifier auto-assigned by MongoDB. message: type: string errorType: type: string timestamp: type: string format: date-time description: | Time the error was recorded. Server-defaulted to `Date.now` when the entry is pushed, so always present. messageId: type: string format: objectId stack: type: string metadata: type: object additionalProperties: true description: | Free-form metadata attached to this error entry (Map of Mixed in the schema). metadata: type: object additionalProperties: true description: Free-form metadata attached to the conversation. lastActivityAt: type: integer format: int64 description: | Unix timestamp of the last activity, stored as epoch milliseconds (server-side default `Date.now`). createdAt: type: string format: date-time updatedAt: type: string format: date-time __v: type: integer description: Mongoose document version key. meta: type: object additionalProperties: false required: - requestId - timestamp - duration properties: requestId: type: string description: | Server-side request identifier. Read from the `X-Request-ID` header when supplied, otherwise auto-generated, so this field is always present. timestamp: type: string format: date-time duration: type: integer description: Server-side processing time in milliseconds. '400': description: | Invalid request. Possible causes: - `title` missing, empty, or longer than 200 characters. - `conversationId` path parameter is not a valid ObjectId. '401': description: Unauthorized '403': description: Forbidden - token is missing the `conversation:write` scope '404': description: Conversation not found, soft-deleted, or not owned by the caller. '500': description: Persistence layer failed to update the conversation document. /conversations/{conversationId}/archive: patch: tags: - Conversations summary: Archive conversation description: | Archive a conversation to hide it from the main list. **Overview:** Archived conversations are preserved but hidden from the default conversation list. Use archiving to clean up your workspace without permanently deleting conversations. **Access:** The caller must be the conversation's initiator, or be listed in `sharedWith` with `accessLevel: write`. Already-archived conversations return `400`. **Retrieval:** View archived conversations using `GET /conversations/show/archives`. Restore one with `PATCH /conversations/{conversationId}/unarchive`. operationId: archiveConversation security: - bearerAuth: [] - oauth2: - conversation:write parameters: - name: conversationId in: path required: true description: Conversation identifier schema: type: string format: objectId responses: '200': description: Conversation archived successfully content: application/json: schema: type: object additionalProperties: false properties: id: type: string format: objectId description: Conversation identifier status: type: string enum: - archived description: New archive status of the conversation archivedBy: type: string format: objectId description: User who archived the conversation archivedAt: type: string format: date-time description: Timestamp when the conversation was archived meta: type: object additionalProperties: false properties: requestId: type: string description: Request correlation identifier timestamp: type: string format: date-time description: Response generation timestamp duration: type: integer description: Server processing time in milliseconds '400': description: Conversation is already archived '401': description: Unauthorized '404': description: Conversation not found or caller lacks archive permission /conversations/{conversationId}/unarchive: patch: tags: - Conversations summary: Unarchive conversation description: | Restore an archived conversation. - Path params: `conversationId` - Query params: none - Body: none operationId: unarchiveConversation security: - bearerAuth: [] - oauth2: - conversation:write parameters: - name: conversationId in: path required: true description: Conversation identifier schema: type: string format: objectId responses: '200': description: Conversation unarchived successfully content: application/json: schema: type: object additionalProperties: false properties: id: type: string format: objectId description: Conversation identifier status: type: string enum: - unarchived description: New archive status of the conversation unarchivedBy: type: string format: objectId description: User who unarchived the conversation unarchivedAt: type: string format: date-time description: Timestamp when the conversation was unarchived meta: type: object additionalProperties: false properties: requestId: type: string description: Request correlation identifier timestamp: type: string format: date-time description: Response generation timestamp duration: type: integer description: Server processing time in milliseconds '400': description: Conversation is not currently archived '401': description: Unauthorized '403': description: Forbidden - token is missing the `conversation:write` scope '404': description: Conversation not found or caller lacks unarchive permission '500': description: Persistence layer failed to update the conversation document. /conversations/{conversationId}/message/{messageId}/regenerate: post: tags: - Conversations summary: Regenerate AI response description: | Regenerate the AI response for a specific message and stream the new answer over Server-Sent Events. **Overview:** If you're not satisfied with an AI response, use this endpoint to generate a new answer. The original user query is re-processed and a new bot response replaces the previous one in place. **Constraints:** - Only the *last* message of the conversation can be regenerated. - The target message must be of type `bot_response`. **Use Cases:** - Response was incomplete or unclear - Want to try a different AI model - New documents have been indexed since original response **Model Override:** Specify `modelKey` to use a different model for regeneration. **Streaming:** The response is delivered as an SSE (`text/event-stream`) stream. The exact event vocabulary depends on `chatMode`: - For non-agent modes (e.g. `internal_search`, `web_search`) the request is dispatched to the assistant chat backend. - For agent modes (e.g. `agent:auto`) the request is dispatched to the agent backend with a placeholder agent built from the caller's workspace, which can additionally emit `tool_result` and `tool_execution_complete` events. See `SSEEvent` for the full union of event names this endpoint can emit across both backends. operationId: regenerateAnswer security: - bearerAuth: [] - oauth2: - conversation:chat parameters: - name: conversationId in: path required: true schema: type: string format: objectId - name: messageId in: path required: true description: ID of the message to regenerate response for schema: type: string format: objectId requestBody: description: Request payload content: application/json: schema: $ref: '#/components/schemas/RegenerateRequest' responses: '200': description: | SSE stream established. The body is a sequence of `text/event-stream` frames using the event vocabulary described on `SSEEvent`. The exact subset of events emitted depends on `chatMode` (see the route description for routing rules). Lifecycle (all event names are sent verbatim on the wire): - `connected` — `{ "message": "SSE connection established" }`. Fired once on connection by the API layer. - `status` — progress messages from the AI backend. Possible `status` sub-values include `started`, `transforming`, `searching`, `processing`, `checking_tools`, `generating_answer`, `generating`, `analyzing`, `evaluating`, `planning`, `executing`, `retrying`, `continuing`, `success`, `skipped`, `pending`, `keepalive`, `cascade_error`, and backend-defined values that may be added over time. - `answer_chunk` — incremental token batches with running `accumulated` text, accumulated `citations`, and the backend-supplied `confidence` (typically null until the final chunk). - `tool_calls` / `tool_call` / `tool_success` / `tool_error` — emitted when the model invokes tools (agent chat modes, or the non-agent path when SQL / record-fetch tools are configured). - `tool_result` / `tool_execution_complete` — additional tool lifecycle events emitted only on the agent-mode path. - `restreaming` — emitted when the LLM is restarted with new context (e.g. before a citation-verification pass or reflection-driven retry). - `metadata` — `{}` keep-alive emitted by the JSON-streaming branch while waiting for the next safe-to-flush chunk. - `complete` — `{ "conversation": Conversation, "recordsUsed": number, "meta": { "requestId": string, "timestamp": string, "duration": number, "recordsUsed": number } }`. Fired once after the regeneration is persisted; the new bot response replaces the previous one in `conversation.messages` at the same index. The AI backend's own `complete` frame is consumed server-side and is **not** forwarded — clients see only this server-defined frame. - `error` — `{ "error": string, "details"?: string }`. Fired if the stream fails; the previous bot response is replaced with an error message and the conversation row is marked FAILED before close. Clients should ignore unknown event names rather than treating them as errors. content: text/event-stream: schema: $ref: '#/components/schemas/SSEEvent' '400': description: | Cannot regenerate. Common causes: target message is not the last message in the conversation, target message is not of type `bot_response`, or no preceding `user_query` exists. '401': description: Unauthorized '404': description: Conversation or message not found /conversations/{conversationId}/message/{messageId}/feedback: post: tags: - Conversations summary: Submit feedback on AI response description: | Append a feedback entry to a bot-response message. **Overview** Feedback helps improve AI response quality over time. You can record an overall helpfulness signal, issue categories, and free-text comments. Each call appends a new entry to the message; previous entries are preserved. **Feedback options** - `isHelpful` — overall thumbs up/down. - `categories` — issue or positive categories from a fixed list. - `comments` — free-text `positive` and `negative`. **Restrictions** Feedback can only be submitted on `bot_response` messages — user queries and system messages are rejected with `400`. operationId: updateMessageFeedback security: - bearerAuth: [] - oauth2: - conversation:write parameters: - name: conversationId in: path required: true description: Unique conversation identifier. schema: type: string format: objectId - name: messageId in: path required: true description: Identifier of the bot-response message being rated. schema: type: string format: objectId requestBody: required: true description: Request payload content: application/json: schema: $ref: '#/components/schemas/MessageFeedbackSubmitRequest' responses: '200': description: Feedback submitted successfully. content: application/json: schema: $ref: '#/components/schemas/MessageFeedbackUpdateResponse' '400': description: | Invalid request. Possible causes: - Feedback target is not a `bot_response` message. - A `categories` value is not in the allowed list. - `conversationId` or `messageId` is not a valid ObjectId. '401': description: Unauthorized. '404': description: | Conversation or message not found, or the caller does not have access to this conversation. '500': description: Persistence layer failed to append the feedback entry. /search: post: tags: - Semantic Search summary: Perform semantic search description: | Run a semantic search across your organization's knowledge base. Matching is meaning-based, so relevant results surface even when the wording differs from the query. Use optional `filters` to narrow the scope: - `filters.apps` — restrict to specific connector apps (for example Google Drive or Confluence). - `filters.kb` — restrict to specific knowledge bases. The response returns a `searchId` for the persisted search along with ranked matches, each carrying a relevance score and the source document's metadata. Past searches can be retrieved via `GET /search`. operationId: search security: - bearerAuth: [] - oauth2: - semantic:write requestBody: required: true description: Request payload content: application/json: schema: $ref: '#/components/schemas/SemanticSearchRequest' examples: simple: summary: Basic search value: query: company vacation policy limit: 10 responses: '200': description: Search ID plus retrieval payload (`searchResponse`) from the AI search service content: application/json: schema: $ref: '#/components/schemas/SemanticSearchExecuteResponse' '400': description: | Invalid request — `query` is missing, empty, or the request body fails validation. '401': description: | Missing or invalid bearer token. '403': description: | Bearer token lacks the `semantic:write` scope. '404': description: | A referenced knowledge base or app filter could not be resolved. '500': description: | Unexpected server error while executing the search, or the upstream AI search service was unreachable. '502': description: | The upstream AI search service returned an invalid response. '503': description: | The upstream AI search service is temporarily unavailable. '504': description: | The upstream AI search service timed out before returning a response. get: tags: - Semantic Search summary: Get search history description: | Retrieve the authenticated user's persisted search history. Returns searches the user owns along with searches shared with them, scoped to the caller's organization. Archived and deleted entries are excluded. Citation references on this endpoint are returned as raw identifier strings; use `GET /search/{searchId}` to fetch a single search with its citations fully expanded. Pagination defaults to `page=1, limit=20` (maximum `limit` is 100). Results are sorted by most recent activity by default. operationId: searchHistory security: - bearerAuth: [] - oauth2: - semantic:read parameters: - name: page in: query description: Page number to return. Must be within `[1, 1000]`. schema: type: integer minimum: 1 maximum: 1000 default: 1 - name: limit in: query description: Number of items per page. Values are clamped to the range `[1, 100]`. schema: type: integer minimum: 1 maximum: 100 default: 20 - name: sortBy in: query description: | Field used to sort results. Any value other than `createdAt`, `lastActivityAt`, or `title` is treated as `lastActivityAt`. schema: type: string enum: - createdAt - lastActivityAt - title default: lastActivityAt - name: sortOrder in: query description: Sort direction applied to `sortBy`. schema: type: string enum: - asc - desc default: desc - name: search in: query description: | Case-insensitive substring to match against a search's title and message content. Regex metacharacters are escaped automatically. Values longer than 1000 characters are rejected with `400`. schema: type: string - name: shared in: query description: | Filter results by their shared status. Accepted values are `'true'` / `'1'` (return only shared searches) and `'false'` / `'0'` (exclude shared searches). Matching is case-insensitive and surrounding whitespace is trimmed. schema: type: string enum: - 'true' - 'false' - '1' - '0' - name: startDate in: query description: ISO 8601 timestamp used as the lower bound for a search's creation date. schema: type: string format: date-time - name: endDate in: query description: ISO 8601 timestamp used as the upper bound for a search's creation date. schema: type: string format: date-time responses: '200': description: | Persisted search history plus pagination, applied/available filter metadata, and a request-scoped `meta` block. content: application/json: schema: $ref: '#/components/schemas/SemanticSearchHistoryResponse' '400': description: | Invalid request, raised when a query parameter fails validation — for example a malformed `startDate` / `endDate`, a `search` value over 1000 characters, or a query value that trips the XSS guard. content: application/json: schema: type: object additionalProperties: false description: Error envelope for a failed request. properties: error: type: object additionalProperties: false description: Error payload. properties: code: type: string description: | Machine-readable error code. For this status the value is either `VALIDATION_ERROR` (request failed schema validation) or `HTTP_BAD_REQUEST` (semantic validation failed — malformed date, value over the allowed length, or XSS-guard trip). message: type: string description: Human-readable description of the failure. required: - code - message required: - error '401': description: | Missing or invalid bearer token. content: application/json: schema: type: object additionalProperties: false description: Error envelope for a failed request. properties: error: type: object additionalProperties: false description: Error payload. properties: code: type: string description: | Machine-readable error code. For this status the value is `HTTP_UNAUTHORIZED` (missing, invalid, or expired bearer token, user no longer exists, or the session has been invalidated). message: type: string description: Human-readable description of the failure. required: - code - message required: - error '403': description: | Bearer token lacks the `semantic:read` scope. content: application/json: schema: type: object additionalProperties: false description: Error envelope for a failed request. properties: error: type: object additionalProperties: false description: Error payload. properties: code: type: string description: | Machine-readable error code. For this status the value is `HTTP_FORBIDDEN` (the token is valid but does not carry the `semantic:read` scope). message: type: string description: Human-readable description of the failure. required: - code - message required: - error '500': description: | Server error. Possible causes: - Explicit `InternalServerError` or any other 500 `BaseError` thrown by the handler. - Non-`BaseError` exception caught by the global error middleware. - Response serializer fallback. content: application/json: schema: type: object additionalProperties: false description: Error envelope for a failed request. properties: error: type: object additionalProperties: false description: Error payload. properties: code: type: string description: | Machine-readable error code. For this status the value is `HTTP_INTERNAL_SERVER_ERROR` for an explicit server-side failure, or `INTERNAL_ERROR` for an unhandled exception coerced by the global error middleware. message: type: string description: Human-readable description of the failure. required: - code - message required: - error delete: tags: - Semantic Search summary: Clear all search history description: | Permanently delete every persisted search row owned by, or shared with, the authenticated user, along with the citation rows those searches reference. The action cannot be undone. Scoped to the caller's org and limited to rows where `isDeleted: false` and `isArchived: false`. If nothing matches (including the case where every row is already archived), the endpoint returns `404` rather than a successful no-op. operationId: deleteSearchHistory security: - bearerAuth: [] - oauth2: - semantic:delete parameters: - name: search in: query description: | Restrict the deletion to rows whose `title` or `messages.content` matches this case-insensitive substring. Special regex characters are escaped before the lookup; values over 1000 chars are rejected with `400`. schema: type: string - name: shared in: query description: | Restrict the deletion to rows with this `isShared` value (`'true'` / `'false'`). schema: type: string enum: - 'true' - 'false' - name: startDate in: query description: | ISO 8601 lower bound for `createdAt`. Combined with `endDate` to scope which rows are deleted. schema: type: string format: date-time - name: endDate in: query description: ISO 8601 upper bound for `createdAt`. schema: type: string format: date-time responses: '200': description: Search history deleted successfully. content: application/json: schema: type: object additionalProperties: false required: - message properties: message: type: string '400': description: | Invalid request, raised from the shared filter helper when a query parameter fails validation — for example a malformed `startDate` / `endDate`, a `search` value over 1000 characters, or a `search` value that trips the XSS guard. '401': description: | Missing or invalid bearer token. '403': description: | Bearer token lacks the `semantic:delete` scope. '404': description: | No matching rows. Returned when the caller has no owned or shared searches that satisfy the filter. '500': description: | Server error. Possible causes: - Explicit `InternalServerError` or any other 500 `BaseError` thrown by the handler. - Non-`BaseError` exception caught by the global error middleware. - Response serializer fallback. /search/{searchId}: get: tags: - Semantic Search summary: Get search by ID description: | Retrieve a previously persisted search by its id, scoped to the caller's org. The response body is always an **array** containing zero or one persisted search document. An unknown id returns an empty array with a `200` status — callers should check array length rather than relying on a `404`. operationId: getSearchById security: - bearerAuth: [] - oauth2: - semantic:read parameters: - name: searchId in: path required: true description: Unique search identifier schema: type: string format: objectId responses: '200': description: Array containing zero or one persisted search document. content: application/json: schema: $ref: '#/components/schemas/PersistedSemanticSearchEnvelope' '400': description: | Invalid request — `searchId` failed Zod validation (not a valid ObjectId). content: application/json: schema: type: object additionalProperties: false required: - error properties: error: type: object additionalProperties: false required: - code - message properties: code: type: string enum: - VALIDATION_ERROR description: | Machine-readable error code. `VALIDATION_ERROR` is emitted when the request fails Zod validation. message: type: string description: Human-readable description of the failure. '401': description: | Missing or invalid bearer token. content: application/json: schema: type: object additionalProperties: false required: - error properties: error: type: object additionalProperties: false required: - code - message properties: code: type: string enum: - HTTP_UNAUTHORIZED description: | Machine-readable error code. `HTTP_UNAUTHORIZED` is emitted when the bearer token is missing, invalid, or expired. message: type: string description: Human-readable description of the failure. '403': description: | Bearer token lacks the `semantic:read` scope. content: application/json: schema: type: object additionalProperties: false required: - error properties: error: type: object additionalProperties: false required: - code - message properties: code: type: string enum: - HTTP_FORBIDDEN description: | Machine-readable error code. `HTTP_FORBIDDEN` is emitted when the bearer token is valid but lacks the required scope. message: type: string description: Human-readable description of the failure. '404': description: | Reserved for parity with sibling routes; this endpoint currently returns `200` with an empty array for an unknown id rather than emitting `404`. content: application/json: schema: type: object additionalProperties: false required: - error properties: error: type: object additionalProperties: false required: - code - message properties: code: type: string enum: - HTTP_NOT_FOUND description: | Machine-readable error code. `HTTP_NOT_FOUND` is emitted when the addressed resource does not exist. message: type: string description: Human-readable description of the failure. '500': description: | Server error. Possible causes: - Explicit `InternalServerError` or any other 500 `BaseError` thrown by the handler. - Non-`BaseError` exception caught by the global error middleware. - Response serializer fallback. content: application/json: schema: type: object additionalProperties: false required: - error properties: error: type: object additionalProperties: false required: - code - message properties: code: type: string enum: - HTTP_INTERNAL_SERVER_ERROR - INTERNAL_ERROR - MIDDLEWARE_ERROR description: | Machine-readable error code. - `HTTP_INTERNAL_SERVER_ERROR` — explicit `InternalServerError` raised by the handler. - `INTERNAL_ERROR` — unhandled exception caught by the global error middleware. - `MIDDLEWARE_ERROR` — the error middleware itself failed while serializing the response. message: type: string description: Human-readable description of the failure. delete: tags: - Semantic Search summary: Delete search by ID description: | Permanently delete a single persisted search row, plus every citation row referenced by its `citationIds`. The caller must either own the row or have it shared with them. Scoped to the caller's org and limited to rows where `isDeleted: false` and `isArchived: false`; archived or already-deleted rows surface as `404`. operationId: deleteSearchById security: - bearerAuth: [] - oauth2: - semantic:delete parameters: - name: searchId in: path required: true description: ObjectId of the persisted search row to delete. schema: type: string format: objectId - name: search in: query description: | Additional substring filter against `title` / `messages.content`. The row is only deleted if the `searchId` row also matches this filter; otherwise `404`. Special regex characters are escaped; values over 1000 chars or tripping the XSS guard yield `400`. schema: type: string - name: shared in: query description: | Additional `isShared` filter (`'true'` / `'false'`). The row is only deleted if it also matches this value. schema: type: string enum: - 'true' - 'false' - name: startDate in: query description: | ISO 8601 lower bound for `createdAt`. The row is only deleted if its `createdAt` is on or after this value. schema: type: string format: date-time - name: endDate in: query description: | ISO 8601 upper bound for `createdAt`. The row is only deleted if its `createdAt` is on or before this value. schema: type: string format: date-time responses: '200': description: Search deleted successfully. content: application/json: schema: type: object additionalProperties: false required: - message properties: message: type: string '400': description: | Invalid request. Possible causes: - `searchId` failed Zod validation (not a valid ObjectId). - A query parameter passed through to the shared filter helper failed validation, e.g. a malformed `startDate` / `endDate`, or a `search` value over 1000 characters or tripping the XSS guard. '401': description: | Missing or invalid bearer token. '403': description: | Bearer token lacks the `semantic:delete` scope. '404': description: | No search matched. Returned when the id does not exist for this caller, or when the row is archived or already deleted. '500': description: | Server error. Possible causes: - Explicit `InternalServerError` or any other 500 `BaseError` thrown by the handler. - Non-`BaseError` exception caught by the global error middleware. - Response serializer fallback. /search/{searchId}/archive: patch: tags: - Semantic Search summary: Archive a search description: | Archive a specific search result. Archived searches are hidden from the default search history view but remain retrievable via the archive-aware listing endpoints. operationId: archiveSearch security: - bearerAuth: [] - oauth2: - semantic:write parameters: - name: searchId in: path required: true description: Unique search identifier schema: type: string format: objectId responses: '200': description: Search archived successfully content: application/json: schema: type: object additionalProperties: false required: - id - status - archivedBy - archivedAt - meta properties: id: type: string format: objectId description: Unique identifier of the archived search. example: 65f1c0a4e2b9c4d8f3a1b2c3 status: type: string enum: - archived description: Resulting status of the search after the operation. example: archived archivedBy: type: string format: objectId description: User ID of the user who archived the search. example: 65f1c0a4e2b9c4d8f3a1b2c4 archivedAt: type: string format: date-time description: Timestamp when the search was archived. example: '2026-05-10T12:34:56.789Z' meta: type: object additionalProperties: false required: - timestamp - duration properties: requestId: type: string description: Server-assigned request identifier for tracing. Omitted when not available. example: req_8f3a1b2c timestamp: type: string format: date-time description: Server timestamp when the response was produced. example: '2026-05-10T12:34:56.789Z' duration: type: integer description: Time taken to process the request, in milliseconds. example: 42 '400': description: | Invalid request. Possible causes: - `searchId` failed Zod validation (not a valid ObjectId). - The target search is already archived. '401': description: | Missing or invalid bearer token. '403': description: | Bearer token lacks the `semantic:write` scope. '404': description: | Search not found, or not owned by the caller's org. '500': description: | Persistence layer failed to update the search document. /search/{searchId}/unarchive: patch: tags: - Semantic Search summary: Unarchive a search description: | Restore a previously archived search result back to the active search history. operationId: unarchiveSearch security: - bearerAuth: [] - oauth2: - semantic:write parameters: - name: searchId in: path required: true description: Unique search identifier schema: type: string format: objectId responses: '200': description: Search unarchived successfully content: application/json: schema: type: object additionalProperties: false required: - id - status - unarchivedBy - unarchivedAt - meta properties: id: type: string format: objectId description: Unique identifier of the unarchived search. example: 65f1c0a4e2b9c4d8f3a1b2c3 status: type: string enum: - unarchived description: Resulting status of the search after the operation. example: unarchived unarchivedBy: type: string format: objectId description: User ID of the user who unarchived the search. example: 65f1c0a4e2b9c4d8f3a1b2c4 unarchivedAt: type: string format: date-time description: Timestamp when the search was unarchived. example: '2026-05-10T12:34:56.789Z' meta: type: object additionalProperties: false required: - timestamp - duration properties: requestId: type: string description: Server-assigned request identifier for tracing. Omitted when not available. example: req_8f3a1b2c timestamp: type: string format: date-time description: Server timestamp when the response was produced. example: '2026-05-10T12:34:56.789Z' duration: type: integer description: Time taken to process the request, in milliseconds. example: 42 '400': description: | Invalid request. Possible causes: - `searchId` failed Zod validation (not a valid ObjectId). - The target search is not currently archived and therefore cannot be unarchived. '401': description: | Missing or invalid bearer token. '403': description: | Bearer token lacks the `semantic:write` scope. '404': description: | No archived search matches `searchId` within the caller's org, or the row is already active / deleted. '500': description: | Unexpected server error while unarchiving the search. /agents: get: tags: - Agents summary: List agents description: | Retrieve a paginated list of agents available to the authenticated user. **Overview** Returns agents accessible through direct, team, or org-level permissions. Search is performed across agent name, description, and tags. Sorting and pagination are applied by the AI backend and the resulting envelope is forwarded unchanged by the Node gateway. **Gateway contract** The Node route supports only these query params: `page`, `limit`, `search`, `sort_by`, and `sort_order`. The Python backend also understands `isDeleted`, but this gateway route does not forward it, so it is not part of the public API contract here. operationId: listAgents security: - bearerAuth: [] - oauth2: - agent:read parameters: - in: query name: page required: false schema: type: integer minimum: 1 default: 1 description: 1-based page number. - in: query name: limit required: false schema: type: integer minimum: 1 maximum: 200 default: 20 description: Maximum number of agents to return in the current page. - in: query name: search required: false schema: type: string minLength: 1 maxLength: 1000 description: Case-insensitive search across agent name, description, and tags. Leading/trailing whitespace is trimmed; blank-after-trim values are rejected. - in: query name: sort_by required: false schema: type: string minLength: 1 maxLength: 100 default: updatedAtTimestamp description: Backend sort field. Leading/trailing whitespace is trimmed. Common value is `updatedAtTimestamp`. - in: query name: sort_order required: false schema: type: string enum: - asc - desc default: desc description: Sort direction. responses: '200': description: Paginated list of accessible agents. content: application/json: schema: $ref: '#/components/schemas/AgentListResponse' examples: success: summary: Example paginated response value: success: true agents: - _id: agentInstances/11111111-2222-3333-4444-555555555555 _key: 11111111-2222-3333-4444-555555555555 _rev: _exampleRev--- createdAtTimestamp: 1779792574728 createdBy: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee description: AI agent for customer support workflows isActive: true isDeleted: false isServiceAccount: false models: - 99999999-8888-7777-6666-555555555555_gpt-5.4-mini name: Customer Support Agent startMessage: Hello! How can I help you today? systemPrompt: You are a helpful assistant. tags: [] updatedAtTimestamp: 1779792574728 shareWithOrg: false toolsets: [] knowledge: [] can_view: true can_share: true can_edit: true can_delete: true user_role: OWNER access_type: INDIVIDUAL pagination: currentPage: 1 limit: 20 totalItems: 2 totalPages: 1 hasNext: false hasPrev: false '400': description: Validation failed for one or more query params. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /agents/create: post: tags: - Agents summary: Create agent description: | Create a new custom AI agent. **Overview:** Agents are specialized AI assistants configured for specific tasks. They can have custom system prompts, access to specific tools, and be limited to certain knowledge bases. **Agent Configuration:** - **System prompt:** Instructions that define agent behavior - **Tools:** Capabilities like web search, code execution, etc. - **Knowledge bases:** Data sources the agent can access - **Model config:** AI model settings (temperature, max tokens) **Use Cases:** - Customer support bot with product knowledge - Code review assistant with repository access - HR assistant with policy documents operationId: createAgent security: - bearerAuth: [] - oauth2: - agent:write requestBody: required: true description: Request payload content: application/json: schema: $ref: '#/components/schemas/AgentCreateRequest' responses: '201': description: Agent created content: application/json: schema: $ref: '#/components/schemas/AgentCreateResponse' '400': description: Invalid agent configuration '401': description: Unauthorized /agents/{agentKey}: get: tags: - Agents summary: Get agent description: | Retrieve agent details by its unique key. **Gateway not-found behavior:** Unknown `agentKey`, lookup after soft-delete, and other AI-backend failures that return 404 from the Python query service are surfaced by the Node gateway as **HTTP 404** with an `ErrorResponse` body. operationId: getAgent security: - bearerAuth: [] - oauth2: - agent:read parameters: - name: agentKey in: path required: true description: Unique agent identifier schema: type: string minLength: 1 example: customer-support-agent responses: '200': description: Agent details content: application/json: schema: $ref: '#/components/schemas/GetAgentResponse' '401': description: Missing or invalid bearer token (e.g. `No token provided`) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: Forbidden — insufficient OAuth scope (`agent:read` required) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '400': description: | Gateway validation failure (non-empty `agentKey` path param) or missing organization/user context on the authenticated request. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Agent not found, inaccessible, or previously deleted. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Unexpected AI-backend or gateway failure. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: AI query service unreachable content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' put: tags: - Agents summary: Update agent description: | Apply a partial update to an existing agent configuration. **Gateway contract** The Node gateway validates the request body via Zod middleware before forwarding to the Python agent service. The `agentKey` path param and the request body are both validated. Query parameters are ignored by the controller. **Update semantics** Only fields present in the request body are updated. When `models` is included, the gateway Zod middleware requires at least one model entry and at least one object entry with `isReasoning: true`. **Permissions** The authenticated user must have `can_edit` on the agent (typically the owner). Service-account and `shareWithOrg` transitions follow additional Python business rules. **Success response** Returns a lightweight success envelope only. Use `GET /agents/{agentKey}` to read the persisted agent after an update. operationId: updateAgent security: - bearerAuth: [] - oauth2: - agent:write parameters: - name: agentKey in: path required: true description: Unique agent identifier schema: type: string minLength: 1 example: customer-support-agent requestBody: required: true description: Partial agent configuration fields to update content: application/json: schema: $ref: '#/components/schemas/AgentUpdateRequest' responses: '200': description: Agent updated successfully content: application/json: schema: $ref: '#/components/schemas/AgentUpdateResponse' '401': description: Missing or invalid authentication content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: Forbidden — insufficient OAuth scope (`agent:write` required) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '400': description: | Gateway validation failure. Returned for missing/invalid `agentKey`, empty `models` array, `models` without a reasoning entry, malformed JSON, and other Zod schema violations. Syntactically invalid JSON may also surface as `500` depending on the Express parser. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Agent not found or inaccessible. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Unexpected AI-backend or gateway failure. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' delete: tags: - Agents summary: Delete agent description: | Soft-delete an agent (tombstone) in the graph database. **Overview:** The Python query service marks the agent instance deleted inside a transaction. List and search endpoints exclude tombstoned agents. Toolsets, tools, and knowledge linked to the agent are not removed by this call. **Permissions:** Only the agent owner may delete (`can_delete` on the permission check). **Warning:** All conversations with this agent will become inaccessible. **Gateway not-found behavior:** Unknown `agentKey`, deleting an already-deleted agent, and `GET /agents/{agentKey}` after delete return **HTTP 404** with an `ErrorResponse` body. operationId: deleteAgent security: - bearerAuth: [] - oauth2: - agent:write parameters: - name: agentKey in: path required: true description: Unique agent identifier (gateway Zod requires non-empty string). schema: type: string minLength: 1 example: customer-support-agent responses: '200': description: Agent soft-deleted successfully content: application/json: schema: $ref: '#/components/schemas/AgentDeleteResponse' '401': description: Missing or invalid bearer token (e.g. `No token provided`) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Agent not found, inaccessible, or already deleted. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Unexpected AI-backend or gateway failure. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /agents/conversations/show/archives: get: tags: - Agents summary: List archived agent conversations grouped by agent description: | Returns archived agent conversations for the current user, grouped by `agentKey`, with pagination over agent groups. Excludes conversations whose agent was soft-deleted upstream. operationId: listAgentArchivedConversationsGrouped security: - bearerAuth: [] - oauth2: - agent:read parameters: - name: agentPage in: query required: false schema: type: integer minimum: 1 default: 1 - name: agentLimit in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 5 responses: '200': description: Grouped archived conversations content: application/json: schema: $ref: '#/components/schemas/AgentArchivedGroupsResponse' '401': description: Unauthorized /agents/{agentKey}/conversations/show/archives: get: tags: - Agents summary: List archived conversations for an agent description: Paginated list of archived conversations for the given agent key. operationId: listAgentConversationArchives security: - bearerAuth: [] - oauth2: - agent:read parameters: - name: agentKey in: path required: true schema: type: string - name: page in: query schema: type: integer minimum: 1 default: 1 - name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 20 - name: sortBy in: query schema: type: string enum: - createdAt - lastActivityAt - title - name: sortOrder in: query schema: type: string enum: - asc - desc - name: search in: query schema: type: string maxLength: 1000 - name: startDate in: query schema: type: string format: date-time - name: endDate in: query schema: type: string format: date-time responses: '200': description: Archived conversations for the agent content: application/json: schema: $ref: '#/components/schemas/AgentArchivedConversationListResponse' '400': description: Invalid query parameters (gateway validation) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized /agents/{agentKey}/conversations/attachments/upload: post: tags: - Agents summary: Upload agent chat attachments description: | Multipart upload of PDF, JPEG, or PNG files for agent chat. Same limits as assistant chat (`POST /conversations/attachments/upload`): up to 10 files, 5 MiB each. Proxies to the AI backend. Optional `conversationId` associates uploads with an existing agent thread. operationId: uploadAgentConversationChatAttachments security: - bearerAuth: [] - oauth2: - agent:execute parameters: - name: agentKey in: path required: true schema: type: string minLength: 1 requestBody: required: true description: Multipart form with attachment files and optional `conversationId`. content: multipart/form-data: schema: type: object required: - files properties: conversationId: type: string pattern: ^$|^[0-9a-fA-F]{24}$ description: | Optional existing agent conversation id. Empty string is treated as unset; any non-empty value must be a 24-character ObjectId. files: type: array minItems: 1 maxItems: 10 description: | One or more files; field name must be `files`. Accepted MIME types: `application/pdf`, `image/jpeg`, `image/jpg`, `image/png`. Max 5 MiB each. items: type: string format: binary x-speakeasy-name-override: File responses: '200': description: | Success. The gateway proxies the AI-backend JSON envelope after transforming the multipart upload into the backend attachment payload. content: application/json: schema: $ref: '#/components/schemas/ChatAttachmentUploadResponse' '400': description: | Invalid `conversationId`, no files, unsupported MIME type (not PDF/JPEG/PNG), or Multer rejection (e.g. file too large). '401': description: Unauthorized '403': description: Missing `agent:execute` scope '500': description: | Gateway fallback when the upstream call does not return a status (implementation default). /agents/{agentKey}/conversations/attachments/{recordId}: delete: tags: - Agents summary: Delete an agent chat attachment description: | Deletes a previously uploaded attachment by proxying `DELETE` to the query service (`/api/v1/chat/attachments/{recordId}`). The Node handler always ends the response **without a JSON body** on success (empty body); the **status code** is the upstream status, or **204** if none is returned. On validation failure in the gateway (invalid / blank path params), the response is **400** with a small JSON error object. Same fire-and-forget semantics as `DELETE /conversations/attachments/{recordId}` on the client. operationId: deleteAgentConversationChatAttachment security: - bearerAuth: [] - oauth2: - agent:execute parameters: - name: agentKey in: path required: true description: Agent key path parameter. Must be non-empty. schema: type: string minLength: 1 - name: recordId in: path required: true description: Attachment record id (from the upload response). Must be non-blank after trim. schema: type: string minLength: 1 responses: '204': description: Success with no content (typical when upstream returns 204). '400': description: Invalid or blank path params (`agentKey` or `recordId`). content: application/json: schema: type: object additionalProperties: false required: - error properties: error: type: string example: recordId is required '401': description: Unauthorized '403': description: Missing `agent:execute` scope default: description: | Other status codes are forwarded from the query service (e.g. 404) with an **empty** response body from this route. /agents/{agentKey}/conversations/stream: post: tags: - Agents summary: Create agent conversation with streaming response description: | Start a new conversation with the specified agent and stream the AI response as Server-Sent Events (SSE). The first user message is saved and forwarded to the upstream agent backend; subsequent tokens, tool calls, and lifecycle events are emitted on the open SSE connection. operationId: streamAgentConversation security: - bearerAuth: [] - oauth2: - agent:execute parameters: - name: agentKey in: path required: true description: Stable key identifying the agent that owns this conversation. schema: type: string minLength: 1 requestBody: required: true description: Initial turn payload for the new agent conversation stream. content: application/json: schema: $ref: '#/components/schemas/AgentStreamCreateConversationRequest' responses: '200': description: SSE stream (text/event-stream) content: text/event-stream: schema: $ref: '#/components/schemas/AgentStreamSSEEvent' '400': description: Invalid request body '401': description: Unauthorized /agents/{agentKey}/conversations/{conversationId}/messages/stream: post: tags: - Agents summary: Add message to agent conversation with streaming response description: | Append a user message to an existing agent conversation and stream the assistant reply over SSE. operationId: streamAgentConversationMessage security: - bearerAuth: [] - oauth2: - agent:execute parameters: - name: agentKey in: path required: true schema: type: string - name: conversationId in: path required: true schema: type: string format: objectId requestBody: required: true description: Follow-up message payload for the agent conversation stream. content: application/json: schema: $ref: '#/components/schemas/AgentAddMessageStreamRequest' responses: '200': description: SSE stream (text/event-stream) content: text/event-stream: schema: $ref: '#/components/schemas/AgentMessageStreamSSEEvent' '400': description: Invalid request body '401': description: Unauthorized '404': description: Conversation not found /agents/{agentKey}/conversations/{conversationId}/message/{messageId}/regenerate: post: tags: - Agents summary: Regenerate agent conversation message description: | Regenerate the AI response for a specific message in an agent conversation and stream the new answer over Server-Sent Events. **Constraints:** - Only the last message in the conversation can be regenerated. - The target message must be of type `bot_response`. **Request body:** All request-body fields are optional. When omitted, the server reuses the original model/context. The body supports: - `filters` - `chatMode` - `modelKey` - `modelName` - `modelFriendlyName` - `timezone` - `currentTime` - `tools` **Streaming behavior:** The response is delivered as `text/event-stream`. Stable events are `connected`, `complete`, and `error`. Additional agent/tool lifecycle events may be forwarded by the backend and should be treated as informational updates. Validation failures on params/body are returned as normal HTTP `400` responses before the stream starts. Valid-shape requests that fail conversation lookup or regenerate rules are reported as SSE `error` events after stream initialization. operationId: regenerateAgentConversationMessage security: - bearerAuth: [] - oauth2: - agent:execute parameters: - name: agentKey in: path required: true description: Stable key identifying the agent that owns this conversation. schema: type: string minLength: 1 - name: conversationId in: path required: true description: ID of the agent conversation containing the target message. schema: type: string format: objectId - name: messageId in: path required: true description: ID of the bot-response message to regenerate. schema: type: string format: objectId requestBody: required: false description: | Optional regeneration payload. All fields are optional and are validated against `RegenerateRequest`. content: application/json: schema: $ref: '#/components/schemas/RegenerateRequest' responses: '200': description: | SSE stream established. Stable event names: - `connected` — confirms the stream is open - `complete` — returns the updated conversation plus metadata - `error` — reports lookup failures, authorization failures on the conversation, or regenerate-rule failures after the stream has started Additional backend-defined agent/tool events may be emitted. Clients should ignore unknown event names. content: text/event-stream: schema: $ref: '#/components/schemas/AgentRegenerateSSEEvent' '400': description: | Validation failed for path parameters or request body. Common causes include invalid ObjectId formats, empty strings for fields that require content, malformed `filters`, invalid `tools` entries, or `currentTime` values that are not ISO 8601 datetimes with offset information. '401': description: Unauthorized /agents/{agentKey}/conversations/{conversationId}/message/{messageId}/feedback: post: tags: - Agents summary: Submit feedback for an agent message description: | Append structured feedback to a bot-response message in an agent conversation. Uses the same request body shape as `updateMessageFeedback` (helpfulness, categories, comments). Feedback can only be submitted on `bot_response` messages. operationId: updateAgentConversationMessageFeedback security: - bearerAuth: [] - oauth2: - agent:execute parameters: - name: agentKey in: path required: true description: Unique agent identifier (gateway Zod requires non-empty string). schema: type: string minLength: 1 - name: conversationId in: path required: true description: Unique conversation identifier. schema: type: string format: objectId - name: messageId in: path required: true description: Identifier of the bot-response message being rated. schema: type: string format: objectId requestBody: required: true description: Feedback payload for the agent message. content: application/json: schema: $ref: '#/components/schemas/MessageFeedbackSubmitRequest' responses: '200': description: Feedback stored content: application/json: schema: $ref: '#/components/schemas/MessageFeedbackUpdateResponse' '400': description: | Invalid request. Possible causes: - Feedback target is not a `bot_response` message. - A `categories` value is not in the allowed list. - `conversationId` or `messageId` is not a valid ObjectId. '401': description: Unauthorized '404': description: Conversation or message not found '500': description: Persistence layer failed to append the feedback entry. /agents/{agentKey}/conversations/{conversationId}/archive: post: tags: - Agents summary: Archive an agent conversation description: Marks the conversation as archived for the authenticated owner. operationId: archiveAgentConversation security: - bearerAuth: [] - oauth2: - agent:write parameters: - name: agentKey in: path required: true schema: type: string - name: conversationId in: path required: true schema: type: string format: objectId responses: '200': description: Conversation archived content: application/json: schema: $ref: '#/components/schemas/AgentConversationArchiveResponse' '400': description: | Invalid path input or the conversation is already archived. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Conversation not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /agents/{agentKey}/conversations/{conversationId}/unarchive: post: tags: - Agents summary: Unarchive an agent conversation description: Restores an archived agent conversation to the active list. operationId: unarchiveAgentConversation security: - bearerAuth: [] - oauth2: - agent:write parameters: - name: agentKey in: path required: true schema: type: string - name: conversationId in: path required: true schema: type: string format: objectId responses: '200': description: Conversation unarchived content: application/json: schema: $ref: '#/components/schemas/AgentConversationUnarchiveResponse' '400': description: | Invalid path input or the conversation is not currently archived. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Conversation not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /agents/{agentKey}/conversations/{conversationId}/title: patch: tags: - Agents summary: Update agent conversation title description: | Updates the display title for an agent conversation owned by the caller. The controller looks up the conversation by `_id`, `orgId`, `userId`, `agentKey`, and `isDeleted: false`. The request body uses the shared title validator (`1..200` chars), and the controller trims the incoming title before saving it. A whitespace-only title can therefore still return HTTP 400 even if the raw string is non-empty. operationId: updateAgentConversationTitle security: - bearerAuth: [] - oauth2: - agent:write parameters: - name: agentKey in: path required: true schema: type: string - name: conversationId in: path required: true schema: type: string format: objectId requestBody: required: true description: | New title for the agent conversation. The server trims the provided string before saving it. content: application/json: schema: $ref: '#/components/schemas/ConversationTitleUpdateRequest' responses: '200': description: Title updated successfully content: application/json: schema: $ref: '#/components/schemas/AgentConversationTitleUpdateResponse' '400': description: | Invalid path or body input. This includes Zod validation failures for malformed `conversationId` or invalid `title` payloads, plus controller-level bad requests such as titles that become empty after trimming. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: | Agent conversation not found for the authenticated user, organization, and agent scope, or the conversation is soft-deleted. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /agents/{agentKey}/conversations/{conversationId}: delete: tags: - Agents summary: Delete an agent conversation description: | Soft-deletes an agent conversation owned by the authenticated user. The controller scopes the lookup by `_id`, `orgId`, `userId`, and `agentKey`. If no matching writable conversation is found, the route is intentionally a no-op and still returns HTTP 200 with `conversation: null`. This makes the operation idempotent: - deleting a nonexistent conversation returns success with `null` - deleting through a different `agentKey` returns success with `null` - deleting an already deleted conversation returns success with `null` operationId: deleteAgentConversationById security: - bearerAuth: [] - oauth2: - agent:write parameters: - name: agentKey in: path required: true schema: type: string - name: conversationId in: path required: true schema: type: string format: objectId responses: '200': description: Conversation deleted or no-op delete completed successfully content: application/json: schema: $ref: '#/components/schemas/AgentConversationDeleteResponse' '400': description: Invalid path input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error while deleting the agent conversation content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' get: tags: - Agents summary: Get agent conversation by ID description: | Returns the conversation with paginated/sorted messages and filter metadata. **Message Pagination:** Messages are paginated newest-first: `page=1` returns the most recent batch. Increment `page` to load older batches (used by the infinite-scroll "load older messages" feature). - `page`: Page number (default: 1) - `limit`: Messages per page (default: 20, max: 100) operationId: getAgentConversationById security: - bearerAuth: [] - oauth2: - agent:read parameters: - name: agentKey in: path required: true schema: type: string - name: conversationId in: path required: true schema: type: string format: objectId - name: page in: query description: Page number for message pagination (1 = most recent batch) schema: type: integer minimum: 1 default: 1 - name: limit in: query description: Number of messages per page schema: type: integer minimum: 1 maximum: 100 default: 20 - name: sortBy in: query description: Field to sort messages by schema: type: string enum: - createdAt - messageType - content default: createdAt - name: sortOrder in: query description: Sort direction schema: type: string enum: - asc - desc default: desc - name: startDate in: query description: Filter messages created on or after this date schema: type: string format: date-time - name: endDate in: query description: Filter messages created on or before this date schema: type: string format: date-time - name: messageType in: query description: Filter messages by type schema: type: string enum: - user_query - bot_response - error - feedback - system responses: '200': description: Agent conversation detail content: application/json: schema: $ref: '#/components/schemas/AgentConversationDetailResponse' '401': description: Unauthorized '404': description: Conversation not found /agents/{agentKey}/conversations: get: tags: - Agents summary: List agent conversations description: | Paginated list of conversations for the agent (owned and shared-with-me), excluding archived threads. operationId: listAgentConversations security: - bearerAuth: [] - oauth2: - agent:read parameters: - name: agentKey in: path required: true description: Agent identifier used to scope the conversation list. schema: type: string - name: page in: query description: 1-based page number. Defaults to `1`. schema: type: integer minimum: 1 default: 1 - name: limit in: query description: Page size. Defaults to `20`; maximum `100`. schema: type: integer minimum: 1 maximum: 100 default: 20 - name: sortBy in: query description: | Preferred sort field. Supported values are `createdAt`, `lastActivityAt`, and `title`. The current gateway validator preserves legacy behavior: unsupported values are accepted but ignored, and the handler falls back to `lastActivityAt`. schema: type: string - name: sortOrder in: query description: | Preferred sort direction. Supported values are `asc` and `desc`. The current gateway validator preserves legacy behavior: unsupported values are accepted but ignored, and the handler falls back to descending order. schema: type: string - name: search in: query description: | Case-insensitive search term applied to conversation `title` and `messages.content`. Maximum length is 1000 characters. HTML/XSS payloads and format specifiers are rejected. schema: type: string maxLength: 1000 - name: startDate in: query description: | Inclusive lower bound on `createdAt`. The handler accepts any JavaScript-parseable date string; invalid values return HTTP 400. schema: type: string example: '2026-05-26T00:00:00.000Z' - name: endDate in: query description: | Inclusive upper bound on `createdAt`. The handler accepts any JavaScript-parseable date string; invalid values return HTTP 400. schema: type: string example: '2026-05-27T00:00:00.000Z' - name: status in: query description: | Optional status filter applied to the `sharedWithMeConversations` branch of the response. The main `conversations` list ignores this parameter. schema: type: string - name: isArchived in: query description: | Optional archived flag applied to the `sharedWithMeConversations` branch before the route-level non-archived guard is enforced. Accepted values are `true` and `false`. schema: type: string enum: - 'true' - 'false' responses: '200': description: Conversation list content: application/json: schema: $ref: '#/components/schemas/AgentConversationListResponse' '400': description: | Invalid path or query parameter. This includes Zod validation failures such as invalid pagination, invalid booleans, malformed date values, duplicate `search` parameters, or overlong / invalid `search` input. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /configurationManager/ai-models/available/{modelType}: get: tags: - AI Models Providers summary: Get available models by type description: | Returns a **flattened list** of individual AI models of the requested type, suitable for use in selection dropdowns and model-picker UIs. Each provider configuration entry may specify multiple comma-separated model names; this endpoint expands those into one object per model name so callers receive a flat, enumerable collection. **Flattening rules:** - Only the **first** model in a multi-model provider entry is marked `isDefault: true`; all subsequent models from the same entry get `false`. - `modelFriendlyName` is included **only** when the provider entry contains exactly one model name (not a comma-separated list). - When no providers of the requested type are configured the endpoint still returns HTTP **200** with an empty `models` array — this is **not** an error. **Access control:** requires a valid bearer token. For OAuth tokens the `config:read` scope must be present; regular JWT bearer tokens pass through without scope enforcement. operationId: getAvailableModelsByType security: - bearerAuth: [] - oauth2: - config:read parameters: - name: modelType in: path required: true description: | Category of AI model to retrieve. Must be one of: `llm`, `embedding`, `ocr`, `slm`, `reasoning`, `multiModal`, `imageGeneration`, `tts`, `stt`. schema: $ref: '#/components/schemas/ModelType' responses: '200': description: | Available models retrieved successfully. An empty `models` array (with HTTP 200) is returned when no providers of the requested type have been configured — treat this as a valid, empty state, not an error. content: application/json: schema: type: object required: - status - models - message properties: status: type: string enum: - success example: success message: type: string description: |- Human-readable summary. Two formats are possible: - `"Found {n} {modelType} models"` — the `modelType` key exists in the stored config (returned even when `n` is 0, e.g. `"Found 0 ocr models"`). - `"No {modelType} models found"` — no AI config has been stored yet, or the `modelType` key is absent from the stored config entirely. example: Found 2 llm models models: type: array description: Flat list of individual model entries. Each entry represents one model name from one provider configuration. items: type: object required: - modelType - provider - modelName - modelKey - isMultimodal - isReasoning - isDefault properties: modelType: allOf: - $ref: '#/components/schemas/ModelType' description: Model category — always matches the `{modelType}` path parameter. provider: type: string description: Provider identifier as stored in configuration (e.g. `openAI`, `azureOpenAI`, `anthropic`, `gemini`, `ollama`). example: azureOpenAI modelName: type: string description: Specific model name/identifier forwarded to the provider API when making inference calls. example: gpt-5.4-mini modelKey: type: string format: uuid description: UUID that uniquely identifies the provider configuration entry this model was expanded from. Use this key when calling update/delete endpoints. example: f3a4b5b6-5b6c-4e85-9097-3202cfe696fc isMultimodal: type: boolean description: '`true` when this model accepts multi-modal inputs (text + images). Always present; defaults to `false` when not explicitly set.' example: true isReasoning: type: boolean description: '`true` when this is a reasoning / chain-of-thought model. Always present; defaults to `false` when not explicitly set.' example: true isDefault: type: boolean description: '`true` for the first model in the provider entry that was marked as default. At most one entry per `modelType` will have this set to `true`.' example: true modelFriendlyName: type: string description: Optional human-readable display name. Only present when the provider configuration entry contains exactly one model name (not a comma-separated list) **and** a friendly name was added during configuration. example: Reasoning model examples: two_llm_models: summary: Two LLM models from an Azure OpenAI provider value: status: success message: Found 2 llm models models: - modelType: llm provider: azureOpenAI modelName: gpt-5.4-mini modelKey: f3a4b5b6-5b6c-4e85-9097-3202cfe696fc isMultimodal: true isReasoning: true isDefault: true - modelType: llm provider: azureOpenAI modelName: gpt-5.4 modelKey: 7af8d3a7-ad2e-43a1-8716-ae95e4fbc888 isMultimodal: true isReasoning: true isDefault: false modelFriendlyName: Reasoning model no_models_configured: summary: modelType key present in config but zero models after expansion value: status: success message: Found 0 ocr models models: [] '400': description: | Invalid `modelType` path parameter. The `modelType` value was not one of the supported enum categories. This response is produced by the Zod validation middleware **before** the handler runs. The `error.metadata.errors` array contains per-field detail about exactly which constraint failed. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message - metadata properties: code: type: string enum: - VALIDATION_ERROR example: VALIDATION_ERROR message: type: string example: Validation failed metadata: type: object required: - errors description: Per-field validation detail from Zod. properties: errors: type: array items: type: object required: - field - message - code - value properties: field: type: string description: Dot-separated path to the failing field within the request (params, body, query). example: params.modelType message: type: string description: Human-readable Zod validation message. example: Invalid enum value. Expected 'ocr' | 'embedding' | 'llm' | 'slm' | 'reasoning' | 'multiModal' | 'imageGeneration' | 'tts' | 'stt', received 'llmr' code: type: string description: Machine-readable error code mapped from the Zod issue code. enum: - INVALID_TYPE - INVALID_LITERAL - INVALID_ENUM - INVALID_UNION - INVALID_DISCRIMINATOR - INVALID_ARGUMENTS - TOO_SMALL - TOO_BIG example: INVALID_ENUM value: type: string description: The rejected value stringified. May be an empty string when the value is not easily serialisable. example: '' example: error: code: VALIDATION_ERROR message: Validation failed metadata: errors: - field: params.modelType message: Invalid enum value. Expected 'ocr' | 'embedding' | 'llm' | 'slm' | 'reasoning' | 'multiModal' | 'imageGeneration' | 'tts' | 'stt', received 'llmr' code: INVALID_ENUM value: '' '401': description: | Missing or invalid authentication token. The bearer token was absent, expired, malformed, or could not be verified by the auth middleware. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_UNAUTHORIZED example: HTTP_UNAUTHORIZED message: type: string example: Invalid token example: error: code: HTTP_UNAUTHORIZED message: Invalid token '403': description: | Insufficient OAuth scope. Only applies to OAuth tokens. The token did not carry the `config:read` scope required by this endpoint. Regular (non-OAuth) JWT bearer tokens are not subject to scope enforcement and will not receive this error. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_FORBIDDEN example: HTTP_FORBIDDEN message: type: string example: 'Insufficient scope. Required: config:read' example: error: code: HTTP_FORBIDDEN message: 'Insufficient scope. Required: config:read' '500': description: An unexpected error occurred on the server. content: application/json: schema: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string enum: - HTTP_INTERNAL_SERVER_ERROR example: HTTP_INTERNAL_SERVER_ERROR message: type: string example: An unexpected error occurred example: error: code: HTTP_INTERNAL_SERVER_ERROR message: An unexpected error occurred /configurationManager/web-search: get: tags: - Web Search summary: Get all web search providers description: | Retrieve all configured web search providers and current web search settings. **Authentication:** Session JWT or OAuth 2.0 access token via `Authorization: Bearer`. OAuth tokens must include the `config:read` scope. Admin role is not required. operationId: getWebSearchProviders security: - bearerAuth: [] - oauth2: - config:read responses: '200': description: Web search providers and settings retrieved content: application/json: schema: $ref: '#/components/schemas/WebSearchProvidersResponse' '401': description: Missing or invalid Bearer token content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: Forbidden — OAuth token missing `config:read` scope content: application/json: schema: $ref: '#/components/schemas/ErrorResponse'