openapi: 3.1.0 info: title: AI Gateway Runtime API version: 0.10.0 description: Go rewrite contract. OpenAI-compatible payloads remain intentionally open. servers: - url: / paths: /healthz: get: operationId: getHealth responses: "200": description: Process is alive content: application/json: schema: $ref: "#/components/schemas/Health" /readyz: get: operationId: getReadiness responses: "200": description: Required dependencies are ready "503": description: A required dependency is unavailable /metrics: get: operationId: getMetrics responses: "200": { description: Prometheus text metrics for runtime, audit, bootstrap and shadow traffic } /api/v1/admin/login: post: operationId: loginAdmin requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/LoginRequest" } responses: "200": { description: Opaque Redis-backed session token } "401": { description: Invalid credentials } "429": { description: Account locked } /api/v1/admin/whoami: get: operationId: getAdminIdentity security: [{ bearerAuth: [] }] responses: "200": { description: Active administrator identity and role } "401": { description: Invalid or expired session } /api/v1/admin/password: post: operationId: changeAdminPassword security: [{ bearerAuth: [] }] responses: "200": { description: Administrator password changed after current-password verification } "401": { description: Current password invalid } /api/v1/admin/system-info: get: operationId: getSystemInfo security: [{ bearerAuth: [] }] responses: { "200": { description: Version, runtime, uptime and enabled resource counts } } /api/v1/admin/monitoring/overview: get: operationId: getMonitoringOverview security: [{ bearerAuth: [] }] responses: { "200": { description: PostgreSQL-backed 24-hour request, token, cost and latency summary } } /api/v1/admin/reload: post: operationId: reloadRuntimeSnapshots security: [{ bearerAuth: [] }] responses: { "200": { description: Provider, content-policy and pricing snapshots reloaded } } /api/v1/admin/fact-check/settings: get: operationId: getFactCheckSettings security: [{ bearerAuth: [] }] responses: { "200": { description: Fact-check Provider reference, model and timeout without duplicated credentials } } put: operationId: updateFactCheckSettings security: [{ bearerAuth: [] }] responses: { "200": { description: Fact-check settings updated } } /api/v1/admin/fact-check/policies: get: operationId: listFactCheckPolicies security: [{ bearerAuth: [] }] responses: { "200": { description: Scoped fact-check policies } } post: operationId: createFactCheckPolicy security: [{ bearerAuth: [] }] responses: { "200": { description: Validated fact-check policy created } } /api/v1/admin/fact-check/policies/{policy_id}: put: operationId: updateFactCheckPolicy security: [{ bearerAuth: [] }] parameters: [{ name: policy_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Fact-check policy revision updated } } delete: operationId: deleteFactCheckPolicy security: [{ bearerAuth: [] }] parameters: [{ name: policy_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Fact-check policy deleted } } /api/v1/admin/fact-check/events: get: operationId: listFactCheckEvents security: [{ bearerAuth: [] }] responses: { "200": { description: Bounded fact-check event summaries } } /api/v1/admin/fact-check/events/{event_id}: get: operationId: getFactCheckEvent security: [{ bearerAuth: [] }] parameters: [{ name: event_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Fact-check claims and evidence detail } } /api/v1/admin/login/totp: post: operationId: completeAdminTOTPLogin requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/TOTPLoginRequest" } responses: "200": { description: TOTP challenge completed and session issued } "401": { description: Invalid, reused, or consumed factor } /api/v1/admin/totp/status: get: operationId: getAdminTOTPStatus security: [{ bearerAuth: [] }] responses: "200": { description: TOTP enrollment status } /api/v1/admin/totp/setup: post: operationId: setupAdminTOTP security: [{ bearerAuth: [] }] responses: "200": { description: New secret and otpauth provisioning URI } /api/v1/admin/totp/confirm: post: operationId: confirmAdminTOTP security: [{ bearerAuth: [] }] responses: "200": { description: Enrollment confirmed; backup codes returned once } /api/v1/admin/totp/disable: post: operationId: disableAdminTOTP security: [{ bearerAuth: [] }] responses: "200": { description: TOTP disabled after password and factor verification } /api/v1/admin/totp/backup-codes/regenerate: post: operationId: regenerateAdminTOTPBackupCodes security: [{ bearerAuth: [] }] responses: "200": { description: Previous backup codes revoked and replacements returned once } /api/v1/admin/logout: post: operationId: logoutAdmin security: [{ bearerAuth: [] }] responses: "200": { description: Session revoked } /api/v1/admin/menus: get: operationId: getAdminMenus security: [{ bearerAuth: [] }] responses: "200": { description: Art Design Pro route tree for the active role } /api/v1/admin/identities/admins: get: operationId: listAdministrators security: [{ bearerAuth: [] }] responses: "200": { description: Administrator accounts with direct and effective permissions } "403": { description: identity:manage permission required } post: operationId: createAdministrator security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/IdentityInput" } responses: "200": { description: Administrator created and outbox event committed } "409": { description: Login already exists } /api/v1/admin/identities/admins/{identity_id}: put: operationId: updateAdministrator security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/IdentityID" requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/IdentityInput" } responses: "200": { description: Account and permissions updated immediately } "409": { description: Self-disable, self-role change, or duplicate login } /api/v1/admin/identities/portal-users: get: operationId: listPortalUsers security: [{ bearerAuth: [] }] responses: "200": { description: Portal accounts with direct and effective permissions } post: operationId: createPortalUser security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/IdentityInput" } responses: "200": { description: Local portal account created } /api/v1/admin/identities/portal-users/{identity_id}: put: operationId: updatePortalUser security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/IdentityID" requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/IdentityInput" } responses: "200": { description: Portal account updated } /api/v1/admin/departments: get: operationId: listDepartments security: [{ bearerAuth: [] }] responses: "200": { description: Flat department catalog with parent names and active user counts } post: operationId: createDepartment security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/DepartmentInput" } responses: "200": { description: Department created with outbox event } "409": { description: Duplicate code or invalid hierarchy } /api/v1/admin/departments/{department_id}: put: operationId: updateDepartment security: [{ bearerAuth: [] }] parameters: - name: department_id in: path required: true schema: { type: string, format: uuid } requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/DepartmentInput" } responses: "200": { description: Department updated with hierarchy validation } "409": { description: Cycle or active users/children prevent the update } /api/v1/admin/identity-providers: get: operationId: listIdentityProviders security: [{ bearerAuth: [] }] responses: "200": { description: OIDC providers without client secret material } post: operationId: createIdentityProvider security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/OIDCProviderInput" } responses: "200": { description: Encrypted OIDC provider configuration created } /api/v1/admin/identity-providers/{provider_id}: put: operationId: updateIdentityProvider security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/ProviderID" requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/OIDCProviderInput" } responses: "200": { description: OIDC provider updated; omitted secret remains unchanged } /api/v1/admin/saml-providers: get: operationId: listSAMLProviders security: [{ bearerAuth: [] }] responses: "200": { description: SAML identity provider configurations } post: operationId: createSAMLProvider security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/SAMLProviderInput" } responses: "200": { description: SAML provider created after metadata and signing certificate validation } /api/v1/admin/saml-providers/{provider_id}: put: operationId: updateSAMLProvider security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/ProviderID" requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/SAMLProviderInput" } responses: "200": { description: SAML provider updated and revision incremented } /api/v1/admin/providers: get: operationId: listProviders security: [{ bearerAuth: [] }] responses: "200": { description: Providers with masked credentials } post: operationId: createProvider security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ProviderInput" } responses: "200": { description: Provider created and outbox event committed } "403": { description: Superadmin role required } /api/v1/admin/api-keys: get: operationId: listAPIKeys security: [{ bearerAuth: [] }] responses: "200": { description: API keys without secret material } "403": { description: Superadmin role required } post: operationId: createAPIKey security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/APIKeyInput" } responses: "200": { description: API key secret returned exactly once } /api/v1/admin/api-keys/{api_key_id}: delete: operationId: revokeAPIKey security: [{ bearerAuth: [] }] parameters: - name: api_key_id in: path required: true schema: { type: string, format: uuid } responses: "200": { description: Key revoked and shared cache invalidated } "404": { description: Key not found or already revoked } /api/v1/admin/api-keys/{api_key_id}/limits: put: operationId: updateAPIKeyLimits security: [{ bearerAuth: [] }] parameters: - name: api_key_id in: path required: true schema: { type: string, format: uuid } requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/APIKeyLimitsInput" } responses: "200": { description: Request and token limits updated; authentication cache invalidated } "404": { description: Key not found or already revoked } /api/v1/admin/model-routes: get: operationId: listModelRoutes security: [{ bearerAuth: [] }] responses: "200": { description: Model alias and weighted route rules } post: operationId: createModelRoute security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ModelRouteInput" } responses: "200": { description: Route committed, snapshot refreshed, and peers notified } "409": { description: Duplicate route } /api/v1/admin/model-routes/{model_route_id}: put: operationId: updateModelRoute security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/ModelRouteID" requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ModelRouteInput" } responses: "200": { description: Route updated and active snapshots refreshed } "404": { description: Route not found } delete: operationId: deleteModelRoute security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/ModelRouteID" responses: "200": { description: Route deleted and active snapshots refreshed } "404": { description: Route not found } /api/v1/admin/audit-events: get: operationId: listAuditEvents security: [{ bearerAuth: [] }] parameters: - { name: from, in: query, schema: { type: string, format: date-time } } - { name: to, in: query, schema: { type: string, format: date-time } } - { name: before, in: query, schema: { type: string, format: date-time } } - { name: api_key_id, in: query, schema: { type: string, format: uuid } } - { name: provider, in: query, schema: { type: string } } - { name: model, in: query, schema: { type: string } } - { name: status, in: query, schema: { type: integer, minimum: 100, maximum: 599 } } - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 200, default: 50 } } responses: "200": { description: Cursor-paginated gateway audit events } "403": { description: audit:read permission required } /api/v1/admin/usage/daily: get: operationId: listDailyUsage security: [{ bearerAuth: [] }] parameters: - { name: from, in: query, schema: { type: string, format: date } } - { name: to, in: query, schema: { type: string, format: date } } - { name: api_key_id, in: query, schema: { type: string, format: uuid } } - { name: provider, in: query, schema: { type: string } } - { name: model, in: query, schema: { type: string } } responses: "200": { description: Daily request, failure, and token aggregates } "403": { description: usage:read permission required } /api/v1/admin/outbox-events: get: operationId: listOutboxEvents security: [{ bearerAuth: [] }] parameters: - { name: status, in: query, schema: { type: string, enum: [pending, dead, processed] } } - { name: type, in: query, schema: { type: string } } - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 500, default: 100 } } responses: "200": { description: Pending, dead-lettered, or processed transactional outbox events } "403": { description: outbox:read permission required } /api/v1/admin/outbox-events/{event_id}/retry: post: operationId: retryOutboxEvent security: [{ bearerAuth: [] }] parameters: - name: event_id in: path required: true schema: { type: string, format: uuid } responses: "200": { description: Pending or dead-lettered event made immediately claimable } "403": { description: outbox:manage permission required } "404": { description: Unprocessed event not found } /api/v1/admin/content-policies: get: operationId: listContentPolicies security: [{ bearerAuth: [] }] responses: "200": { description: Ordered content policy definitions } "403": { description: content_policy:read permission required } post: operationId: createContentPolicy security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ContentPolicyInput" } responses: "200": { description: Policy committed, compiled, and activated locally } "400": { description: Invalid RE2 rule or policy scope } /api/v1/admin/content-policies/{policy_id}: put: operationId: updateContentPolicy security: [{ bearerAuth: [] }] parameters: [{ name: policy_id, in: path, required: true, schema: { type: string, format: uuid } }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ContentPolicyInput" } responses: "200": { description: Policy revision updated and snapshot reloaded } "404": { description: Policy not found } delete: operationId: deleteContentPolicy security: [{ bearerAuth: [] }] parameters: [{ name: policy_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: "200": { description: Policy deleted and snapshot reloaded } /api/v1/admin/model-prices: get: operationId: listModelPrices security: [{ bearerAuth: [] }] responses: "200": { description: Versioned model price definitions } "403": { description: pricing:read permission required } post: operationId: createModelPrice security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ModelPriceInput" } responses: "200": { description: Price version created and runtime snapshot reloaded } /api/v1/admin/model-prices/{price_id}: put: operationId: updateModelPrice security: [{ bearerAuth: [] }] parameters: [{ name: price_id, in: path, required: true, schema: { type: string, format: uuid } }] requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ModelPriceInput" } responses: "200": { description: Price revision updated and runtime snapshot reloaded } delete: operationId: deleteModelPrice security: [{ bearerAuth: [] }] parameters: [{ name: price_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: "200": { description: Price version deleted } /api/v1/admin/prompts: get: operationId: listPrompts security: [{ bearerAuth: [] }] responses: { "200": { description: Prompt templates and active immutable versions } } post: operationId: createPrompt security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/PromptInput" } } } } responses: { "200": { description: Template and initial immutable version created } } /api/v1/admin/prompts/{prompt_id}: get: operationId: getPrompt security: [{ bearerAuth: [] }] parameters: [{ name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Prompt metadata and current immutable version } } put: operationId: updatePromptMetadata security: [{ bearerAuth: [] }] parameters: [{ name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/PromptInput" } } } } responses: { "200": { description: Prompt metadata updated without mutating version content } } delete: operationId: deletePrompt security: [{ bearerAuth: [] }] parameters: [{ name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Prompt and versions deleted } } /api/v1/admin/prompts/{prompt_id}/versions: get: operationId: listPromptVersions security: [{ bearerAuth: [] }] parameters: [{ name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Immutable Prompt version history } } post: operationId: createPromptVersion security: [{ bearerAuth: [] }] parameters: [{ name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: New immutable version created and optionally activated } } /api/v1/admin/prompts/{prompt_id}/versions/{version}/activate: post: operationId: activatePromptVersion security: [{ bearerAuth: [] }] parameters: - { name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } } - { name: version, in: path, required: true, schema: { type: integer, minimum: 1 } } responses: { "200": { description: Historical immutable version made current } } /api/v1/admin/prompts/{prompt_id}/render: post: operationId: previewPrompt security: [{ bearerAuth: [] }] parameters: [{ name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Current Prompt rendered for control-plane preview } } /api/v1/admin/prompt-categories: get: operationId: listPromptCategories security: [{ bearerAuth: [] }] responses: { "200": { description: Prompt categories with template counts } } post: operationId: createPromptCategory security: [{ bearerAuth: [] }] responses: { "200": { description: Prompt category created } } /api/v1/admin/prompt-categories/{category_id}: delete: operationId: deletePromptCategory security: [{ bearerAuth: [] }] parameters: [{ name: category_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Category removed and templates made uncategorized } } /api/v1/admin/knowledge-bases: get: operationId: listKnowledgeBases security: [{ bearerAuth: [] }] responses: { "200": { description: PostgreSQL-backed knowledge bases } } post: operationId: createKnowledgeBase security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/KnowledgeBaseInput" } } } } responses: { "200": { description: Knowledge base created } } /api/v1/admin/knowledge-bases/{knowledge_base_id}: put: operationId: updateKnowledgeBase security: [{ bearerAuth: [] }] parameters: [{ name: knowledge_base_id, in: path, required: true, schema: { type: string, format: uuid } }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/KnowledgeBaseInput" } } } } responses: { "200": { description: Knowledge base updated } } delete: operationId: deleteKnowledgeBase security: [{ bearerAuth: [] }] parameters: [{ name: knowledge_base_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Unreferenced knowledge base deleted } } /api/v1/admin/knowledge-bases/{knowledge_base_id}/documents: get: operationId: listKnowledgeDocuments security: [{ bearerAuth: [] }] parameters: [{ name: knowledge_base_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Bounded extracted-text documents } } post: operationId: addKnowledgeDocument security: [{ bearerAuth: [] }] parameters: [{ name: knowledge_base_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Document stored in PostgreSQL and synchronously chunked } } /api/v1/admin/knowledge-bases/{knowledge_base_id}/documents/{document_id}: delete: operationId: deleteKnowledgeDocument security: [{ bearerAuth: [] }] parameters: - { name: knowledge_base_id, in: path, required: true, schema: { type: string, format: uuid } } - { name: document_id, in: path, required: true, schema: { type: string, format: uuid } } responses: { "200": { description: Document and chunks deleted } } /api/v1/admin/knowledge-bases/{knowledge_base_id}/documents/{document_id}/reprocess: post: operationId: reprocessKnowledgeDocument security: [{ bearerAuth: [] }] parameters: - { name: knowledge_base_id, in: path, required: true, schema: { type: string, format: uuid } } - { name: document_id, in: path, required: true, schema: { type: string, format: uuid } } responses: { "200": { description: Stored bounded text re-chunked transactionally } } /api/v1/admin/knowledge-bases/{knowledge_base_id}/search: post: operationId: testKnowledgeSearch security: [{ bearerAuth: [] }] parameters: [{ name: knowledge_base_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Retriever test results } } /api/v1/admin/tools: get: operationId: listTools security: [{ bearerAuth: [] }] responses: { "200": { description: HTTP tool definitions without decrypted secret headers } } post: operationId: createTool security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/ToolInput" } } } } responses: { "200": { description: SSRF-validated tool with encrypted headers created } } /api/v1/admin/tools/{tool_id}: put: operationId: updateTool security: [{ bearerAuth: [] }] parameters: [{ name: tool_id, in: path, required: true, schema: { type: string, format: uuid } }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/ToolInput" } } } } responses: { "200": { description: Tool revision updated } } delete: operationId: deleteTool security: [{ bearerAuth: [] }] parameters: [{ name: tool_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Unreferenced tool deleted } } /api/v1/admin/tools/{tool_id}/test: post: operationId: testTool security: [{ bearerAuth: [] }] parameters: [{ name: tool_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Bounded SSRF-safe administrative tool test } } /api/v1/admin/applications: get: operationId: listApplications security: [{ bearerAuth: [] }] responses: { "200": { description: Application drafts and current published versions } } post: operationId: createApplication security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/ApplicationInput" } } } } responses: { "200": { description: Application draft created } } /api/v1/admin/applications/catalog: get: operationId: getApplicationCompositionCatalog security: [{ bearerAuth: [] }] responses: { "200": { description: Prompt, knowledge and tool assets available for composition } } /api/v1/admin/applications/asset-dependencies: get: operationId: getApplicationAssetDependencies security: [{ bearerAuth: [] }] parameters: - { name: asset_type, in: query, required: true, schema: { type: string, enum: [prompt, knowledge, tool] } } - { name: asset_id, in: query, required: true, schema: { type: string, format: uuid } } responses: { "200": { description: Draft and published application references to an asset } } /api/v1/admin/applications/{application_id}/publish: post: operationId: publishApplication security: [{ bearerAuth: [] }] parameters: [{ name: application_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Validated immutable application composition published } } /api/v1/admin/applications/{application_id}: get: operationId: getApplication security: [{ bearerAuth: [] }] parameters: [{ name: application_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Application composition and immutable version history } } put: operationId: updateApplication security: [{ bearerAuth: [] }] parameters: [{ name: application_id, in: path, required: true, schema: { type: string, format: uuid } }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/ApplicationInput" } } } } responses: { "200": { description: Application draft updated } } delete: operationId: deleteApplication security: [{ bearerAuth: [] }] parameters: [{ name: application_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Application and its versions deleted } } /api/v1/admin/applications/{application_id}/rollback/{version}: post: operationId: rollbackApplication security: [{ bearerAuth: [] }] parameters: - { name: application_id, in: path, required: true, schema: { type: string, format: uuid } } - { name: version, in: path, required: true, schema: { type: integer, minimum: 1 } } responses: { "200": { description: Historical composition copied into a new immutable published version } } /api/v1/admin/applications/{application_id}/versions: get: operationId: listApplicationVersions security: [{ bearerAuth: [] }] parameters: [{ name: application_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Immutable application publication history } } /api/v1/admin/applications/{application_id}/runs: get: operationId: listApplicationRuns security: [{ bearerAuth: [] }] parameters: [{ name: application_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Recent application orchestration runs } } /api/v1/admin/notification-channels: get: operationId: listNotificationChannels security: [{ bearerAuth: [] }] responses: { "200": { description: Webhook subscriptions without decrypted signing secrets } } post: operationId: createNotificationChannel security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/NotificationChannelInput" } } } } responses: { "200": { description: Signed Webhook subscription created } } /api/v1/admin/notification-deliveries: get: operationId: listNotificationDeliveries security: [{ bearerAuth: [] }] responses: { "200": { description: Durable Webhook delivery history } } /api/v1/admin/notification-channels/{channel_id}: put: operationId: updateNotificationChannel security: [{ bearerAuth: [] }] parameters: [{ name: channel_id, in: path, required: true, schema: { type: string, format: uuid } }] requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/NotificationChannelInput" } } } } responses: { "200": { description: Notification channel updated } } delete: operationId: deleteNotificationChannel security: [{ bearerAuth: [] }] parameters: [{ name: channel_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Notification channel and deliveries deleted } } /api/v1/admin/notification-deliveries/{delivery_id}/retry: post: operationId: retryNotificationDelivery security: [{ bearerAuth: [] }] parameters: [{ name: delivery_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Failed delivery attempted immediately } } /v1/prompts: get: operationId: listRuntimePrompts security: [{ apiKeyAuth: [] }] responses: { "200": { description: Visible enabled Prompt definitions without template bodies } } /v1/prompts/{prompt_name}/render: post: operationId: renderPrompt security: [{ apiKeyAuth: [] }] parameters: [{ name: prompt_name, in: path, required: true, schema: { type: string } }] responses: { "200": { description: Active template rendered after required-variable validation } } /v1/knowledge/{knowledge_base_id}/search: post: operationId: searchKnowledge security: [{ apiKeyAuth: [] }] parameters: [{ name: knowledge_base_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Department-scoped Retriever results } } /v1/knowledge/search: post: operationId: searchKnowledgeLegacyShape security: [{ apiKeyAuth: [] }] responses: { "200": { description: Knowledge search with knowledge_base_id in the JSON body } } /v1/tools: get: operationId: listRuntimeTools security: [{ apiKeyAuth: [] }] responses: { "200": { description: Department-scoped tool schemas without encrypted headers } } /v1/tools/{tool_code}/invoke: post: operationId: invokeTool security: [{ apiKeyAuth: [] }] parameters: [{ name: tool_code, in: path, required: true, schema: { type: string } }] responses: { "200": { description: Schema-validated, SSRF-safe bounded HTTP tool result } } /v1/applications/{application_code}/chat/completions: post: operationId: runApplication security: [{ apiKeyAuth: [] }] parameters: [{ name: application_code, in: path, required: true, schema: { type: string } }] responses: { "200": { description: Prompt, retrieval and bounded tool loop executed through the governed gateway } } /api/v1/admin/providers/{provider_id}: put: operationId: updateProvider security: [{ bearerAuth: [] }] parameters: - name: provider_id in: path required: true schema: { type: string, format: uuid } requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ProviderInput" } responses: "200": { description: Provider updated and revision incremented } "404": { description: Provider not found } /api/v1/admin/providers/{provider_id}/test: post: operationId: testProviderConnection security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/ProviderID" responses: "200": description: Bounded connectivity test against the upstream models endpoint content: application/json: schema: { $ref: "#/components/schemas/ProviderConnectionResult" } "404": { description: Provider not found } "502": { description: Upstream network request failed } /api/v1/admin/providers/{provider_id}/models: get: operationId: listProviderModels security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/ProviderID" responses: "200": description: Current and historical provider model catalog "404": { description: Provider not found } /api/v1/admin/providers/{provider_id}/models/sync: post: operationId: syncProviderModels security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/ProviderID" responses: "200": description: Model catalog transactionally synchronized and outbox event committed content: application/json: schema: { $ref: "#/components/schemas/ModelSyncResult" } "404": { description: Provider not found } "502": { description: Upstream response failed validation } /api/v1/admin/providers/credentials/rotate: post: operationId: rotateProviderCredentials description: Re-encrypt every Provider credential not already using the active KEK version. security: [{ bearerAuth: [] }] responses: "200": description: All required credential updates and outbox events committed atomically content: application/json: schema: { $ref: "#/components/schemas/CredentialRotationResult" } /api/v1/portal/login: post: operationId: loginPortal requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/LoginRequest" } responses: "200": { description: Opaque Redis-backed portal session token } "401": { description: Invalid credentials } /api/v1/portal/sso/providers: get: operationId: listPublicSSOProviders responses: "200": { description: Enabled OIDC and SAML providers safe for login-page display } /api/v1/portal/sso/{provider_code}/start: get: operationId: startSSOLogin parameters: - name: provider_code in: path required: true schema: { type: string } responses: "302": { description: Redirect to the OIDC authorization endpoint or SAML Redirect-binding SSO endpoint } /api/v1/portal/sso/{provider_code}/callback: get: operationId: completeOIDCLogin parameters: - name: provider_code in: path required: true schema: { type: string } responses: "302": { description: Verified identity redirects with a one-minute single-use exchange code } "401": { description: State or ID Token validation failed } post: operationId: completeSAMLLogin parameters: - name: provider_code in: path required: true schema: { type: string } requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: [SAMLResponse, RelayState] properties: SAMLResponse: { type: string, format: byte } RelayState: { type: string } responses: "302": { description: Signed assertion accepted and browser redirected with a single-use exchange code } "401": { description: Signature, request correlation, assertion, or replay validation failed } /api/v1/portal/sso/{provider_code}/metadata: get: operationId: getSAMLServiceProviderMetadata parameters: - name: provider_code in: path required: true schema: { type: string } responses: "200": { description: SAML Service Provider metadata XML } "404": { description: SAML provider not found } /api/v1/portal/sso/exchange: post: operationId: exchangeOIDCCode requestBody: required: true content: application/json: schema: type: object required: [code] properties: code: { type: string } responses: "200": { description: Redis-backed portal session token } "401": { description: Exchange code invalid, expired, or already consumed } /api/v1/portal/me: get: operationId: getPortalIdentity security: [{ bearerAuth: [] }] responses: "200": { description: Active portal identity } /api/v1/portal/login/totp: post: operationId: completePortalTOTPLogin requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/TOTPLoginRequest" } responses: "200": { description: TOTP challenge completed and session issued } "401": { description: Invalid, reused, or consumed factor } /api/v1/portal/totp/status: get: operationId: getPortalTOTPStatus security: [{ bearerAuth: [] }] responses: "200": { description: TOTP enrollment status } /api/v1/portal/totp/setup: post: operationId: setupPortalTOTP security: [{ bearerAuth: [] }] responses: "200": { description: New secret and otpauth provisioning URI } /api/v1/portal/totp/confirm: post: operationId: confirmPortalTOTP security: [{ bearerAuth: [] }] responses: "200": { description: Enrollment confirmed; backup codes returned once } /api/v1/portal/totp/disable: post: operationId: disablePortalTOTP security: [{ bearerAuth: [] }] responses: "200": { description: TOTP disabled after password and factor verification } /api/v1/portal/totp/backup-codes/regenerate: post: operationId: regeneratePortalTOTPBackupCodes security: [{ bearerAuth: [] }] responses: "200": { description: Previous backup codes revoked and replacements returned once } /api/v1/portal/logout: post: operationId: logoutPortal security: [{ bearerAuth: [] }] responses: "200": { description: Session revoked } /api/v1/portal/menus: get: operationId: getPortalMenus security: [{ bearerAuth: [] }] responses: "200": { description: Art Design Pro portal route tree } /api/v1/portal/password: post: operationId: changePortalPassword security: [{ bearerAuth: [] }] responses: { "200": { description: Local password changed after current-password verification } } /api/v1/portal/applications: get: operationId: listPortalApplications security: [{ bearerAuth: [] }] responses: { "200": { description: Published applications visible to the portal user's department } } /api/v1/portal/catalog: get: operationId: getPortalCatalog security: [{ bearerAuth: [] }] responses: { "200": { description: Department-scoped application and AI asset catalog } } /api/v1/portal/knowledge: get: operationId: listPortalKnowledge security: [{ bearerAuth: [] }] responses: { "200": { description: Enabled visible knowledge bases } } /api/v1/portal/tools: get: operationId: listPortalTools security: [{ bearerAuth: [] }] responses: { "200": { description: Enabled visible tool metadata without endpoint or secret headers } } /api/v1/portal/prompts: get: operationId: listPortalPrompts security: [{ bearerAuth: [] }] responses: { "200": { description: Enabled visible prompts with favorite state } } /api/v1/portal/prompts/{prompt_id}: get: operationId: getPortalPrompt security: [{ bearerAuth: [] }] parameters: [{ name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Visible prompt and current immutable content } } /api/v1/portal/prompts/{prompt_id}/favorite: post: operationId: favoritePortalPrompt security: [{ bearerAuth: [] }] parameters: [{ name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Prompt added to favorites idempotently } } delete: operationId: unfavoritePortalPrompt security: [{ bearerAuth: [] }] parameters: [{ name: prompt_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Prompt removed from favorites idempotently } } /api/v1/portal/model-requests/available: get: operationId: listPortalAvailableModels security: [{ bearerAuth: [] }] responses: { "200": { description: Enabled provider model catalog } } /api/v1/portal/model-requests: get: operationId: listPortalModelRequests security: [{ bearerAuth: [] }] responses: { "200": { description: Current user's model access requests } } post: operationId: createPortalModelRequest security: [{ bearerAuth: [] }] responses: { "200": { description: Pending model access request created with outbox event } } /api/v1/portal/logs: get: operationId: listPortalAuditEvents security: [{ bearerAuth: [] }] responses: { "200": { description: Bounded audit events owned through portal API keys } } /api/v1/portal/logs/{audit_event_id}: get: operationId: getPortalAuditEvent security: [{ bearerAuth: [] }] parameters: [{ name: audit_event_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Owned audit event with bounded previews } } /api/v1/portal/stats: get: operationId: getPortalStats security: [{ bearerAuth: [] }] responses: { "200": { description: Personal requests, tokens, cost and latency aggregate } } /api/v1/portal/cost: get: operationId: getPortalCost security: [{ bearerAuth: [] }] responses: { "200": { description: Personal month-to-date cost in integer microunits } } /api/v1/portal/docs-info: get: operationId: getPortalIntegrationDocs security: [{ bearerAuth: [] }] responses: { "200": { description: Safe runtime protocol and authentication overview } } /api/v1/portal/apps/{application_code}/chat: post: operationId: runPortalApplicationCompatibilityChat security: [{ bearerAuth: [] }] parameters: [{ name: application_code, in: path, required: true, schema: { type: string } }] responses: { "200": { description: Single user message executed with a server-held encrypted application credential } } /api/v1/portal/apps/{application_code}/conversations: post: operationId: createPortalApplicationConversation security: [{ bearerAuth: [] }] parameters: [{ name: application_code, in: path, required: true, schema: { type: string } }] responses: { "200": { description: Server-managed conversation created } } /api/v1/portal/apps/{application_code}/conversations/{conversation_id}: get: operationId: getPortalApplicationConversation security: [{ bearerAuth: [] }] parameters: - { name: application_code, in: path, required: true, schema: { type: string } } - { name: conversation_id, in: path, required: true, schema: { type: string, format: uuid } } responses: { "200": { description: Ownership-checked conversation with verified immutable hash chain } } /api/v1/portal/apps/{application_code}/conversations/{conversation_id}/messages: post: operationId: appendPortalApplicationConversationMessage security: [{ bearerAuth: [] }] parameters: - { name: application_code, in: path, required: true, schema: { type: string } } - { name: conversation_id, in: path, required: true, schema: { type: string, format: uuid } } responses: { "200": { description: Leased serial message execution with verified server-side history } } /api/v1/admin/models: get: operationId: listAdministrativeModels security: [{ bearerAuth: [] }] responses: { "200": { description: Enabled provider model catalog } } /api/v1/admin/model-requests: get: operationId: listAdministrativeModelRequests security: [{ bearerAuth: [] }] responses: { "200": { description: Portal model access requests by status } } /api/v1/admin/model-requests/{request_id}/approve: post: operationId: approveModelRequest security: [{ bearerAuth: [] }] parameters: [{ name: request_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Pending request approved transactionally } } /api/v1/admin/model-requests/{request_id}/reject: post: operationId: rejectModelRequest security: [{ bearerAuth: [] }] parameters: [{ name: request_id, in: path, required: true, schema: { type: string, format: uuid } }] responses: { "200": { description: Pending request rejected transactionally } } /v1/models: get: operationId: listModels security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/GatewayProvider" responses: "200": { description: OpenAI-compatible model list } "429": { description: Per-minute, monthly request, or monthly token quota exceeded } "503": { description: Authentication, admission control, or provider configuration unavailable } /v1/chat/completions: post: operationId: createChatCompletion security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/GatewayProvider" - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: { type: object, additionalProperties: true } responses: "200": { description: JSON response or SSE stream } "429": { description: Per-minute, monthly request, or monthly token quota exceeded } "503": { description: Authentication, admission control, or provider configuration unavailable } /v1/responses: post: operationId: createResponse security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/GatewayProvider" - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: { type: object, additionalProperties: true } responses: "200": { description: JSON response or SSE stream } "429": { description: Per-minute, monthly request, or monthly token quota exceeded } "503": { description: Authentication, admission control, or provider configuration unavailable } /v1/embeddings: post: operationId: createEmbedding security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/GatewayProvider" - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: { type: object, additionalProperties: true } responses: "200": { description: OpenAI-compatible embedding response } "429": { description: Per-minute, monthly request, or monthly token quota exceeded } "503": { description: Authentication, admission control, or provider configuration unavailable } /v1/messages: post: operationId: createAnthropicMessage security: [{ bearerAuth: [] }] parameters: - $ref: "#/components/parameters/GatewayProvider" - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: { type: object, additionalProperties: true } responses: "200": { description: Anthropic-compatible response or SSE stream } "429": { description: Per-minute, monthly request, or monthly token quota exceeded } "503": { description: Authentication, admission control, or provider configuration unavailable } components: parameters: ModelRouteID: name: model_route_id in: path required: true schema: { type: string, format: uuid } IdempotencyKey: name: Idempotency-Key in: header required: false description: Enables bounded retries for replayable POST requests. Reusing a key is the caller's idempotency contract. schema: { type: string, minLength: 1, maxLength: 255 } IdentityID: name: identity_id in: path required: true schema: { type: string, format: uuid } ProviderID: name: provider_id in: path required: true schema: { type: string, format: uuid } GatewayProvider: name: X-Gateway-Provider in: header required: false description: Enabled database Provider code. Omit to use the current default snapshot entry. schema: { type: string } securitySchemes: bearerAuth: type: http scheme: bearer apiKeyAuth: type: http scheme: bearer description: Gateway API Key with gateway:invoke scope; X-Gateway-API-Key is also accepted. schemas: Health: type: object required: [status, version] properties: status: { type: string, const: ok } version: { type: string } LoginRequest: type: object required: [userName, password] properties: userName: { type: string, minLength: 1, maxLength: 128 } password: { type: string, minLength: 1, maxLength: 1024 } TOTPLoginRequest: type: object required: [temp_token] properties: temp_token: { type: string, minLength: 1 } code: { type: string, pattern: "^[0-9]{6}$" } backup_code: { type: string, pattern: "^[A-Za-z2-9]{4}-?[A-Za-z2-9]{4}$" } anyOf: - required: [code] - required: [backup_code] ProviderInput: type: object required: [code, adapter, base_url, capabilities, config, enabled] properties: code: type: string pattern: "^[a-z][a-z0-9_-]{1,63}$" adapter: type: string enum: [openai-compatible] base_url: { type: string, format: uri } api_key: type: string description: Omit during update to retain the existing encrypted credential. capabilities: type: array items: { type: string } config: { type: object, additionalProperties: true } enabled: { type: boolean } IdentityInput: type: object required: [login, display_name, role, permissions, active] properties: login: { type: string, minLength: 2, maxLength: 128 } display_name: { type: string, maxLength: 64 } role: { type: string, enum: [superadmin, operator, auditor, member] } password: type: string minLength: 12 maxLength: 1024 description: Required on create; omit on update to retain the current password. permissions: type: array uniqueItems: true items: type: string pattern: "^[a-z][a-z0-9_.:-]{2,127}$|^\\*$" active: { type: boolean } department_id: type: [string, "null"] format: uuid description: Portal accounts may bind to an active department. DepartmentInput: type: object required: [code, name, description, active] properties: code: { type: string, pattern: "^[a-z][a-z0-9_-]{1,63}$" } name: { type: string, minLength: 1, maxLength: 128 } description: { type: string, maxLength: 1024 } parent_id: { type: [string, "null"], format: uuid } active: { type: boolean } OIDCProviderInput: type: object required: [code, display_name, issuer_url, client_id, redirect_uri, portal_return_url, scopes, auto_provision, enabled] properties: code: { type: string, pattern: "^[a-z][a-z0-9_-]{1,63}$" } display_name: { type: string, minLength: 1, maxLength: 128 } issuer_url: { type: string, format: uri } client_id: { type: string, minLength: 1 } client_secret: type: string description: Required on create and omitted on update to retain the encrypted value. redirect_uri: { type: string, format: uri } portal_return_url: { type: string, format: uri } scopes: type: array contains: { const: openid } items: { type: string } auto_provision: { type: boolean } default_department_id: { type: [string, "null"], format: uuid } enabled: { type: boolean } SAMLProviderInput: type: object required: [code, display_name, metadata_url, sp_entity_id, acs_url, portal_return_url, email_attribute, name_attribute, auto_provision, enabled] properties: code: { type: string, pattern: "^[a-z][a-z0-9_-]{1,63}$" } display_name: { type: string, minLength: 1, maxLength: 128 } metadata_url: { type: string, format: uri } sp_entity_id: type: string minLength: 1 maxLength: 512 description: Absolute URI used as the SAML audience. acs_url: type: string format: uri description: Must end with /api/v1/portal/sso/{code}/callback. portal_return_url: { type: string, format: uri } email_attribute: { type: string, maxLength: 256 } name_attribute: { type: string, maxLength: 256 } auto_provision: { type: boolean } default_department_id: { type: [string, "null"], format: uuid } enabled: { type: boolean } ProviderConnectionResult: type: object required: [connected, latency_ms, message] properties: connected: { type: boolean } status_code: { type: integer } latency_ms: { type: integer, format: int64, minimum: 0 } message: { type: string } ProviderModel: type: object required: [id, provider_id, provider_model_id, metadata, enabled, discovered_at, last_seen_at] properties: id: { type: string, format: uuid } provider_id: { type: string, format: uuid } provider_model_id: { type: string, minLength: 1, maxLength: 512 } owned_by: { type: string } metadata: { type: object, additionalProperties: true } enabled: { type: boolean } discovered_at: { type: string, format: date-time } last_seen_at: { type: string, format: date-time } ModelSyncResult: type: object required: [discovered, active, disabled, synced_at] properties: discovered: { type: integer, minimum: 0 } active: { type: integer, minimum: 0 } disabled: { type: integer, minimum: 0 } synced_at: { type: string, format: date-time } CredentialRotationResult: type: object required: [active_version, loaded_versions, rotated, skipped] properties: active_version: { type: integer, minimum: 1 } loaded_versions: type: array items: { type: integer, minimum: 1 } rotated: { type: integer, minimum: 0 } skipped: { type: integer, minimum: 0 } APIKeyInput: type: object required: [name, scopes, requests_per_minute, monthly_request_quota, monthly_token_quota] properties: name: { type: string, minLength: 1, maxLength: 128 } scopes: type: array minItems: 1 items: { type: string, enum: [gateway:invoke, "*"] } requests_per_minute: type: integer minimum: 0 maximum: 1000000 description: Per-API-key UTC minute request limit; zero means unlimited. monthly_request_quota: type: integer format: int64 minimum: 0 maximum: 1000000000000 description: Accepted requests per UTC calendar month; zero means unlimited. monthly_token_quota: type: integer format: int64 minimum: 0 maximum: 1000000000000000 description: Input plus output tokens per UTC calendar month; zero means unlimited. expires_at: { type: [string, "null"], format: date-time } APIKeyLimitsInput: type: object required: [requests_per_minute, monthly_request_quota, monthly_token_quota] properties: requests_per_minute: { type: integer, minimum: 0, maximum: 1000000 } monthly_request_quota: { type: integer, format: int64, minimum: 0, maximum: 1000000000000 } monthly_token_quota: { type: integer, format: int64, minimum: 0, maximum: 1000000000000000 } ModelRouteInput: type: object required: [name, source_model, target_model, provider_id, weight, priority, conditions, enabled] properties: name: { type: string, minLength: 1, maxLength: 128 } source_model: { type: string, minLength: 1, maxLength: 512 } target_model: { type: string, minLength: 1, maxLength: 512 } provider_id: { type: string, format: uuid } weight: { type: integer, minimum: 1, maximum: 10000 } priority: { type: integer, minimum: -100000, maximum: 100000 } enabled: { type: boolean } conditions: type: object additionalProperties: true properties: endpoints: type: array items: { type: string, enum: [/v1/chat/completions, /v1/responses, /v1/embeddings, /v1/messages] } api_key_ids: type: array items: { type: string, format: uuid } tenant_ids: type: array items: { type: string, format: uuid } ContentPolicyInput: type: object required: [name, description, action, priority, paths, models, api_key_ids, rules, enabled] properties: name: { type: string, minLength: 1, maxLength: 128 } description: { type: string, maxLength: 1000 } action: { type: string, enum: [audit, block, redact] } priority: { type: integer, minimum: -100000, maximum: 100000 } paths: { type: array, items: { type: string } } models: { type: array, items: { type: string } } api_key_ids: { type: array, items: { type: string, format: uuid } } enabled: { type: boolean } rules: type: array minItems: 1 maxItems: 20 items: type: object required: [name, pattern, replacement] properties: name: { type: string, minLength: 1 } pattern: { type: string, minLength: 1, maxLength: 512, description: Go RE2 expression } replacement: { type: string } ModelPriceInput: type: object required: [provider_code, model_pattern, input_microunits_per_million, output_microunits_per_million, currency, effective_from, enabled] properties: provider_code: { type: string, pattern: "^[a-z][a-z0-9_-]{1,63}$" } model_pattern: { type: string, description: Exact model name or a prefix ending in one asterisk } input_microunits_per_million: { type: integer, format: int64, minimum: 0 } output_microunits_per_million: { type: integer, format: int64, minimum: 0 } currency: { type: string, minLength: 3, maxLength: 3, default: USD } effective_from: { type: string, format: date-time } effective_to: { type: [string, "null"], format: date-time } enabled: { type: boolean } PromptVariable: type: object required: [name, required] properties: name: { type: string, pattern: "^[A-Za-z_][A-Za-z0-9_]*$" } label: { type: string, maxLength: 128 } default: { type: string, maxLength: 10000 } required: { type: boolean } PromptInput: type: object required: [name, description, tags, department_ids, enabled] properties: name: { type: string, minLength: 1, maxLength: 128 } description: { type: string, maxLength: 4000 } category_id: { type: [string, "null"], format: uuid } tags: { type: array, maxItems: 30, items: { type: string } } department_ids: { type: array, maxItems: 100, items: { type: string, format: uuid } } enabled: { type: boolean } content: { type: string, maxLength: 100000, description: Required only when creating the initial version. } variables: { type: array, maxItems: 100, items: { $ref: "#/components/schemas/PromptVariable" } } change_note: { type: string } KnowledgeBaseInput: type: object required: [name, description, retrieval_mode, chunk_size, chunk_overlap, department_ids, enabled] properties: name: { type: string, minLength: 1, maxLength: 128 } description: { type: string, maxLength: 4000 } retrieval_mode: { type: string, enum: [postgres_fts] } chunk_size: { type: integer, minimum: 200, maximum: 8000 } chunk_overlap: { type: integer, minimum: 0 } department_ids: { type: array, maxItems: 100, items: { type: string, format: uuid } } enabled: { type: boolean } ToolInput: type: object required: [code, name, description, endpoint_url, http_method, input_schema, timeout_seconds, department_ids, enabled] properties: code: { type: string, pattern: "^[a-z][a-z0-9_-]{1,63}$" } name: { type: string, minLength: 1, maxLength: 128 } description: { type: string, maxLength: 4000 } endpoint_url: { type: string, format: uri } http_method: { type: string, enum: [GET, POST, PUT, PATCH, DELETE] } headers: type: object writeOnly: true additionalProperties: { type: string } description: Omit during update to preserve the existing KEK-encrypted headers. input_schema: { type: object, additionalProperties: true } timeout_seconds: { type: integer, minimum: 1, maximum: 120 } department_ids: { type: array, maxItems: 100, items: { type: string, format: uuid } } enabled: { type: boolean } ApplicationConfig: type: object required: [model, knowledge_base_ids, tool_ids, retrieval_top_k, temperature, max_tool_rounds] properties: model: { type: string, maxLength: 255 } prompt_template_id: { type: string, format: uuid } knowledge_base_ids: { type: array, maxItems: 20, items: { type: string, format: uuid } } tool_ids: { type: array, maxItems: 20, items: { type: string, format: uuid } } retrieval_top_k: { type: integer, minimum: 1, maximum: 20 } temperature: { type: number, minimum: 0, maximum: 2 } max_tool_rounds: { type: integer, minimum: 0, maximum: 8 } ApplicationInput: type: object required: [code, name, description, status, department_ids, draft_config] properties: code: { type: string, pattern: "^[a-z][a-z0-9_-]{2,63}$" } name: { type: string, minLength: 1, maxLength: 128 } description: { type: string, maxLength: 4000 } status: { type: string, enum: [draft, active, suspended, retired] } department_ids: { type: array, maxItems: 100, items: { type: string, format: uuid } } draft_config: { $ref: "#/components/schemas/ApplicationConfig" } NotificationChannelInput: type: object required: [name, webhook_url, event_patterns, enabled] properties: name: { type: string, minLength: 1, maxLength: 128 } webhook_url: { type: string, format: uri } signing_secret: type: string writeOnly: true maxLength: 4096 description: Omit during update to preserve the existing KEK-encrypted signing secret. event_patterns: type: array minItems: 1 maxItems: 100 items: { type: string, description: Exact event type or a prefix ending in one asterisk. } enabled: { type: boolean }