openapi: 3.1.0 info: title: AlgaPSA API version: 0.1.0 description: OpenAPI specification generated from registered route metadata. servers: - url: https://algapsa.com description: Production - url: http://localhost:3000 description: Local development tags: - name: AI - name: Access Control & Users v1 - name: Accounting Exports - name: Admin - name: Assets - name: Auth - name: Automation - name: Billing - name: Billing Analytics - name: Boards - name: Categories - name: Chat - name: Client Contract Lines - name: Clients - name: Comments - name: Contacts - name: Contract Lines - name: Documents - name: Email - name: Extension Gateway - name: Extension Installs - name: Extensions - name: Files - name: Financial - name: Inbound Webhooks - name: Integrations - QuickBooks - name: Invoices - name: Knowledge Base - name: Meta & Utility v1 - name: Priorities - name: Products - name: Project Templates - name: Projects - name: QuickBooks v1 - name: Quotes & Contracts v1 - name: Search - name: Service Catalog - name: Service Categories - name: Service Types - name: Services - name: Software - name: SoftwareOne Extensions - name: Statuses - name: Storage - name: System - name: Telemetry - name: Ticket Categories - name: Webhooks - name: Work Management v1 - name: Workflow Definitions - name: Workflow Registry - name: Workflow Runs - name: Workflows v1 - name: accounting - name: auth - name: billing - name: calendar - name: chat - name: client-portal - name: clients - name: documents - name: email - name: ext - name: ext-bundles - name: ext-debug - name: ext-proxy - name: import - name: inbound - name: integrations - name: internal - name: mobile - name: online-meetings - name: platform-feature-flags - name: platform-notifications - name: platform-reports - name: public - name: secrets - name: share - name: storage - name: teams - name: tenant-management - name: tickets - name: webhooks components: securitySchemes: ApiKeyAuth: type: apiKey in: header name: x-api-key BearerAuth: type: http scheme: bearer bearerFormat: Auth.js JWE session token SessionCookieAuth: type: apiKey in: cookie name: authjs.session-token description: Auth.js session cookie. In secure production deployments the cookie may be named __Secure-authjs.session-token; in local development it may include a port suffix. WebhookSignatureAuth: type: apiKey in: header name: x-webhook-signature description: HMAC-SHA256 signature generated with ALGA_WEBHOOK_SECRET. POST signs the raw JSON body. GET signs the string GET:. GooglePubSubJWT: type: http scheme: bearer bearerFormat: Google Pub/Sub JWT description: Google-signed JWT from Pub/Sub push. The webhook validates the audience against the webhook URL and checks the issuer/service account against tenant Google configuration. schemas: ErrorResponse: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error PlaceholderObject: type: object properties: {} OAuthCallbackHtmlResponse: type: string description: HTML popup callback page. The page posts a JSON oauth-callback message to window.opener or window.parent via postMessage, then attempts to close itself. OAuthCallbackQuery: type: object properties: code: type: string description: OAuth 2.0 authorization code. Required unless the provider returned error. state: type: string description: Base64-encoded JSON state object generated when the OAuth flow was initiated. It carries tenant context, providerId, redirectUri, timestamp, and nonce values used to complete the callback. error: type: string description: OAuth error code returned by the provider, such as access_denied. error_description: type: string description: Human-readable OAuth error description returned by the provider. AuthSessionUser: type: object properties: id: type: string description: User identifier from the users.user_id record. email: type: string format: email description: User's email address. name: type: string description: User's display name, usually first_name plus last_name. username: type: string description: User's login username. image: type: string description: Avatar or profile image URL. proToken: type: string description: Legacy Pro token value when present. tenant: type: string description: Tenant UUID from the user session JWT. tenantSlug: type: string description: URL-safe tenant slug for portal routing. user_type: type: string enum: - client - internal description: User classification from users.user_type. clientId: type: string format: uuid description: Client UUID from contacts.client_id for client-portal users. contactId: type: string format: uuid description: Contact UUID from users.contact_id for client-portal users. plan: type: string description: Current tenant billing plan key. addons: type: array items: type: string description: Enabled tenant add-on keys. trial_end: type: - string - "null" description: Trial expiry timestamp when present. subscription_status: type: - string - "null" enum: - active - trialing - past_due - unpaid description: Billing subscription status copied into the session token. solo_pro_trial_end: type: - string - "null" description: Solo Pro trial expiry timestamp when present. premium_trial_end: type: - string - "null" description: Premium trial expiry timestamp when present. premium_trial_confirmed: type: boolean description: Whether the user confirmed the Premium trial. premium_trial_effective_date: type: - string - "null" description: Premium trial effective date when present. required: - id - email - name - username AuthSessionAuthenticatedResponse: type: object properties: session_id: type: string format: uuid description: Current session UUID from the sessions table, created at sign-in. login_method: type: string description: Authentication method used for this session, such as credentials, google, or azure-ad. user: $ref: "#/components/schemas/AuthSessionUser" required: - user EmptyObjectResponse: type: object properties: {} additionalProperties: false description: Empty object returned when no authenticated session is present. AuthSessionResponse: anyOf: - $ref: "#/components/schemas/AuthSessionAuthenticatedResponse" - $ref: "#/components/schemas/EmptyObjectResponse" description: Authenticated session data, or an empty object when the request has no valid session cookie. FlatErrorResponse: type: object properties: error: type: string description: Human-readable error message. required: - error ValidateApiKeyHeaders: type: object properties: x-api-key: type: string minLength: 1 description: Plaintext API key to validate. The service hashes this value before looking up the api_keys record. required: - x-api-key ValidateApiKeyResponse: type: object properties: isValid: type: boolean enum: - true description: Indicates that the API key is active and valid. userId: type: string format: uuid description: UUID of the user who owns the API key, from api_keys.user_id. tenant: type: string description: Tenant identifier scoped to this API key, from api_keys.tenant. required: - isValid - userId - tenant ValidateTokenHeaders: type: object properties: authorization: type: string description: Optional Bearer token fallback. The route also accepts the Auth.js session token cookie. ValidateTokenSuccessResponse: type: object properties: isValid: type: boolean enum: - true description: Indicates that the request contains a valid Auth.js session token. userType: type: string enum: - internal - client description: User classification from users.user_type in the session JWT. tenant: type: string description: Tenant identifier from the session JWT. required: - isValid - userType - tenant ValidateTokenUnauthorizedResponse: type: object properties: isValid: type: boolean enum: - false description: No valid session token was found. required: - isValid NextAuthCatchAllParams: type: object properties: nextauth: type: string description: NextAuth catch-all action path. Common values include csrf, providers, signin, signout, session, error, verify-request, webauthn-options, callback/credentials, callback/google, callback/azure-ad, and callback/keycloak. required: - nextauth NextAuthGetQuery: type: object properties: callbackUrl: type: string description: Optional URL to redirect to after sign-in or sign-out flows. error: type: string description: Optional NextAuth/OAuth error code shown by sign-in or error pages. code: type: string description: OAuth authorization code for provider callback sub-routes. state: type: string description: OAuth state value for provider callback sub-routes. error_description: type: string description: Human-readable provider error description for OAuth callback sub-routes. CsrfTokenResponse: type: object properties: csrfToken: type: string description: Opaque double-submit CSRF token required for mutating NextAuth POST actions. required: - csrfToken ProviderInfo: type: object properties: id: type: string description: Provider identifier such as credentials, google, azure-ad, or keycloak. name: type: string description: Provider display name. type: type: string enum: - oauth - oidc - credentials - email - webauthn description: NextAuth provider type. signinUrl: type: string description: URL used to initiate sign-in with this provider. callbackUrl: type: string description: URL the provider redirects to after authentication. required: - id - name - type - signinUrl - callbackUrl AuthProvidersResponse: type: object additionalProperties: $ref: "#/components/schemas/ProviderInfo" description: Map of configured providers keyed by provider ID. NextAuthGetResponse: anyOf: - $ref: "#/components/schemas/AuthSessionAuthenticatedResponse" - $ref: "#/components/schemas/EmptyObjectResponse" - $ref: "#/components/schemas/CsrfTokenResponse" - $ref: "#/components/schemas/AuthProvidersResponse" - $ref: "#/components/schemas/OAuthCallbackHtmlResponse" - $ref: "#/components/schemas/EmptyObjectResponse" description: "Representative successful GET response for the NextAuth catch-all route. The exact payload depends on the nextauth action: session returns a session object or {}, csrf returns csrfToken, providers returns a provider map, and page actions return HTML or redirects." NextAuthPostBody: type: object properties: email: type: string format: email description: Credentials-provider email address for callback/credentials. password: type: string description: Credentials-provider plaintext password for callback/credentials. twoFactorCode: type: string description: TOTP code required when two-factor authentication is enabled and the device is not trusted. userType: type: string enum: - client - internal description: Optional user type used to scope credentials-provider lookup. tenant: type: string description: Optional tenant slug used to resolve the tenant for credentials-provider login. csrfToken: type: string description: CSRF token from GET /api/auth/csrf. Required for sign-in, sign-out, and other mutating NextAuth actions. callbackUrl: type: string description: Post-authentication redirect URL. redirect: type: string description: NextAuth redirect mode flag. json: type: string description: NextAuth JSON response mode flag. code: type: string description: OAuth authorization code for provider callback actions. state: type: string description: OAuth state value for provider callback actions. error: type: string description: Provider OAuth error code for callback actions. error_description: type: string description: Provider OAuth error description for callback actions. RedirectResponse: type: string description: HTTP redirect response. NextAuth sets or clears cookies depending on the action. TelemetrySettingsGetResponse: type: object properties: usageStatsEnabled: type: boolean description: Whether usage statistics are enabled by the ALGA_USAGE_STATS environment variable. environmentVariable: type: string enum: - ALGA_USAGE_STATS description: Environment variable controlling telemetry collection. currentValue: type: string description: Raw ALGA_USAGE_STATS environment value, or not set when absent. controlledBy: type: string enum: - environment description: Telemetry is controlled by process environment, not runtime API writes. message: type: string description: Human-readable explanation of the current telemetry setting. required: - usageStatsEnabled - environmentVariable - currentValue - controlledBy - message TelemetrySettingsPostResponse: type: object properties: usageStatsEnabled: type: boolean description: Whether usage statistics are enabled by the ALGA_USAGE_STATS environment variable. controlledBy: type: string enum: - environment description: Telemetry is controlled by process environment, not runtime API writes. message: type: string description: Explains that telemetry settings cannot be changed through this API. required: - usageStatsEnabled - controlledBy - message AdminTelemetryErrorResponse: type: object properties: error: type: string description: Error message such as Authentication required, Insufficient permissions, or the handler failure message. required: - error AccessUserIdParamV1: type: object properties: id: type: string format: uuid description: User UUID from users.user_id. required: - id AccessRoleIdParamV1: type: object properties: id: type: string format: uuid description: Role UUID from roles.role_id. required: - id AccessTeamIdParamV1: type: object properties: id: type: string format: uuid description: Team UUID from teams.team_id. required: - id AccessTeamMemberParamsV1: type: object properties: id: type: string format: uuid description: Team UUID from teams.team_id. userId: type: string format: uuid description: User UUID from users.user_id. required: - id - userId AccessTeamPermissionParamsV1: type: object properties: id: type: string format: uuid description: Team UUID from teams.team_id. permissionId: type: string format: uuid description: Permission UUID from permissions.permission_id. required: - id - permissionId AccessUserTeamParamsV1: type: object properties: id: type: string format: uuid description: User UUID from users.user_id. teamId: type: string format: uuid description: Team UUID from teams.team_id. required: - id - teamId AccessPermissionIdParamV1: type: object properties: id: type: string format: uuid description: Permission UUID from permissions.permission_id. required: - id AccessUserListQueryV1: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a32 - asc - desc username: type: string first_name: type: string last_name: type: string email: type: string user_type: type: string enum: &a33 - internal - client - admin - contractor role_id: type: string format: uuid team_id: type: string format: uuid is_inactive: type: string enum: &a34 - "true" - "false" include_permissions: type: string enum: &a35 - "true" - "false" include_teams: type: string enum: &a36 - "true" - "false" fields: type: string AccessUserSearchQueryV1: type: object properties: query: type: string fields: type: string description: Controller query parser sends strings; schema expects an array of field names. user_type: type: string enum: &a37 - internal - client - admin - contractor role_id: type: string format: uuid team_id: type: string format: uuid include_inactive: type: string enum: &a38 - "true" - "false" limit: type: string required: - query AccessUserActivityQueryV1: type: object properties: page: type: string limit: type: string from_date: type: string to_date: type: string activity_type: type: string description: Controller converts single query value to one-element array for service filter. ip_address: type: string AccessUserRolesListQueryV1: type: object properties: page: type: string limit: type: string search: type: string is_inactive: type: string enum: &a30 - "true" - "false" sort: type: string order: type: string enum: &a31 - asc - desc AccessRoleListQueryV1: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a23 - asc - desc role_name: type: string has_permissions: type: string enum: &a24 - "true" - "false" permission_resource: type: string permission_action: type: string is_template: type: string enum: &a25 - "true" - "false" AccessPermissionListQueryV1: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a22 - asc - desc resource: type: string action: type: string AccessTeamListQueryV1: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a26 - asc - desc team_name: type: string manager_id: type: string format: uuid fields: type: string AccessTeamSearchQueryV1: type: object properties: query: type: string page: type: string limit: type: string manager_id: type: string format: uuid has_manager: type: string enum: &a27 - "true" - "false" sort: type: string order: type: string enum: &a28 - asc - desc AccessTeamAnalyticsQueryV1: type: object properties: start_date: type: string end_date: type: string include_metrics: type: string description: Controller query parser provides strings; schema expects metric array. granularity: type: string enum: &a29 - daily - weekly - monthly AccessCreateUserBodyV1: type: object properties: username: type: string minLength: 3 email: type: string format: email password: type: string minLength: 8 first_name: type: string last_name: type: string phone: type: string timezone: type: string user_type: type: string enum: &a1 - internal - client - admin - contractor contact_id: type: string format: uuid two_factor_enabled: type: boolean is_google_user: type: boolean is_inactive: type: boolean role_ids: type: array items: type: string format: uuid required: - username - email - password AccessUpdateUserBodyV1: type: object properties: username: type: string minLength: 3 email: type: string format: email first_name: type: string last_name: type: string phone: type: string timezone: type: string user_type: type: string enum: *a1 contact_id: type: string format: uuid two_factor_enabled: type: boolean is_google_user: type: boolean is_inactive: type: boolean role_ids: type: array items: type: string format: uuid AccessChangePasswordBodyV1: type: object properties: current_password: type: string new_password: type: string minLength: 8 confirm_password: type: string required: - new_password - confirm_password AccessUserRoleIdsBodyV1: type: object properties: role_ids: type: array items: type: string format: uuid minItems: 1 required: - role_ids AccessUserPreferenceBodyV1: type: object additionalProperties: {} description: Controller forwards request body directly to UserService.updateUserPreferences(). AccessEnable2FABodyV1: type: object properties: secret: type: string token: type: string required: - secret - token AccessCreateRoleBodyV1: type: object properties: role_name: type: string description: type: string permissions: type: array items: type: string format: uuid copy_from_role_id: type: string format: uuid is_template: type: boolean required: - role_name AccessUpdateRoleBodyV1: type: object properties: role_name: type: string description: type: string permissions: type: array items: type: string format: uuid is_template: type: boolean AccessRoleCloneBodyV1: type: object properties: new_role_name: type: string new_description: type: string copy_permissions: type: boolean copy_user_assignments: type: boolean required: - new_role_name AccessRolePermissionsBodyV1: type: object properties: permission_ids: type: array items: type: string format: uuid minItems: 1 required: - permission_ids AccessBulkRolesBodyV1: type: object properties: roles: type: array items: $ref: "#/components/schemas/AccessCreateRoleBodyV1" minItems: 1 required: - roles AccessCreatePermissionBodyV1: type: object properties: resource: type: string action: type: string description: type: string required: - resource - action AccessUpdatePermissionBodyV1: type: object properties: resource: type: string action: type: string description: type: string AccessPermissionChecksBodyV1: type: object properties: user_id: type: string format: uuid permissions: type: array items: type: object properties: resource: type: string action: type: string required: - resource - action minItems: 1 required: - permissions AccessCreateTeamBodyV1: type: object properties: team_name: type: string manager_id: type: string format: uuid members: type: array items: type: object additionalProperties: {} required: - team_name AccessUpdateTeamBodyV1: type: object properties: team_name: type: string manager_id: type: string format: uuid members: type: array items: type: object additionalProperties: {} AccessAddTeamMemberBodyV1: type: object properties: user_id: type: string format: uuid required: - user_id AccessBulkAddTeamMembersBodyV1: type: object properties: user_ids: type: array items: type: string format: uuid minItems: 1 required: - user_ids AccessAssignTeamManagerBodyV1: type: object properties: manager_id: type: string format: uuid required: - manager_id AccessTeamPermissionGrantBodyV1: type: object properties: resource: type: string description: Controller also accepts permission alias field. permission: type: string action: type: string expires_at: type: string AccessTeamHierarchyBodyV1: type: object properties: parent_team_id: type: - string - "null" format: uuid AccessTeamBulkUpdateBodyV1: type: object properties: team_ids: type: array items: type: string format: uuid minItems: 1 updates: type: object additionalProperties: {} required: - team_ids - updates AccessTeamBulkDeleteBodyV1: type: object properties: team_ids: type: array items: type: string format: uuid minItems: 1 required: - team_ids AccessApiErrorV1: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error AccessApiSuccessV1: type: object properties: data: anyOf: - type: object additionalProperties: {} - type: array items: type: object additionalProperties: {} meta: type: object additionalProperties: {} required: - data AccessApiPaginatedV1: type: object properties: data: type: array items: type: object additionalProperties: {} pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination AssetListQuery: type: object properties: page: type: string description: Page number as a query string. Defaults to 1 after validation. limit: type: string description: Page size as a query string. Must parse to 1 through 100; defaults to 25. sort: type: string description: Sort column. Defaults to created_at. order: type: string enum: &a39 - asc - desc description: Sort direction. Defaults to desc. search: type: string description: General search filter accepted by the shared filter schema. The current AssetService.list implementation does not apply this filter. created_from: type: string format: date-time description: Accepted by validation, but not currently applied by AssetService.list. created_to: type: string format: date-time description: Accepted by validation, but not currently applied by AssetService.list. updated_from: type: string format: date-time description: Accepted by validation, but not currently applied by AssetService.list. updated_to: type: string format: date-time description: Accepted by validation, but not currently applied by AssetService.list. is_active: type: string enum: &a40 - "true" - "false" description: Accepted by validation, but not currently applied by AssetService.list. asset_tag: type: string description: Partial asset tag match using ILIKE. name: type: string description: Partial asset name match using ILIKE. client_id: type: string format: uuid description: Client UUID from clients.client_id. location_id: type: string format: uuid description: Client location UUID from client_locations.location_id. asset_type: type: string enum: &a2 - workstation - network_device - server - mobile_device - printer - unknown description: Asset type stored in assets.asset_type. status: type: string description: Exact asset status match. location: type: string description: Partial location match using ILIKE. client_name: type: string description: Partial client name match; joins clients on client_id and tenant. has_warranty: type: string enum: &a41 - "true" - "false" description: true requires warranty_end_date to be non-null; false requires it to be null. warranty_expired: type: string enum: &a42 - "true" - "false" description: true filters warranty_end_date before now; false filters future warranty dates or no warranty. maintenance_due: type: string enum: &a43 - "true" - "false" description: Accepted by validation, but not currently applied by AssetService.list. purchase_date_from: type: string format: date-time description: Filter purchase_date greater than or equal to this timestamp. purchase_date_to: type: string format: date-time description: Filter purchase_date less than or equal to this timestamp. warranty_end_from: type: string format: date-time description: Filter warranty_end_date greater than or equal to this timestamp. warranty_end_to: type: string format: date-time description: Filter warranty_end_date less than or equal to this timestamp. AssetExportQuery: type: object properties: format: type: string enum: &a44 - csv - json description: Export format. csv (default) returns text/csv as an attachment; json returns the success envelope with the rows in data. asset_types: type: array items: type: string enum: *a2 description: Filter to these asset types. Repeat the param or pass a comma-separated list. statuses: type: array items: type: string description: Filter to these asset statuses. Repeat the param or pass a comma-separated list. client_ids: type: array items: type: string format: uuid description: Filter to these client UUIDs. Repeat the param or pass a comma-separated list. fields: type: array items: type: string description: Restrict exported columns to this set. Repeat the param or pass a comma-separated list. AssetIdParams: type: object properties: id: type: string format: uuid description: Asset UUID from assets.asset_id. required: - id AssetDocumentAssociationParams: type: object properties: associationId: type: string format: uuid description: Document association UUID from document_associations.association_id. required: - associationId AssetDocumentAssociationRequest: type: object properties: document_id: type: string format: uuid description: Document UUID from documents.document_id to associate with the asset. notes: type: string description: Optional notes stored on document_associations.notes. required: - document_id AssetExtensionData: type: object additionalProperties: {} description: Asset-type-specific extension data written to the corresponding extension table for workstation, network device, server, mobile device, or printer assets. AssetCreateRequest: type: object properties: client_id: type: string format: uuid description: Client UUID from clients.client_id. Required. asset_type: type: string enum: *a2 description: Asset type. Determines the optional extension data table. asset_tag: type: string minLength: 1 maxLength: 255 description: Required tenant-specific asset tag. name: type: string minLength: 1 maxLength: 255 description: Required asset name. status: type: string minLength: 1 description: Required asset status. location_id: type: - string - "null" format: uuid description: Optional client_locations.location_id link. Validated to belong to client_id. location: type: string description: Optional free-text asset location. serial_number: type: string description: Optional serial number. purchase_date: type: string format: date-time description: Optional purchase date/time. warranty_end_date: type: string format: date-time description: Optional warranty end date/time. extension_data: $ref: "#/components/schemas/AssetExtensionData" required: - client_id - asset_type - asset_tag - name - status AssetUpdateData: type: object properties: client_id: type: string format: uuid description: Client UUID to assign to the asset. asset_type: type: string enum: *a2 description: Asset type to store in assets.asset_type. asset_tag: type: string minLength: 1 maxLength: 255 description: Tenant-specific asset tag. name: type: string minLength: 1 maxLength: 255 description: Asset name. status: type: string minLength: 1 description: Asset status. location_id: type: - string - "null" format: uuid description: Client_locations.location_id link. Pass null to clear. location: type: string description: Free-text asset location. serial_number: type: string description: Serial number. purchase_date: type: string format: date-time description: Purchase date/time. warranty_end_date: type: string format: date-time description: Warranty end date/time. AssetBulkUpdateRequest: type: object properties: assets: type: array items: type: object properties: asset_id: type: string format: uuid description: Asset UUID from assets.asset_id. data: allOf: - $ref: "#/components/schemas/AssetUpdateData" - description: Partial update data validated with updateAssetSchema. required: - asset_id - data minItems: 1 maxItems: 50 description: Assets to update. Limited to 1 through 50 entries by validation. required: - assets AssetBulkStatusRequest: type: object properties: asset_ids: type: array items: type: string format: uuid minItems: 1 maxItems: 50 description: Asset UUIDs from assets.asset_id. Limited to 1 through 50 entries by validation. status: type: string minLength: 1 description: New status assigned to every asset in asset_ids. required: - asset_ids - status HateoasLink: type: object properties: href: type: string description: Target URL for the related operation. method: type: string description: HTTP method for the link when supplied. required: - href AssetLinks: type: object properties: self: $ref: "#/components/schemas/HateoasLink" edit: $ref: "#/components/schemas/HateoasLink" delete: $ref: "#/components/schemas/HateoasLink" list: $ref: "#/components/schemas/HateoasLink" documents: $ref: "#/components/schemas/HateoasLink" maintenance: $ref: "#/components/schemas/HateoasLink" history: $ref: "#/components/schemas/HateoasLink" description: HATEOAS links generated from the asset_id. AssetDocumentAssociationRow: type: object properties: association_id: type: string format: uuid description: Primary key from document_associations.association_id. entity_type: type: string enum: - asset description: Entity type stored on document_associations; always asset for these routes. entity_id: type: string format: uuid description: Asset UUID from document_associations.entity_id. document_id: type: string format: uuid description: Document UUID from document_associations.document_id. notes: type: - string - "null" description: Optional association notes. tenant: type: string format: uuid description: Tenant UUID from document_associations.tenant. created_at: type: string format: date-time description: Association creation timestamp. original_filename: type: string description: Original filename from the joined documents table, present on list responses. file_size: type: number description: File size in bytes from the joined documents table, present on list responses. mime_type: type: string description: MIME type from the joined documents table, present on list responses. uploaded_at: type: string format: date-time description: Document upload timestamp from the joined documents table, present on list responses. required: - association_id - entity_type - entity_id - document_id - tenant AssetDocumentListPayload: type: object properties: data: type: array items: $ref: "#/components/schemas/AssetDocumentAssociationRow" description: Document association rows for the asset. Empty when no associations exist or the asset is not found. _links: type: object properties: self: $ref: "#/components/schemas/HateoasLink" create: $ref: "#/components/schemas/HateoasLink" parent: $ref: "#/components/schemas/HateoasLink" description: Collection links. The controller currently points these at /api/v2/assets paths. required: - data - _links AssetDocumentListResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetDocumentListPayload" meta: type: object properties: timestamp: type: string format: date-time version: type: string required: - timestamp - version required: - success - data - meta AssetDocumentAssociationPayload: type: object properties: data: allOf: - $ref: "#/components/schemas/AssetDocumentAssociationRow" - description: Inserted document association row returned from document_associations.returning(*). required: - data AssetDocumentAssociationResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetDocumentAssociationPayload" meta: type: object properties: timestamp: type: string format: date-time version: type: string required: - timestamp - version required: - success - data - meta AssetResource: type: object properties: asset_id: type: string format: uuid description: Primary key from assets.asset_id. client_id: type: string format: uuid description: Client UUID from assets.client_id. asset_type: type: string enum: *a2 description: Asset type stored in assets.asset_type. asset_tag: type: string description: Tenant-specific asset tag. name: type: string description: Asset display name. status: type: string description: Asset status. location_id: type: - string - "null" format: uuid description: Client_locations.location_id link, when set. location: type: - string - "null" description: Asset location, when recorded. serial_number: type: - string - "null" description: Asset serial number, when recorded. purchase_date: type: - string - "null" description: Asset purchase date from assets.purchase_date. warranty_end_date: type: - string - "null" description: Warranty end date from assets.warranty_end_date. created_at: type: string format: date-time description: Asset creation timestamp. updated_at: type: string format: date-time description: Asset last update timestamp. tenant: type: string format: uuid description: Tenant UUID from assets.tenant; filtered to the authenticated request context. client_name: type: string description: Client name selected from the joined clients table. warranty_status: type: string enum: - no_warranty - expired - expiring_soon - active description: Computed from warranty_end_date by SQL CASE expression. maintenance_status: type: string description: Optional computed maintenance status when present in service results. extension_data: allOf: - $ref: "#/components/schemas/AssetExtensionData" - type: - object - "null" description: Asset-type-specific extension data returned by getWithDetails after create. relationships: type: array items: type: object additionalProperties: {} description: Related asset rows included by getWithDetails after create. documents: type: array items: type: object additionalProperties: {} description: Associated document rows included by getWithDetails after create. maintenance_schedules: type: array items: type: object additionalProperties: {} description: Maintenance schedule rows included by getWithDetails after create. _links: $ref: "#/components/schemas/AssetLinks" required: - asset_id - client_id - asset_type - asset_tag - name - status - created_at - updated_at - tenant AssetListPagination: type: object properties: page: type: integer description: Current page number. limit: type: integer description: Page size. total: type: integer description: Total matching asset count. totalPages: type: integer description: Total number of pages calculated from total and limit. required: - page - limit - total - totalPages AssetCollectionLinks: type: object properties: self: $ref: "#/components/schemas/HateoasLink" create: $ref: "#/components/schemas/HateoasLink" search: $ref: "#/components/schemas/HateoasLink" export: $ref: "#/components/schemas/HateoasLink" stats: $ref: "#/components/schemas/HateoasLink" description: Collection links returned by ApiAssetController.list. These currently point at /api/v2/assets paths. ApiResponseMeta: type: object properties: timestamp: type: string format: date-time description: Response timestamp generated by createApiResponse/createErrorResponse. version: type: string description: API response version string. required: - timestamp - version AssetListPayload: type: object properties: data: type: array items: $ref: "#/components/schemas/AssetResource" description: Asset records for the requested page. pagination: $ref: "#/components/schemas/AssetListPagination" _links: $ref: "#/components/schemas/AssetCollectionLinks" required: - data - pagination - _links AssetListResponse: type: object properties: success: type: boolean enum: - true description: Indicates the controller returned a successful response envelope. data: allOf: - $ref: "#/components/schemas/AssetListPayload" - description: Nested payload passed to createApiResponse by ApiAssetController.list. meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetResourcePayload: type: object properties: data: allOf: - $ref: "#/components/schemas/AssetResource" - description: Asset record returned by the service. required: - data AssetResourceResponse: type: object properties: success: type: boolean enum: - true data: allOf: - $ref: "#/components/schemas/AssetResourcePayload" - description: Nested payload passed to createApiResponse by ApiAssetController.create. meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetBulkUpdatePayload: type: object properties: data: type: array items: $ref: "#/components/schemas/AssetResource" description: Updated asset rows returned from AssetService.update. message: type: string description: Human-readable count of updated assets. required: - data - message AssetBulkUpdateResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetBulkUpdatePayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetExportJsonPayload: type: object properties: data: type: array items: $ref: "#/components/schemas/AssetResource" description: All asset rows returned by AssetService.list with default list options. Export filters are currently not applied. required: - data AssetExportJsonResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetExportJsonPayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetApiErrorEnvelope: type: object properties: success: type: boolean enum: - false description: Indicates the API response is an error envelope. error: type: object properties: message: type: string description: Human-readable error message. code: type: string description: Machine-readable error code such as VALIDATION_ERROR or INTERNAL_ERROR. details: description: Optional structured details, including Zod validation errors. required: - message - code meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - error AssetMiddlewareUnauthorizedResponse: type: object properties: error: type: string description: "Middleware-level error, usually Unauthorized: API key missing." required: - error AssetMaintenanceScheduleParams: type: object properties: scheduleId: type: string format: uuid description: Maintenance schedule UUID from asset_maintenance_schedules.schedule_id. required: - scheduleId AssetRelationshipParams: type: object properties: relationshipId: type: string format: uuid description: Asset relationship UUID from asset_relationships.relationship_id. required: - relationshipId AssetMaintenanceScheduleUpdateRequest: type: object properties: schedule_type: type: string enum: - preventive - inspection - calibration - replacement description: Type of maintenance schedule. frequency: type: string enum: - daily - weekly - monthly - quarterly - yearly - custom description: Recurrence frequency. Changing this triggers next_maintenance recalculation. frequency_interval: type: number minimum: 1 description: Frequency multiplier used when calculating the next maintenance date. start_date: type: string format: date-time description: Schedule start date/time. Changing this triggers next_maintenance recalculation. end_date: type: string format: date-time description: Optional schedule end date/time. notes: type: string description: Free-text schedule notes. assigned_to: type: string format: uuid description: Assigned user UUID from users.user_id. is_active: type: boolean description: Whether the schedule is active. schedule_config: type: object additionalProperties: {} description: Custom scheduling configuration. AssetMaintenanceScheduleResource: type: object properties: schedule_id: type: string format: uuid description: Primary key from asset_maintenance_schedules.schedule_id. asset_id: type: string format: uuid description: Asset UUID from asset_maintenance_schedules.asset_id. schedule_type: type: string description: Maintenance schedule type as used by ApiAssetController. frequency: type: string description: Recurrence frequency. frequency_interval: type: - number - "null" description: Frequency multiplier. start_date: type: - string - "null" description: Schedule start date/time. end_date: type: - string - "null" description: Schedule end date/time. last_maintenance: type: - string - "null" description: Last recorded maintenance date/time. next_maintenance: type: - string - "null" description: Next calculated maintenance date/time. notes: type: - string - "null" description: Free-text schedule notes. assigned_to: type: - string - "null" format: uuid description: Assigned user UUID. is_active: type: boolean description: Whether the schedule is active. schedule_config: type: - object - "null" additionalProperties: {} description: Custom scheduling configuration. created_at: type: string format: date-time description: Creation timestamp. updated_at: type: string format: date-time description: Last update timestamp. tenant: type: string format: uuid description: Tenant UUID scoped from the request context. required: - schedule_id - asset_id - tenant AssetMaintenanceSchedulePayload: type: object properties: data: allOf: - $ref: "#/components/schemas/AssetMaintenanceScheduleResource" - description: Updated schedule row. Undefined when the schedule ID does not exist or belongs to another tenant. AssetMaintenanceScheduleResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetMaintenanceSchedulePayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetMaintenanceScheduleCreateRequest: type: object properties: schedule_type: type: string enum: - preventive - inspection - calibration - replacement description: Required type of maintenance schedule. frequency: type: string enum: - daily - weekly - monthly - quarterly - yearly - custom description: Required recurrence frequency used to calculate next_maintenance. frequency_interval: type: number minimum: 1 description: Frequency multiplier. Defaults to service logic when absent. start_date: type: string format: date-time description: Schedule start date/time. The current schema makes this optional; the service falls back to now when absent. end_date: type: string format: date-time description: Optional schedule end date/time. notes: type: string description: Free-text schedule notes. assigned_to: type: string format: uuid description: Assigned user UUID from users.user_id. is_active: type: boolean description: Whether the schedule is active. Defaults to true in validation. schedule_config: type: object additionalProperties: {} description: Custom scheduling configuration. required: - schedule_type - frequency AssetMaintenanceScheduleListPayload: type: object properties: data: type: array items: $ref: "#/components/schemas/AssetMaintenanceScheduleResource" description: Maintenance schedule rows for the asset. Empty when no schedules exist or the asset is not found. _links: type: object properties: self: $ref: "#/components/schemas/HateoasLink" create: $ref: "#/components/schemas/HateoasLink" history: $ref: "#/components/schemas/HateoasLink" parent: $ref: "#/components/schemas/HateoasLink" description: Collection links. The controller currently points these at /api/v2/assets paths. required: - data - _links AssetMaintenanceScheduleListResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetMaintenanceScheduleListPayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetMaintenanceHistoryResource: type: object properties: history_id: type: string format: uuid description: Primary key from asset_maintenance_history.history_id. asset_id: type: string format: uuid description: Asset UUID from asset_maintenance_history.asset_id. schedule_id: type: - string - "null" format: uuid description: Optional related maintenance schedule UUID. maintenance_type: anyOf: - type: string enum: - preventive - corrective - inspection - calibration - replacement - type: string description: Maintenance type recorded for the history row. performed_by: type: string format: uuid description: User UUID supplied in the maintenance record. performed_at: type: string format: date-time description: Timestamp when maintenance was performed. duration_hours: type: - number - "null" description: Maintenance duration in hours, when recorded. cost: type: - number - "null" description: Maintenance cost, when recorded. notes: type: - string - "null" description: Free-text notes. parts_used: type: - array - "null" items: type: string description: Parts used, when recorded. maintenance_data: type: - object - "null" additionalProperties: {} description: Arbitrary structured maintenance data. description: type: - string - "null" description: Description column when present in the maintenance history table. created_at: type: string format: date-time description: History creation timestamp. tenant: type: string format: uuid description: Tenant UUID scoped from the request context. performed_by_user_name: type: - string - "null" description: Concatenated user name from the joined users table. required: - history_id - asset_id - maintenance_type - performed_by - performed_at - created_at - tenant AssetMaintenanceHistoryPayload: type: object properties: data: type: array items: $ref: "#/components/schemas/AssetMaintenanceHistoryResource" description: Maintenance history rows ordered by performed_at descending. _links: type: object properties: self: $ref: "#/components/schemas/HateoasLink" schedules: $ref: "#/components/schemas/HateoasLink" parent: $ref: "#/components/schemas/HateoasLink" description: History links. The controller currently points these at /api/v2/assets paths. required: - data - _links AssetMaintenanceHistoryResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetMaintenanceHistoryPayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetRecordMaintenanceRequest: type: object properties: schedule_id: type: string format: uuid description: Optional maintenance schedule UUID. If present and found for the tenant, the schedule last_maintenance and next_maintenance are updated. maintenance_type: type: string enum: - preventive - corrective - inspection - calibration - replacement description: Required type of maintenance performed. performed_by: type: string format: uuid description: Required UUID of the user who performed maintenance. The service does not validate this user before insert. performed_at: type: string format: date-time description: Required timestamp when maintenance was performed. duration_hours: type: number minimum: 0 description: Optional duration in hours. cost: type: number minimum: 0 description: Optional cost. notes: type: string description: Optional notes. parts_used: type: array items: type: string description: Optional list of parts used. maintenance_data: type: object additionalProperties: {} description: Optional structured maintenance data. required: - maintenance_type - performed_by - performed_at AssetRecordMaintenancePayload: type: object properties: data: allOf: - $ref: "#/components/schemas/AssetMaintenanceHistoryResource" - description: Inserted asset_maintenance_history row returned from the database. required: - data AssetRecordMaintenanceResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetRecordMaintenancePayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetRelationshipCreateRequest: type: object properties: related_asset_id: type: string format: uuid description: Related asset UUID from assets.asset_id. relationship_type: type: string minLength: 1 description: Free-form relationship type. Must be non-empty. required: - related_asset_id - relationship_type AssetRelationshipRow: type: object properties: relationship_id: type: string format: uuid description: Primary key from asset_relationships.relationship_id. asset_id: type: string format: uuid description: Source asset UUID from asset_relationships.asset_id. related_asset_id: type: string format: uuid description: Related asset UUID from asset_relationships.related_asset_id. relationship_type: type: string description: Free-form relationship type. tenant: type: string format: uuid description: Tenant UUID from asset_relationships.tenant. created_at: type: string format: date-time description: Relationship creation timestamp. asset_tag: type: string description: Related asset tag from joined related_assets, present in list responses. related_asset_name: type: string description: Related asset name from joined related_assets, present in list responses. asset_type: type: string enum: *a2 description: Related asset type from joined related_assets, present in list responses. status: type: string description: Related asset status from joined related_assets, present in list responses. required: - relationship_id - asset_id - related_asset_id - relationship_type - tenant AssetRelationshipListPayload: type: object properties: data: type: array items: $ref: "#/components/schemas/AssetRelationshipRow" description: Relationship rows for the asset. Empty when no relationships exist or the asset is not found. _links: type: object properties: self: $ref: "#/components/schemas/HateoasLink" create: $ref: "#/components/schemas/HateoasLink" parent: $ref: "#/components/schemas/HateoasLink" description: Relationship links. The controller currently points these at /api/v2/assets paths. required: - data - _links AssetRelationshipListResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetRelationshipListPayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetRelationshipPayload: type: object properties: data: allOf: - $ref: "#/components/schemas/AssetRelationshipRow" - description: Inserted asset_relationships row returned from the database. required: - data AssetRelationshipResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetRelationshipPayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetSearchQuery: type: object properties: query: type: string minLength: 1 description: Required search term used in ILIKE clauses. fields: type: array items: type: string enum: &a45 - asset_tag - name - serial_number - location - client_name description: Search fields. If omitted, the service searches asset_tag, name, serial_number, and location. asset_types: type: array items: type: string enum: *a2 description: Optional asset type filters. statuses: type: array items: type: string description: Optional status filters. client_ids: type: array items: type: string format: uuid description: Optional client UUID filters. include_extension_data: type: string enum: &a46 - "true" - "false" description: When true, the service fetches asset-type-specific extension data for every result. limit: type: string description: Maximum result count as a query string. Must parse to 1 through 100; defaults to 25. required: - query AssetSearchPayload: type: object properties: data: type: array items: $ref: "#/components/schemas/AssetResource" description: Matching assets with HATEOAS links. _links: type: object properties: self: $ref: "#/components/schemas/HateoasLink" description: Search collection link. The controller currently points this at /api/v2/assets/search. required: - data - _links AssetSearchResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetSearchPayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetStatsPayload: type: object properties: data: type: object properties: total_assets: type: integer description: Total asset count for the tenant. assets_added_this_month: type: integer description: Count of assets created since the start of the current month. average_asset_age_days: type: - integer - "null" description: Rounded average age in days from purchase_date, or null when unavailable. total_asset_value: type: number description: Sum of purchase_price values, treating null as zero. assets_by_type: type: object additionalProperties: type: integer description: Counts grouped by assets.asset_type. assets_by_status: type: object additionalProperties: type: integer description: Counts grouped by assets.status. assets_by_client: type: object additionalProperties: type: integer description: Top client counts grouped by clients.client_name. The service limits this grouping to 10 clients. warranty_expiring_soon: type: integer description: Count of warranties ending within 30 days. warranty_expired: type: integer description: Count of warranties already expired. maintenance_due: type: integer description: Count of active maintenance schedules with next_maintenance due now or earlier. maintenance_overdue: type: integer description: Count of active maintenance schedules overdue by more than seven days. required: - total_assets - assets_added_this_month - average_asset_age_days - total_asset_value - assets_by_type - assets_by_status - assets_by_client - warranty_expiring_soon - warranty_expired - maintenance_due - maintenance_overdue _links: type: object properties: self: $ref: "#/components/schemas/HateoasLink" assets: $ref: "#/components/schemas/HateoasLink" description: Stats links. The controller currently points these at /api/v2/assets paths. required: - data - _links AssetStatsResponse: type: object properties: success: type: boolean enum: - true data: $ref: "#/components/schemas/AssetStatsPayload" meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta AssetTicketRow: type: object properties: ticket_id: type: string format: uuid description: Ticket UUID from tickets.ticket_id. ticket_number: type: string description: Human-readable ticket number from tickets.ticket_number. title: type: - string - "null" description: Ticket title. status_id: type: - string - "null" format: uuid description: Status UUID from tickets.status_id. status_name: type: - string - "null" description: Status name from the joined statuses table. is_closed: type: - boolean - "null" description: Whether the ticket is closed. priority_id: type: - string - "null" format: uuid description: Priority UUID from tickets.priority_id. assigned_to: type: - string - "null" format: uuid description: Assigned user UUID from tickets.assigned_to. client_id: type: - string - "null" format: uuid description: Client UUID from tickets.client_id. board_id: type: - string - "null" format: uuid description: Board UUID from tickets.board_id. entered_at: type: - string - "null" description: Ticket creation timestamp. updated_at: type: - string - "null" description: Ticket last update timestamp. relationship_type: type: string description: Association type from asset_associations.relationship_type (e.g. affected, related). association_notes: type: - string - "null" description: Optional notes from asset_associations.notes. linked_at: type: - string - "null" description: When the asset was linked to the ticket, from asset_associations.created_at. required: - ticket_id - ticket_number - relationship_type AssetTicketListResponse: type: object properties: success: type: boolean enum: - true data: type: array items: $ref: "#/components/schemas/AssetTicketRow" description: Tickets linked to the asset via asset_associations, ordered by ticket updated_at descending. Empty when no associations exist or the asset is not found. meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta TicketAssetRow: allOf: - $ref: "#/components/schemas/AssetResource" - type: object properties: relationship_type: type: string description: Association type from asset_associations.relationship_type (e.g. affected, related). association_notes: type: - string - "null" description: Optional notes from asset_associations.notes. linked_at: type: - string - "null" description: When the asset was linked to the ticket, from asset_associations.created_at. required: - relationship_type TicketAssetListResponse: type: object properties: data: type: array items: $ref: "#/components/schemas/TicketAssetRow" description: Assets linked to the ticket via asset_associations, ordered by link time descending. Empty when no associations exist or the ticket is not found. meta: type: object additionalProperties: {} required: - data AssetAssociationRow: type: object properties: tenant: type: string format: uuid description: Tenant UUID from asset_associations.tenant. asset_id: type: string format: uuid description: Asset UUID from asset_associations.asset_id. entity_id: type: string format: uuid description: Linked entity UUID — the ticket_id, from asset_associations.entity_id. entity_type: type: string enum: - ticket description: Always 'ticket' for these endpoints. relationship_type: type: string description: Association type from asset_associations.relationship_type (defaults to affected). notes: type: - string - "null" description: Optional notes from asset_associations.notes. created_by: type: string format: uuid description: Creator user UUID from asset_associations.created_by. created_at: type: string description: Link creation timestamp from asset_associations.created_at. required: - tenant - asset_id - entity_id - entity_type - relationship_type - created_by - created_at AssetTicketLinkRequest: type: object properties: ticket_id: type: string format: uuid description: Ticket UUID to link to the asset. relationship_type: type: string minLength: 1 description: Optional association type; defaults to affected. notes: type: string description: Optional notes stored on asset_associations.notes. required: - ticket_id TicketAssetLinkRequest: type: object properties: asset_id: type: string format: uuid description: Asset UUID to link to the ticket. relationship_type: type: string minLength: 1 description: Optional association type; defaults to affected. notes: type: string description: Optional notes stored on asset_associations.notes. required: - asset_id AssetTicketLinkResponse: type: object properties: success: type: boolean enum: - true data: allOf: - $ref: "#/components/schemas/AssetAssociationRow" - description: The inserted asset_associations row. meta: $ref: "#/components/schemas/ApiResponseMeta" required: - success - data - meta TicketAssetLinkResponse: type: object properties: data: allOf: - $ref: "#/components/schemas/AssetAssociationRow" - description: The inserted asset_associations row. meta: type: object additionalProperties: {} required: - data AssetTicketLinkParams: type: object properties: id: type: string format: uuid description: Asset UUID from assets.asset_id. ticketId: type: string format: uuid description: Ticket UUID from tickets.ticket_id. required: - id - ticketId TicketAssetLinkParams: type: object properties: id: type: string format: uuid description: Ticket UUID from tickets.ticket_id. assetId: type: string format: uuid description: Asset UUID from assets.asset_id. required: - id - assetId AssetNotesResponse: type: object properties: document: type: - object - "null" additionalProperties: {} blockData: description: Parsed BlockNote JSON, or null when no notes exist. lastUpdated: type: - string - "null" AssetNotesUpdateBody: type: object properties: blockData: description: BlockNote JSON block data to store as the asset notes. AssetRmmResponse: type: object properties: data: type: - object - "null" additionalProperties: {} description: Cached RMM device data, or null (always null on Community Edition). required: - data AssetRmmActionResponse: type: object properties: success: type: boolean message: type: string jobId: type: string description: Provider job id when the action was queued (EE). required: - success - message AssetRemoteControlResponse: type: - object - "null" properties: url: type: string type: type: string description: Remote-control session URL, or null when unavailable (always null on Community Edition). AssetRmmScriptBody: type: object properties: scriptId: type: string description: Provider script identifier to run on the device. required: - scriptId AssetRemoteControlQuery: type: object properties: type: type: string enum: &a47 - splashtop - teamviewer - vnc - rdp - shell description: Remote-control protocol (default splashtop). AssetSoftwareQuery: type: object properties: page: type: integer minimum: 1 limit: type: integer minimum: 1 maximum: 200 category: type: string software_type: type: string search: type: string include_uninstalled: type: string enum: &a48 - "true" - "false" AssetSoftwareResponse: type: object properties: data: type: array items: type: object additionalProperties: {} summary: type: object additionalProperties: {} pagination: type: object additionalProperties: {} required: - data AssetSummaryResponse: type: object properties: health_status: type: string enum: - healthy - warning - critical - unknown health_reason: type: string security_status: type: string enum: - secure - at_risk - critical security_issues: type: array items: type: string warranty_status: type: string enum: - no_warranty - expired - expiring_soon - active warranty_days_remaining: type: - number - "null" open_tickets_count: type: number AutomationExecutionParams: type: object properties: id: type: string format: uuid description: Automation execution UUID from automation_executions.execution_id. required: - id AutomationRuleParams: type: object properties: id: type: string format: uuid description: Automation rule UUID from automation_rules.rule_id. required: - id AutomationTemplateParams: type: object properties: id: type: string format: uuid description: Automation template UUID from automation_templates.template_id. required: - id AutomationExecutionsListQuery: type: object properties: page: type: string description: Page number as a query string. Defaults to 1. limit: type: string description: Page size as a query string. Must parse to 1 through 100; defaults to 25. sort: type: string description: Accepted by shared list query validation; the service currently orders executions by started_at desc. order: type: string enum: &a49 - asc - desc description: Accepted by shared list query validation. search: type: string description: Accepted by shared filter validation. created_from: type: string format: date-time description: Accepted by shared filter validation. created_to: type: string format: date-time description: Accepted by shared filter validation. updated_from: type: string format: date-time description: Accepted by shared filter validation. updated_to: type: string format: date-time description: Accepted by shared filter validation. is_active: type: string enum: &a50 - "true" - "false" description: Accepted by shared filter validation and transformed to boolean. automation_rule_id: type: string format: uuid description: Filter executions by parent automation rule UUID. status: type: string enum: &a4 - pending - running - completed - failed - cancelled - timeout - skipped description: Filter by execution status. started_from: type: string format: date-time description: Filter executions started at or after this timestamp. started_to: type: string format: date-time description: Filter executions started at or before this timestamp. duration_min_ms: type: number minimum: 0 description: Minimum execution duration in milliseconds. duration_max_ms: type: number minimum: 0 description: Maximum execution duration in milliseconds. has_errors: type: string enum: &a51 - "true" - "false" description: Filter by whether the execution has errors; transformed to boolean by validation. trigger_type: type: string enum: &a3 - time_based - event_based - condition_based - manual - recurring - webhook description: Filter by automation trigger type. AutomationRulesListQuery: type: object properties: page: type: string description: Page number as a query string. Defaults to 1. limit: type: string description: Page size as a query string. Must parse to 1 through 100; defaults to 25. sort: type: string description: Accepted by shared list query validation; service currently orders rules by created_at desc. order: type: string enum: &a52 - asc - desc description: Accepted by shared list query validation. search: type: string description: Accepted by shared filter validation. created_from: type: string format: date-time description: Accepted by shared filter validation. created_to: type: string format: date-time description: Accepted by shared filter validation. updated_from: type: string format: date-time description: Accepted by shared filter validation. updated_to: type: string format: date-time description: Accepted by shared filter validation. is_active: type: string enum: &a53 - "true" - "false" description: Accepted by shared filter validation and transformed to boolean. name: type: string description: Optional rule name filter. status: type: string enum: &a6 - active - inactive - draft - error description: Filter by automation rule status. trigger_type: type: string enum: *a3 description: Filter by trigger type. priority: type: string enum: &a7 - low - normal - high - critical description: Filter by priority level. template_category: type: string description: Filter template category. created_by: type: string format: uuid description: Filter by creator user UUID from automation_rules.created_by. last_executed_from: type: string format: date-time description: Filter for rules last executed at or after timestamp. last_executed_to: type: string format: date-time description: Filter for rules last executed at or before timestamp. execution_count_min: type: integer minimum: 0 description: Minimum execution count filter. execution_count_max: type: integer minimum: 0 description: Maximum execution count filter. AutomationTemplatesListQuery: type: object properties: page: type: string description: Page number as a query string. Defaults to 1. limit: type: string description: Page size as a query string. Must parse to 1 through 100; defaults to 25. sort: type: string description: Accepted by shared list query validation; service currently orders templates by created_at desc. order: type: string enum: &a54 - asc - desc description: Accepted by shared list query validation. search: type: string description: Accepted by shared filter validation. created_from: type: string format: date-time description: Accepted by shared filter validation. created_to: type: string format: date-time description: Accepted by shared filter validation. updated_from: type: string format: date-time description: Accepted by shared filter validation. updated_to: type: string format: date-time description: Accepted by shared filter validation. is_active: type: string enum: &a55 - "true" - "false" description: Accepted by shared filter validation and transformed to boolean. category: type: string description: Filter templates by category. compatible_version: type: string description: Filter templates by compatibility version tag. author: type: string description: Filter templates by author/user id value saved on the template. usage_count_min: type: integer minimum: 0 description: Minimum usage_count filter. usage_count_max: type: integer minimum: 0 description: Maximum usage_count filter. AutomationPerformanceQuery: type: object properties: date_from: type: string format: date-time description: Optional lower bound for performance window. date_to: type: string format: date-time description: Optional upper bound for performance window. group_by: type: string enum: &a56 - hour - day - week - month description: Aggregation bucket size; defaults to day. rule_ids: type: string description: Raw query value copied from URL. The controller expects an array UUID schema but validateQueryParams passes string values, so array filters currently require custom caller-side encoding or fail validation. metrics: type: string description: Raw query value copied from URL. The controller expects an array enum schema but validateQueryParams passes string values, so array filters currently require custom caller-side encoding or fail validation. AutomationExecutionLogEntry: type: object properties: timestamp: type: string format: date-time description: Log timestamp. level: type: string enum: - debug - info - warn - error description: Log level. message: type: string description: Log message. action_index: type: integer description: Optional action index that produced the log. metadata: type: object additionalProperties: {} description: Optional structured log metadata. required: - level - message AutomationLinks: type: object additionalProperties: {} description: HATEOAS links generated by the automation controller. Some generic links may point to methods not implemented by a route file. AutomationExecution: type: object properties: execution_id: type: string format: uuid description: Execution UUID generated with crypto.randomUUID when the execution is created. automation_rule_id: type: string format: uuid description: Parent automation rule UUID. trigger_data: type: object additionalProperties: {} description: Trigger payload captured when execution started. status: type: string enum: *a4 description: Current execution status. started_at: type: string format: date-time description: Timestamp when execution started. completed_at: type: - string - "null" format: date-time description: Timestamp when execution completed. duration_ms: type: - number - "null" minimum: 0 description: Execution duration in milliseconds. actions_total: type: integer minimum: 0 description: Number of actions planned for this execution. actions_successful: type: integer minimum: 0 description: Number of actions completed successfully. actions_failed: type: integer minimum: 0 description: Number of actions that failed. error_message: type: - string - "null" description: Top-level error message, when failed. error_stack: type: - string - "null" description: Error stack, when captured. failed_action_index: type: - integer - "null" description: Index of failed action, when applicable. execution_context: type: object additionalProperties: {} description: Execution context data. logs: type: array items: $ref: "#/components/schemas/AutomationExecutionLogEntry" description: Execution log entries. tenant: type: string format: uuid description: Tenant UUID scoped from the API key context. _links: $ref: "#/components/schemas/AutomationLinks" required: - execution_id - automation_rule_id - status - actions_total - actions_successful - actions_failed - tenant AutomationPagination: type: object properties: page: type: integer description: Current page number. limit: type: integer description: Page size. total: type: integer description: Total matching executions. totalPages: type: integer description: Total page count. hasNext: type: boolean description: Whether another page exists. hasPrev: type: boolean description: Whether a previous page exists. required: - page - limit - total - totalPages - hasNext - hasPrev AutomationExecutionListResponse: type: object properties: data: type: array items: $ref: "#/components/schemas/AutomationExecution" description: Automation execution rows. Current service code wraps the DB result array in another array; this schema documents the intended flat shape returned by createPaginatedResponse. pagination: $ref: "#/components/schemas/AutomationPagination" meta: type: object properties: filters: type: object additionalProperties: {} description: Validated filters echoed by the controller. resource: type: string enum: - automation_execution description: Resource name supplied by the controller. required: - data - pagination AutomationExecutionResponse: type: object properties: data: $ref: "#/components/schemas/AutomationExecution" required: - data AutomationErrorResponse: type: object properties: error: type: object properties: code: type: string description: Machine-readable error code, such as UNAUTHORIZED, FORBIDDEN, VALIDATION_ERROR, or INTERNAL_ERROR. message: type: string description: Human-readable error message. details: description: Optional structured error details. required: - code - message required: - error AutomationMetaResponse: type: object properties: data: type: object properties: trigger_types: type: array items: type: string enum: *a3 description: Valid automation trigger types. action_types: type: array items: type: string enum: &a5 - email_notification - sms_notification - webhook_call - database_update - ticket_creation - ticket_update - project_update - time_entry_creation - invoice_generation - custom_script - workflow_execution - system_command description: Valid automation action types. rule_statuses: type: array items: type: string enum: - active - inactive - draft - error description: Valid automation rule statuses. execution_statuses: type: array items: type: string enum: *a4 description: Valid automation execution statuses. priority_levels: type: array items: type: string enum: - low - normal - high - critical description: Valid automation priority levels. condition_operators: type: array items: type: string enum: - equals - not_equals - greater_than - less_than - greater_than_or_equal - less_than_or_equal - contains - not_contains - starts_with - ends_with - in - not_in - exists - not_exists - regex_match description: Valid condition operators. required: - trigger_types - action_types - rule_statuses - execution_statuses - priority_levels - condition_operators required: - data AutomationRuleCondition: type: object properties: field: type: string description: Field path evaluated for this condition. operator: type: string enum: - equals - not_equals - greater_than - less_than - greater_than_or_equal - less_than_or_equal - contains - not_contains - starts_with - ends_with - in - not_in - exists - not_exists - regex_match value: description: Condition comparison value. data_type: type: string enum: - string - number - boolean - date - array - object required: - field - operator AutomationRuleAction: type: object properties: type: type: string enum: *a5 description: Automation action type. config: type: object additionalProperties: {} description: Action configuration object. Expected keys depend on action type. order: type: integer minimum: 1 description: Execution order (1-based). continue_on_error: type: boolean description: Continue execution after a failed action. timeout_seconds: type: integer minimum: 1 description: Optional per-action timeout in seconds. retry_attempts: type: integer minimum: 0 maximum: 5 description: Optional retry count for this action. required: - type - config - order AutomationNotificationSettings: type: object properties: notify_on_success: type: boolean notify_on_failure: type: boolean notification_emails: type: array items: type: string format: email notification_webhooks: type: array items: type: string format: uri AutomationRule: type: object properties: rule_id: type: string format: uuid description: Rule UUID generated with crypto.randomUUID when a rule is created. tenant: type: string format: uuid description: Tenant UUID scoped from API key authentication. name: type: string description: Rule display name. description: type: - string - "null" status: type: string enum: *a6 description: Current automation rule status. priority: type: string enum: *a7 description: Current automation rule priority. trigger_type: type: string enum: *a3 description: Trigger type used to start rule execution. trigger_config: type: object additionalProperties: {} description: Trigger configuration object stored with the rule. conditions: type: array items: $ref: "#/components/schemas/AutomationRuleCondition" description: Optional additional rule conditions. condition_logic: type: string enum: - and - or description: Condition combination logic. actions: type: array items: $ref: "#/components/schemas/AutomationRuleAction" description: Ordered action list for this rule. max_concurrent_executions: type: integer minimum: 1 execution_timeout_minutes: type: integer minimum: 1 retry_failed_executions: type: boolean is_template: type: boolean template_category: type: - string - "null" tags: type: array items: type: string metadata: type: object additionalProperties: {} notification_settings: $ref: "#/components/schemas/AutomationNotificationSettings" created_by: type: - string - "null" format: uuid description: User UUID from API key context that created the rule. created_at: type: string format: date-time updated_at: type: string format: date-time execution_count: type: integer minimum: 0 last_executed: type: - string - "null" format: date-time execution_statistics: type: object additionalProperties: {} description: Included on GET /rules/{id} by service lookup helper. _links: $ref: "#/components/schemas/AutomationLinks" required: - rule_id - tenant - name - status - priority - trigger_type - trigger_config - actions CreateAutomationRuleRequest: type: object properties: name: type: string minLength: 1 maxLength: 255 description: type: string status: type: string enum: *a6 description: Defaults to draft when omitted. priority: type: string enum: *a7 description: Defaults to normal when omitted. trigger_type: type: string enum: *a3 trigger_config: type: object additionalProperties: {} description: Trigger-type-specific configuration object. conditions: type: array items: $ref: "#/components/schemas/AutomationRuleCondition" condition_logic: type: string enum: &a8 - and - or actions: type: array items: $ref: "#/components/schemas/AutomationRuleAction" minItems: 1 max_concurrent_executions: type: integer minimum: 1 execution_timeout_minutes: type: integer minimum: 1 retry_failed_executions: type: boolean is_template: type: boolean template_category: type: string tags: type: array items: type: string metadata: type: object additionalProperties: {} notification_settings: $ref: "#/components/schemas/AutomationNotificationSettings" required: - name - trigger_type - trigger_config - actions UpdateAutomationRuleRequest: type: object properties: name: type: string minLength: 1 maxLength: 255 description: type: string status: type: string enum: *a6 description: Defaults to draft when omitted. priority: type: string enum: *a7 description: Defaults to normal when omitted. trigger_type: type: string enum: *a3 trigger_config: type: object additionalProperties: {} description: Trigger-type-specific configuration object. conditions: type: array items: $ref: "#/components/schemas/AutomationRuleCondition" condition_logic: type: string enum: *a8 actions: type: array items: $ref: "#/components/schemas/AutomationRuleAction" minItems: 1 max_concurrent_executions: type: integer minimum: 1 execution_timeout_minutes: type: integer minimum: 1 retry_failed_executions: type: boolean is_template: type: boolean template_category: type: string tags: type: array items: type: string metadata: type: object additionalProperties: {} notification_settings: $ref: "#/components/schemas/AutomationNotificationSettings" ManualExecutionRequest: type: object properties: automation_rule_id: type: string format: uuid description: Required by current validation schema but ignored by controller/service, which execute the path rule ID. execution_data: type: object additionalProperties: {} override_conditions: type: boolean description: Set true to allow execution of inactive rules. dry_run: type: boolean description: When true, returns a completed execution without queueing actions. required: - automation_rule_id BulkStatusUpdateRequest: type: object properties: ids: type: array items: type: string format: uuid minItems: 1 maxItems: 100 description: Rule UUIDs from automation_rules.rule_id. status: type: string enum: *a6 description: Status to apply to each provided rule id. required: - ids - status BulkExecuteRequest: type: object properties: automation_rule_ids: type: array items: type: string format: uuid minItems: 1 maxItems: 20 description: Rule UUIDs to execute. execution_data: type: object additionalProperties: {} description: Optional shared execution payload for each run. override_conditions: type: boolean description: Allow execution of inactive rules when true. sequential_execution: type: boolean description: When true, executes rules sequentially; otherwise Promise.all is used. required: - automation_rule_ids AutomationTemplateVariable: type: object properties: name: type: string display_name: type: string description: type: string type: type: string enum: - string - number - boolean - date - select - multiselect required: type: boolean default_value: {} options: type: array items: type: object properties: label: type: string value: {} required: - label validation: type: object properties: min: type: number max: type: number pattern: type: string custom_validator: type: string required: - name - type AutomationTemplate: type: object properties: template_id: type: string format: uuid description: Template UUID generated with crypto.randomUUID. name: type: string description: type: - string - "null" category: type: string icon: type: - string - "null" template_config: type: object additionalProperties: {} description: Template rule blueprint derived from an automation rule. version: type: string author: type: - string - "null" compatible_versions: type: array items: type: string required_permissions: type: array items: type: string usage_count: type: integer minimum: 0 last_used: type: - string - "null" format: date-time template_variables: type: array items: $ref: "#/components/schemas/AutomationTemplateVariable" is_active: type: boolean is_featured: type: boolean tenant: type: string format: uuid _links: $ref: "#/components/schemas/AutomationLinks" required: - template_id - name - category - template_config - tenant CreateAutomationTemplateRequest: type: object properties: automation_rule_id: type: string format: uuid description: Source automation_rules.rule_id copied into template_config. template_name: type: string minLength: 1 maxLength: 255 template_description: type: string category: type: string minLength: 1 template_variables: type: array items: type: object properties: rule_field_path: type: string minLength: 1 variable_name: type: string minLength: 1 display_name: type: string minLength: 1 description: type: string type: type: string enum: - string - number - boolean - date - select - multiselect required: type: boolean required: - rule_field_path - variable_name - display_name - type required: - automation_rule_id - template_name - category UseAutomationTemplateRequest: type: object properties: variables: type: object additionalProperties: {} description: Optional variable substitutions applied to template_config before creating a new automation rule. AutomationRuleResponse: type: object properties: data: $ref: "#/components/schemas/AutomationRule" required: - data AutomationRuleListResponse: type: object properties: data: type: array items: $ref: "#/components/schemas/AutomationRule" pagination: $ref: "#/components/schemas/AutomationPagination" meta: type: object properties: filters: type: object additionalProperties: {} resource: type: string enum: - automation_rule required: - data - pagination AutomationTemplateResponse: type: object properties: data: $ref: "#/components/schemas/AutomationTemplate" required: - data AutomationTemplateListResponse: type: object properties: data: type: array items: $ref: "#/components/schemas/AutomationTemplate" description: Template rows. Current service code wraps the DB result array in another array before createPaginatedResponse, which can produce nested data in practice. pagination: $ref: "#/components/schemas/AutomationPagination" meta: type: object properties: filters: type: object additionalProperties: {} resource: type: string enum: - automation_template required: - data - pagination AutomationStatisticsResponse: type: object properties: data: type: object properties: total_rules: type: integer minimum: 0 active_rules: type: integer minimum: 0 inactive_rules: type: integer minimum: 0 draft_rules: type: integer minimum: 0 error_rules: type: integer minimum: 0 total_executions: type: integer minimum: 0 successful_executions: type: integer minimum: 0 failed_executions: type: integer minimum: 0 executions_today: type: integer minimum: 0 executions_this_week: type: integer minimum: 0 executions_this_month: type: integer minimum: 0 avg_execution_time_ms: type: number minimum: 0 success_rate_percent: type: number minimum: 0 maximum: 100 _links: type: object properties: self: type: string enum: - /api/v1/automation/statistics rules: type: string enum: - /api/v1/automation/rules executions: type: string enum: - /api/v1/automation/executions templates: type: string enum: - /api/v1/automation/templates performance: type: string enum: - /api/v1/automation/performance required: - self - rules - executions - templates - performance required: - total_rules - active_rules - inactive_rules - draft_rules - error_rules - total_executions - successful_executions - failed_executions - executions_today - executions_this_week - executions_this_month required: - data AutomationPerformanceResponse: type: object properties: data: allOf: - type: object additionalProperties: {} - type: object properties: _links: type: object properties: self: type: string enum: - /api/v1/automation/performance statistics: type: string enum: - /api/v1/automation/statistics required: - self - statistics description: Performance payload from AutomationService.calculatePerformanceMetrics plus links. required: - data BulkStatusUpdateResponse: type: object properties: data: type: object properties: action: type: string enum: - bulk_status_update status: type: string enum: *a6 rule_ids: type: array items: type: string format: uuid updated: type: integer minimum: 0 errors: type: array items: type: string description: "Per-rule failures emitted as `: ` entries." message: type: string required: - action - status - rule_ids - updated - errors - message required: - data BulkExecuteResponse: type: object properties: data: type: object properties: action: type: string enum: - bulk_execute rule_ids: type: array items: type: string format: uuid started: type: integer minimum: 0 errors: type: array items: type: string description: "Per-rule failures emitted as `: ` entries." sequential: type: boolean message: type: string required: - action - rule_ids - started - errors - message required: - data LicenceCountHeaders: type: object properties: x-webhook-signature: type: string description: HMAC-SHA256 hex digest proving the caller knows ALGA_WEBHOOK_SECRET. required: - x-webhook-signature LicenceCountQuery: type: object properties: tenant_id: type: string description: Tenant identifier to query. This must match a tenants.tenant record. required: - tenant_id LicenceUsageResponse: type: object properties: tenant_id: type: string description: Echoed tenant identifier from the request. limit: type: - integer - "null" description: Licensed internal-user count from tenants.licensed_user_count. Null means unlimited. used: type: integer description: Count of active internal users where users.user_type is internal and is_inactive is false. remaining: type: - integer - "null" description: Calculated remaining seats as max(0, limit - used), or null when limit is unlimited. last_updated: type: - string - "null" description: ISO timestamp from tenants.last_license_update, or null if no license update has been recorded. required: - tenant_id - limit - used - remaining - last_updated LicenceCountUpdateRequest: type: object properties: tenant_id: type: string description: Tenant identifier from tenants.tenant whose licensed user count should be updated. license_count: type: integer minimum: 0 description: Licensed internal-user count from the Stripe subscription quantity. event_id: type: string description: Stripe webhook event ID. When supplied, the handler uses tenants.stripe_event_id for idempotency. required: - tenant_id - license_count LicenceCountUpdateResponse: type: object properties: success: type: boolean enum: - true description: Indicates the license count update was accepted. tenant_id: type: string description: Echoed tenant identifier that was updated. license_count: type: integer description: Echoed licensed user count that was written. updated_at: type: string format: date-time description: ISO timestamp generated by the handler for this response. required: - success - tenant_id - license_count - updated_at LicenceCountErrorResponse: type: object properties: error: type: string description: Human-readable error message. required: - error ChatMessage: type: object properties: role: type: string enum: - user - assistant description: Role of the message author in the conversation. content: type: string description: Message text sent to the chat model. required: - role - content ChatStreamRequest: type: object properties: inputs: type: array items: $ref: "#/components/schemas/ChatMessage" minItems: 1 description: Conversation messages in order. These are passed to the OpenRouter chat model. options: type: object additionalProperties: {} description: Optional model options. Currently declared by the internal interface but not consumed by the handler. model: type: string description: Optional model override. Currently ignored; the server uses OPENROUTER_CHAT_MODEL or minimax/minimax-m2. meta: type: object properties: authorization: type: string description: Optional downstream authorization token. Currently declared but not consumed by the handler. description: Optional metadata for legacy chat clients. required: - inputs ChatTitleStreamRequest: type: object properties: inputs: type: array items: $ref: "#/components/schemas/ChatMessage" minItems: 1 description: Conversation messages used as context for generating a short chat title. required: - inputs ChatStreamEvent: type: object properties: content: type: string description: SSE data payload content. Normal events contain generated text; terminal events may contain [DONE]. type: type: string enum: - text - error description: Event type. text carries model output; error carries an in-stream error message. required: - content ChatStreamError: type: object properties: error: type: string description: Human-readable error message. required: - error ChatStreamSlugParams: type: object properties: slug: type: string description: Catch-all chat stream path segment. The current handler accepts the value but does not use it. required: - slug ClientIdParam: type: object properties: id: type: string format: uuid required: - id ContactIdParam: type: object properties: id: type: string format: uuid required: - id ClientContractLineIdParam: type: object properties: id: type: string format: uuid required: - id ClientListQuery: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a57 - asc - desc search: type: string created_from: type: string format: date-time created_to: type: string format: date-time updated_from: type: string format: date-time updated_to: type: string format: date-time client_name: type: string email: type: string client_type: type: string billing_cycle: type: string enum: &a58 - weekly - bi-weekly - monthly - quarterly - semi-annually - annually is_inactive: type: string enum: &a59 - "true" - "false" is_tax_exempt: type: string enum: &a60 - "true" - "false" account_manager_id: type: string format: uuid region_code: type: string credit_balance_min: type: string credit_balance_max: type: string has_credit_limit: type: string enum: &a61 - "true" - "false" industry: type: string company_size: type: string ClientBody: type: object properties: client_name: type: string minLength: 1 maxLength: 255 phone_no: type: string email: type: string format: email url: type: string format: uri address: type: string client_type: type: string tax_id_number: type: string notes: type: string properties: type: object additionalProperties: {} payment_terms: type: string billing_cycle: type: string enum: - weekly - bi-weekly - monthly - quarterly - semi-annually - annually credit_limit: type: number minimum: 0 preferred_payment_method: type: string auto_invoice: type: boolean invoice_delivery_method: type: string enum: - email - mail - portal region_code: type: string is_tax_exempt: type: boolean tax_exemption_certificate: type: string timezone: type: string invoice_template_id: type: string format: uuid billing_contact_id: type: string format: uuid billing_email: type: string format: email account_manager_id: type: string format: uuid is_inactive: type: boolean tags: type: array items: type: string required: - client_name - billing_cycle ClientLocationBody: type: object properties: location_name: type: string address_line1: type: string minLength: 1 address_line2: type: string address_line3: type: string city: type: string minLength: 1 state_province: type: string postal_code: type: string country_code: type: string minLength: 2 maxLength: 3 country_name: type: string minLength: 1 region_code: type: string is_billing_address: type: boolean is_shipping_address: type: boolean is_default: type: boolean phone: type: string fax: type: string email: type: string format: email notes: type: string is_active: type: boolean required: - address_line1 - city - country_code - country_name ContactListQuery: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a62 - asc - desc search: type: string created_from: type: string format: date-time created_to: type: string format: date-time updated_from: type: string format: date-time updated_to: type: string format: date-time full_name: type: string email: type: string phone_number: type: string client_id: type: string format: uuid role: type: string is_inactive: type: string enum: &a63 - "true" - "false" has_client: type: string enum: &a64 - "true" - "false" client_name: type: string ContactBody: type: object properties: full_name: type: string minLength: 1 maxLength: 255 client_id: type: string format: uuid phone_numbers: type: array items: type: object additionalProperties: {} email: type: string format: email primary_email_canonical_type: type: - string - "null" primary_email_custom_type: type: - string - "null" primary_email_custom_type_id: type: - string - "null" format: uuid additional_email_addresses: type: array items: type: object additionalProperties: {} role: type: string notes: type: string is_inactive: type: boolean tags: type: array items: type: string required: - full_name - email ContactSearchQuery: type: object properties: query: type: string minLength: 1 fields: type: string description: Comma-separated field list; parsed by contactSearchSchema transform. client_id: type: string format: uuid include_inactive: type: string enum: &a65 - "true" - "false" limit: type: string required: - query ContactExportQuery: type: object properties: format: type: string enum: &a66 - csv - json include_inactive: type: string enum: &a67 - "true" - "false" client_id: type: string format: uuid fields: type: string description: Array schema expects parsed list, but URL values arrive as string. ClientContractLineQuery: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a68 - asc - desc search: type: string created_from: type: string format: date-time created_to: type: string format: date-time updated_from: type: string format: date-time updated_to: type: string format: date-time client_id: type: string format: uuid contract_line_id: type: string format: uuid service_category: type: string is_active: type: string enum: &a69 - "true" - "false" has_custom_rate: type: string enum: &a70 - "true" - "false" is_contractd: type: string enum: &a71 - "true" - "false" start_date_from: type: string format: date-time start_date_to: type: string format: date-time end_date_from: type: string format: date-time end_date_to: type: string format: date-time ClientContractLineBody: type: object properties: client_id: type: string format: uuid contract_line_id: type: string format: uuid service_category: type: string start_date: type: string format: date-time end_date: type: string format: date-time is_active: type: boolean custom_rate: type: number minimum: 0 client_contract_id: type: string format: uuid required: - client_id - contract_line_id - start_date ClientContactApiError: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error ContactResource: type: object properties: contact_name_id: type: string format: uuid full_name: type: string client_id: type: - string - "null" format: uuid email: type: string format: email role: type: - string - "null" created_at: type: string format: date-time updated_at: type: string format: date-time is_inactive: type: boolean tenant: type: string format: uuid phone_numbers: type: array items: type: object properties: contact_phone_number_id: type: string format: uuid phone_number: type: string normalized_phone_number: type: string canonical_type: type: - string - "null" custom_phone_type_id: type: - string - "null" format: uuid custom_type: type: - string - "null" is_default: type: boolean display_order: type: integer minimum: 0 required: - contact_phone_number_id - phone_number - normalized_phone_number - custom_type - is_default - display_order additional_email_addresses: type: array items: type: object properties: contact_additional_email_address_id: type: string format: uuid email_address: type: string format: email normalized_email_address: type: string format: email canonical_type: type: - string - "null" custom_email_type_id: type: - string - "null" format: uuid custom_type: type: - string - "null" display_order: type: integer minimum: 0 required: - contact_additional_email_address_id - email_address - normalized_email_address - custom_type - display_order default_phone_number: type: - string - "null" default_phone_type: type: - string - "null" primary_email_canonical_type: type: - string - "null" primary_email_custom_type_id: type: - string - "null" format: uuid primary_email_type: type: - string - "null" notes: type: - string - "null" avatarUrl: type: - string - "null" tags: type: array items: type: string client_name: type: - string - "null" required: - contact_name_id - full_name - client_id - email - role - created_at - updated_at - is_inactive - tenant ContactStatsResource: type: object properties: total_contacts: type: number active_contacts: type: number inactive_contacts: type: number contacts_with_client: type: number contacts_without_client: type: number contacts_by_role: type: object additionalProperties: type: number recent_contacts: type: number required: - total_contacts - active_contacts - inactive_contacts - contacts_with_client - contacts_without_client - contacts_by_role - recent_contacts ClientContractLineResource: type: object properties: client_contract_line_id: type: string format: uuid client_id: type: string format: uuid contract_line_id: type: string format: uuid service_category: type: - string - "null" start_date: type: string format: date-time end_date: type: - string - "null" format: date-time is_active: type: boolean custom_rate: type: - number - "null" client_contract_id: type: - string - "null" format: uuid tenant: type: string format: uuid required: - client_contract_line_id - client_id - contract_line_id - start_date - is_active ContactExportRow: type: object properties: contact_name_id: type: string format: uuid full_name: type: string email: type: - string - "null" format: email role: type: - string - "null" is_inactive: type: boolean created_at: type: string format: date-time client_name: type: - string - "null" default_phone_number: type: - string - "null" default_phone_type: type: - string - "null" required: - contact_name_id - full_name - email - role - is_inactive - created_at - client_name - default_phone_number - default_phone_type ClientEnvelope: type: object properties: data: type: object properties: client_id: type: string format: uuid client_name: type: string phone_no: type: - string - "null" credit_balance: type: number email: type: - string - "null" url: type: - string - "null" address: type: - string - "null" created_at: type: string format: date-time updated_at: type: string format: date-time is_inactive: type: boolean client_type: type: - string - "null" tax_id_number: type: - string - "null" notes: type: - string - "null" properties: type: object properties: industry: type: string company_size: type: string annual_revenue: type: string primary_contact_id: type: string format: uuid primary_contact_name: type: string status: type: string type: type: string billing_address: type: string tax_id: type: string notes: type: string payment_terms: type: string website: type: string format: uri parent_client_id: type: string format: uuid parent_client_name: type: string last_contact_date: type: string format: date-time logo: type: string payment_terms: type: - string - "null" billing_cycle: type: string enum: &a9 - weekly - bi-weekly - monthly - quarterly - semi-annually - annually credit_limit: type: - number - "null" preferred_payment_method: type: - string - "null" auto_invoice: type: boolean invoice_delivery_method: type: - string - "null" region_code: type: - string - "null" is_tax_exempt: type: boolean tax_exemption_certificate: type: - string - "null" timezone: type: - string - "null" invoice_template_id: type: - string - "null" format: uuid billing_contact_id: type: - string - "null" format: uuid billing_email: type: - string - "null" account_manager_id: type: - string - "null" format: uuid account_manager_full_name: type: - string - "null" logoUrl: type: - string - "null" tenant: type: string format: uuid tags: type: array items: type: string required: - client_id - client_name - phone_no - credit_balance - email - url - address - created_at - updated_at - is_inactive - client_type - tax_id_number - notes - payment_terms - billing_cycle - credit_limit - preferred_payment_method - auto_invoice - invoice_delivery_method - region_code - is_tax_exempt - tax_exemption_certificate - timezone - invoice_template_id - billing_contact_id - billing_email - account_manager_id - tenant meta: type: object additionalProperties: {} required: - data PaginatedClientEnvelope: type: object properties: data: type: array items: type: object properties: client_id: type: string format: uuid client_name: type: string phone_no: type: - string - "null" credit_balance: type: number email: type: - string - "null" url: type: - string - "null" address: type: - string - "null" created_at: type: string format: date-time updated_at: type: string format: date-time is_inactive: type: boolean client_type: type: - string - "null" tax_id_number: type: - string - "null" notes: type: - string - "null" properties: type: object properties: industry: type: string company_size: type: string annual_revenue: type: string primary_contact_id: type: string format: uuid primary_contact_name: type: string status: type: string type: type: string billing_address: type: string tax_id: type: string notes: type: string payment_terms: type: string website: type: string format: uri parent_client_id: type: string format: uuid parent_client_name: type: string last_contact_date: type: string format: date-time logo: type: string payment_terms: type: - string - "null" billing_cycle: type: string enum: *a9 credit_limit: type: - number - "null" preferred_payment_method: type: - string - "null" auto_invoice: type: boolean invoice_delivery_method: type: - string - "null" region_code: type: - string - "null" is_tax_exempt: type: boolean tax_exemption_certificate: type: - string - "null" timezone: type: - string - "null" invoice_template_id: type: - string - "null" format: uuid billing_contact_id: type: - string - "null" format: uuid billing_email: type: - string - "null" account_manager_id: type: - string - "null" format: uuid account_manager_full_name: type: - string - "null" logoUrl: type: - string - "null" tenant: type: string format: uuid tags: type: array items: type: string required: - client_id - client_name - phone_no - credit_balance - email - url - address - created_at - updated_at - is_inactive - client_type - tax_id_number - notes - payment_terms - billing_cycle - credit_limit - preferred_payment_method - auto_invoice - invoice_delivery_method - region_code - is_tax_exempt - tax_exemption_certificate - timezone - invoice_template_id - billing_contact_id - billing_email - account_manager_id - tenant pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination ClientStatsEnvelope: type: object properties: data: type: object properties: total_clients: type: number active_clients: type: number inactive_clients: type: number clients_by_billing_cycle: type: object additionalProperties: type: number clients_by_client_type: type: object additionalProperties: type: number total_credit_balance: type: number average_credit_balance: type: number required: - total_clients - active_clients - inactive_clients - clients_by_billing_cycle - clients_by_client_type - total_credit_balance - average_credit_balance meta: type: object additionalProperties: {} required: - data ClientContactEnvelope: type: object properties: data: $ref: "#/components/schemas/ContactResource" meta: type: object additionalProperties: {} required: - data PaginatedContactEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/ContactResource" pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination ContactSearchEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/ContactResource" meta: type: object additionalProperties: {} required: - data ContactStatsEnvelope: type: object properties: data: $ref: "#/components/schemas/ContactStatsResource" meta: type: object additionalProperties: {} required: - data ClientLocationsEnvelope: type: object properties: data: type: array items: type: object properties: location_id: type: string format: uuid client_id: type: string format: uuid location_name: type: - string - "null" address_line1: type: string address_line2: type: - string - "null" address_line3: type: - string - "null" city: type: string state_province: type: - string - "null" postal_code: type: - string - "null" country_code: type: string country_name: type: string region_code: type: - string - "null" is_billing_address: type: boolean is_shipping_address: type: boolean is_default: type: boolean phone: type: - string - "null" fax: type: - string - "null" email: type: - string - "null" notes: type: - string - "null" is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time tenant: type: string format: uuid required: - location_id - client_id - location_name - address_line1 - address_line2 - address_line3 - city - state_province - postal_code - country_code - country_name - region_code - is_billing_address - is_shipping_address - is_default - phone - fax - email - notes - is_active - created_at - updated_at - tenant meta: type: object additionalProperties: {} required: - data ClientLocationEnvelope: type: object properties: data: type: object properties: location_id: type: string format: uuid client_id: type: string format: uuid location_name: type: - string - "null" address_line1: type: string address_line2: type: - string - "null" address_line3: type: - string - "null" city: type: string state_province: type: - string - "null" postal_code: type: - string - "null" country_code: type: string country_name: type: string region_code: type: - string - "null" is_billing_address: type: boolean is_shipping_address: type: boolean is_default: type: boolean phone: type: - string - "null" fax: type: - string - "null" email: type: - string - "null" notes: type: - string - "null" is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time tenant: type: string format: uuid required: - location_id - client_id - location_name - address_line1 - address_line2 - address_line3 - city - state_province - postal_code - country_code - country_name - region_code - is_billing_address - is_shipping_address - is_default - phone - fax - email - notes - is_active - created_at - updated_at - tenant meta: type: object additionalProperties: {} required: - data ContactExportEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/ContactExportRow" meta: type: object additionalProperties: {} required: - data ClientContractLineListItem: type: object properties: data: type: array items: $ref: "#/components/schemas/ClientContractLineResource" total: type: integer minimum: 0 required: - data - total ClientContractLineListEnvelope: type: object properties: data: $ref: "#/components/schemas/ClientContractLineListItem" meta: type: object additionalProperties: {} required: - data ClientContractLineEnvelope: type: object properties: data: $ref: "#/components/schemas/ClientContractLineResource" meta: type: object additionalProperties: {} required: - data ContractLineIdParam: type: object properties: id: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: - id ContractLineServiceParam: type: object properties: id: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. serviceId: type: string format: uuid description: Service UUID from service_catalog.service_id. required: - id - serviceId ContractLineTemplateParam: type: object properties: id: type: string format: uuid description: Template UUID from plan_templates.template_id. required: - id ContractLineListQuery: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a72 - asc - desc search: type: string created_from: type: string format: date-time created_to: type: string format: date-time updated_from: type: string format: date-time updated_to: type: string format: date-time contract_line_name: type: string contract_line_type: type: string enum: &a11 - Fixed - Hourly - Usage billing_frequency: type: string enum: &a10 - weekly - bi-weekly - monthly - quarterly - semi-annually - annually is_custom: type: string enum: &a73 - "true" - "false" is_active: type: string enum: &a74 - "true" - "false" service_category: type: string has_services: type: string enum: &a75 - "true" - "false" clients_count_min: type: string clients_count_max: type: string revenue_min: type: string revenue_max: type: string include_services: type: string enum: &a76 - "true" - "false" description: Controller-level include flag parsed directly from query string. include_usage: type: string enum: &a77 - "true" - "false" description: Controller-level include flag parsed directly from query string. include_clients: type: string enum: &a78 - "true" - "false" description: Controller-level include flag parsed directly from query string. ContractLineUsageMetricsQuery: type: object properties: period_start: type: string format: date-time description: Defaults to now minus 30 days when omitted. period_end: type: string format: date-time description: Defaults to now when omitted. ContractLineBody: type: object properties: contract_line_name: type: string minLength: 1 maxLength: 255 billing_frequency: type: string enum: *a10 is_custom: type: boolean service_category: type: string contract_line_type: type: string enum: *a11 cadence_owner: type: string enum: &a12 - client - contract hourly_rate: type: number minimum: 0 minimum_billable_time: type: number minimum: 0 round_up_to_nearest: type: number minimum: 1 enable_overtime: type: boolean overtime_rate: type: number minimum: 0 overtime_threshold: type: number minimum: 0 enable_after_hours_rate: type: boolean after_hours_multiplier: type: number minimum: 0 is_active: type: boolean features: type: array items: type: string location_id: type: - string - "null" format: uuid required: - contract_line_name - billing_frequency - contract_line_type UpdateContractLineBody: type: object properties: contract_line_name: type: string minLength: 1 maxLength: 255 billing_frequency: type: string enum: *a10 is_custom: type: boolean service_category: type: string contract_line_type: type: string enum: *a11 cadence_owner: type: string enum: *a12 hourly_rate: type: number minimum: 0 minimum_billable_time: type: number minimum: 0 round_up_to_nearest: type: number minimum: 1 enable_overtime: type: boolean overtime_rate: type: number minimum: 0 overtime_threshold: type: number minimum: 0 enable_after_hours_rate: type: boolean after_hours_multiplier: type: number minimum: 0 is_active: type: boolean features: type: array items: type: string location_id: type: - string - "null" format: uuid ContractLineFixedConfigBody: type: object properties: base_rate: type: number minimum: 0 enable_proration: type: boolean billing_cycle_alignment: type: string enum: - start - end - prorated ContractLineAddServiceBody: type: object properties: service_id: type: string format: uuid quantity: type: number minimum: 1 custom_rate: type: number minimum: 0 configuration_type: type: string enum: &a13 - Fixed - Hourly - Usage - Bucket type_config: type: object additionalProperties: {} required: - service_id ContractLineUpdateServiceBody: type: object properties: quantity: type: number minimum: 1 custom_rate: type: number minimum: 0 type_config: type: object additionalProperties: {} rate_tiers: type: array items: type: object additionalProperties: {} user_type_rates: type: array items: type: object additionalProperties: {} ContractLineActivationBody: type: object properties: is_active: type: boolean effective_date: type: string format: date-time reason: type: string notify_clients: type: boolean required: - is_active CopyContractLineBody: type: object properties: source_contract_line_id: type: string format: uuid description: Used by service; path id is currently ignored. new_contract_line_name: type: string minLength: 1 maxLength: 255 copy_services: type: boolean copy_configurations: type: boolean modify_rates: type: object properties: percentage_change: type: number fixed_adjustment: type: number required: - source_contract_line_id - new_contract_line_name BulkCreateContractLinesBody: type: object properties: plans: type: array items: $ref: "#/components/schemas/ContractLineBody" minItems: 1 maxItems: 50 required: - plans BulkUpdateContractLinesBody: type: object properties: plans: type: array items: type: object properties: contract_line_id: type: string format: uuid data: $ref: "#/components/schemas/UpdateContractLineBody" required: - contract_line_id - data minItems: 1 maxItems: 50 required: - plans BulkDeleteContractLinesBody: type: object properties: contract_line_ids: type: array items: type: string format: uuid minItems: 1 maxItems: 50 required: - contract_line_ids BulkAddServicesBody: type: object properties: contract_line_id: type: string format: uuid services: type: array items: $ref: "#/components/schemas/ContractLineAddServiceBody" minItems: 1 maxItems: 20 required: - contract_line_id - services BulkRemoveServicesBody: type: object properties: contract_line_id: type: string format: uuid service_ids: type: array items: type: string format: uuid minItems: 1 maxItems: 20 required: - contract_line_id - service_ids CreateContractLineTemplateBody: type: object properties: template_name: type: string minLength: 1 maxLength: 255 template_description: type: string contract_line_type: type: string enum: *a11 billing_frequency: type: string enum: *a10 default_services: type: array items: type: object properties: service_id: type: string format: uuid configuration_type: type: string enum: *a13 default_rate: type: number minimum: 0 quantity: type: number minimum: 1 required: - service_id - configuration_type is_public: type: boolean required: - template_name - contract_line_type - billing_frequency CreateContractLineFromTemplateBody: type: object properties: template_id: type: string format: uuid description: Optional; the template id is taken from the path {id} and overrides this field when both are present. contract_line_name: type: string minLength: 1 maxLength: 255 modify_rates: type: object properties: percentage_change: type: number fixed_adjustment: type: number override_services: type: array items: type: object properties: service_id: type: string format: uuid custom_rate: type: number minimum: 0 quantity: type: number minimum: 1 required: - service_id required: - contract_line_name ContractLineApiSuccess: type: object properties: success: type: boolean enum: - true data: anyOf: - type: object additionalProperties: {} - type: array items: type: object additionalProperties: {} meta: type: object properties: timestamp: type: string format: date-time version: type: string required: - timestamp - version required: - success - data ContractLineApiError: type: object properties: success: type: boolean enum: - false error: type: object properties: message: type: string code: type: string details: {} required: - message - code meta: type: object properties: timestamp: type: string format: date-time version: type: string required: - timestamp - version required: - success - error DocumentDownloadParams: type: object properties: fileId: type: string format: uuid description: Document UUID or file UUID. The download handler resolves document_id first, then file_id. required: - fileId DocumentFileIdParams: type: object properties: fileId: type: string format: uuid description: File UUID from external_files.file_id identifying the stored file to serve. required: - fileId DocumentIdDownloadParams: type: object properties: documentId: type: string format: uuid description: Document UUID from documents.document_id, or file UUID from documents.file_id. The handler resolves document_id first and falls back to file_id. required: - documentId DocumentIdDownloadHeaders: type: object properties: x-api-key: type: string description: Optional API key for machine-to-machine download requests. Used only when no valid Auth.js session cookie is present. DocumentDownloadQuery: type: object properties: format: type: string enum: &a79 - pdf - markdown - md description: Optional export format. pdf generates a PDF; markdown or md exports markdown; omitted downloads the original stored file. DocumentViewHeaders: type: object properties: range: type: string description: HTTP Range header for partial video responses, for example bytes=0-1048575. Only honored for video/* files. x-api-key: type: string description: Optional API key fallback for non-browser clients. Used only when no valid session cookie is present. BinaryFileResponse: type: string description: Binary file bytes streamed from the storage provider. MarkdownFileResponse: type: string description: Markdown export text generated from document content. DocumentDownloadError: type: object properties: error: type: string description: Human-readable error message. permissionError: type: string description: Permission-denied message returned by the underlying document action in some RBAC failures. DocumentPlainTextError: type: string description: Plain text error response. EmailErrorResponse: type: object properties: error: type: string description: Human-readable error message. success: type: boolean description: Present on some failure responses. retryable: type: boolean description: Whether a webhook sender should retry the request. required: - error EmailOAuthInitiateRequest: type: object properties: provider: type: string enum: - microsoft - google description: Email OAuth provider to authorize. redirectUri: type: string format: uri description: Optional OAuth callback URI. If omitted, the server builds /api/auth/{provider}/callback from the configured base URL. providerId: type: string format: uuid description: Email provider configuration ID to carry through OAuth state and use during callback token persistence. required: - provider EmailOAuthInitiateResponse: type: object properties: success: type: boolean enum: - true description: OAuth initiation succeeded. authUrl: type: string format: uri description: Provider authorization URL for the browser to visit. provider: type: string enum: - microsoft - google description: Email OAuth provider being authorized. state: type: string description: Base64-encoded OAuth state containing tenant, userId, providerId, redirectUri, timestamp, nonce, and hosted flag. required: - success - authUrl - provider - state EmailOAuthState: type: object properties: tenant: type: string description: Tenant identifier from the authenticated user session. userId: type: string description: User UUID from the authenticated session. providerId: type: string format: uuid description: Email provider configuration UUID from the initiate request. redirectUri: type: string description: OAuth redirect URI included in the authorization request. timestamp: type: number description: Epoch milliseconds when state was generated. nonce: type: string description: Random hex nonce for CSRF correlation. hosted: type: boolean description: Whether hosted credentials are used for the flow. required: - tenant - redirectUri - timestamp - nonce EmailRefreshWatchRequest: type: object properties: providerId: type: string format: uuid description: Active Gmail email provider ID from email_providers.id to refresh. required: - providerId EmailRefreshWatchResponse: type: object properties: success: type: boolean enum: - true description: Refresh completed successfully. message: type: string description: Human-readable success message. providerId: type: string format: uuid description: Email provider ID that was refreshed. mailbox: type: string format: email description: Mailbox address for the Gmail provider. required: - success - message - providerId - mailbox GooglePubSubMessage: type: object properties: data: type: string description: Base64-encoded Gmail notification JSON containing emailAddress and historyId. messageId: type: string description: Google Pub/Sub message ID. publishTime: type: string description: ISO timestamp when Pub/Sub published the message. required: - data - messageId - publishTime GooglePubSubPushBody: type: object properties: message: $ref: "#/components/schemas/GooglePubSubMessage" subscription: type: string description: Full Pub/Sub subscription path, such as projects/{project}/subscriptions/{subscriptionName}. required: - message - subscription GmailNotificationPayload: type: object properties: emailAddress: type: string format: email description: Gmail mailbox address with new activity. historyId: type: string description: Gmail history ID indicating the mailbox change position. required: - emailAddress - historyId GoogleWebhookEnqueueResponse: type: object properties: success: type: boolean enum: - true description: Webhook was accepted. queued: type: boolean enum: - true description: The notification was enqueued for asynchronous processing. handoff: type: string enum: - unified_pointer_queue description: Queue handoff mechanism used for the Gmail notification pointer. providerId: type: string format: uuid description: Resolved email_providers.id for the Gmail mailbox. tenant: type: string description: Tenant identifier owning the provider. historyId: type: string description: Gmail history ID from the decoded notification. jobId: type: string format: uuid description: UUID assigned to the Redis queue job. queueDepth: type: integer description: Redis queue depth after enqueue. required: - success - queued - handoff - providerId - tenant - historyId - jobId - queueDepth GoogleWebhookSkippedResponse: type: object properties: success: type: boolean enum: - true description: Webhook request was accepted but no job was enqueued. message: type: string enum: - No data to process - No provider found - No google config found description: Reason the webhook did not enqueue work. required: - success - message MicrosoftWebhookValidationQuery: type: object properties: validationtoken: type: string description: Microsoft Graph subscription validation token. The handler also accepts validationToken with camel-case spelling. validationToken: type: string description: Camel-case variant of the Microsoft Graph validation token. MicrosoftWebhookTextResponse: type: string description: Plain text response. For validation requests, this is the validation token echoed verbatim; otherwise it may be OK or Internal Server Error. MicrosoftGraphResourceData: type: object properties: "@odata.type": type: string description: "OData resource type, such as #microsoft.graph.message." "@odata.id": type: string description: OData resource identifier. id: type: string description: Microsoft Graph message ID. If absent, the handler extracts it from resource. subject: type: string description: Optional message subject supplied by Microsoft Graph. MicrosoftGraphNotification: type: object properties: changeType: type: string description: Microsoft Graph change type, typically created for new mail. clientState: type: string description: Opaque verification token that must match microsoft_email_provider_config.webhook_verification_token when configured. resource: type: string description: Graph resource path, for example /users/{userId}/messages/{messageId}. resourceData: $ref: "#/components/schemas/MicrosoftGraphResourceData" subscriptionExpirationDateTime: type: string description: Microsoft Graph subscription expiry timestamp. subscriptionId: type: string description: Microsoft Graph subscription ID. Used to resolve microsoft_email_provider_config.webhook_subscription_id. tenantId: type: string description: Microsoft tenant GUID from the notification. Informational only; tenant is resolved from DB. required: - changeType - resource - resourceData - subscriptionId MicrosoftGraphWebhookBody: type: object properties: value: type: array items: $ref: "#/components/schemas/MicrosoftGraphNotification" description: Batch of Microsoft Graph change notifications. required: - value MicrosoftWebhookSuccessResponse: type: object properties: success: type: boolean enum: - true description: Webhook request was processed successfully. queued: type: boolean description: Whether any notification pointer jobs were enqueued. handoff: type: string enum: - unified_pointer_queue description: Queue handoff mechanism used for Microsoft notification pointers. unifiedQueuedCount: type: integer description: Number of notification jobs enqueued. processedCount: type: integer description: Number of notifications processed. messageIds: type: array items: type: string description: Microsoft Graph message IDs that were enqueued. required: - success - queued - handoff - unifiedQueuedCount - processedCount - messageIds MicrosoftWebhookEmptyResponse: type: object properties: success: type: boolean enum: - true description: Webhook request was accepted. message: type: string description: Reason no notification jobs were enqueued. required: - success - message MicrosoftWebhookEnqueueErrorResponse: type: object properties: error: type: string enum: - Failed to enqueue one or more Microsoft pointer jobs failureCount: type: integer description: Number of enqueue failures. failures: type: array items: type: object properties: subscriptionId: type: string description: Microsoft Graph subscription ID from the notification. messageId: type: string description: Microsoft Graph message ID that failed to enqueue. providerId: type: string description: Resolved email provider ID. tenantId: type: string description: Resolved tenant identifier. reason: type: string description: Failure reason. required: - subscriptionId - messageId - providerId - tenantId - reason description: Per-notification enqueue failures. required: - error - failureCount - failures EmailWebhookTestRequest: type: object properties: provider: type: string enum: - microsoft - google description: Email provider type to simulate in the synthetic inbound email event. Defaults to microsoft. messageId: type: string description: Synthetic message identifier to include in the test event. Defaults to test-message-123. EmailWebhookTestResponse: type: object properties: success: type: boolean enum: - true description: Test event was published successfully. message: type: string description: Human-readable success message. eventId: type: string description: Redis Streams event ID returned by publishEvent. tenant: type: string description: Tenant identifier from the authenticated user session. required: - success - message - eventId - tenant ExtensionGatewayParams: type: object properties: extensionId: type: string minLength: 1 description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. path: type: string description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. required: - extensionId ExtensionGatewayHeaders: type: object properties: x-request-id: type: string format: uuid description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. x-idempotency-key: type: string description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. x-alga-tenant: type: string description: Internal tenant header used for tenant resolution before session fallback. x-tenant-id: type: string description: Legacy tenant header accepted for tenant resolution before session fallback. ExtensionOpaqueRequest: type: object properties: {} description: Extension-specific request body. The gateway treats this as opaque, enforces a 10 MB limit for non-GET methods, base64-encodes it, and forwards it to the extension runner. ExtensionOpaqueResponse: type: object properties: {} description: Extension-specific response relayed from the runner. Status code, content type, and body are controlled by the extension. ExtensionGatewayErrorResponse: type: object properties: error: type: string enum: - not_installed - payload_too_large - install_context_missing - runner_empty_response - runner_invalid_response - bad_gateway - internal_error description: Gateway-level error code. detail: description: Additional error detail when available. required: - error FinancialInvoiceUuidIdParam: type: object properties: id: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: - id FinancialInvoiceApiError: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error FinancialInvoiceApiSuccess: type: object properties: data: anyOf: - type: object additionalProperties: {} - type: array items: type: object additionalProperties: {} meta: type: object additionalProperties: {} required: - data FinancialInvoiceApiPaginated: type: object properties: data: type: array items: type: object additionalProperties: {} pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination FinancialListQuery: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a80 - asc - desc search: type: string created_from: type: string created_to: type: string updated_from: type: string updated_to: type: string client_id: type: string format: uuid invoice_id: type: string format: uuid type: type: string status: type: string amount_min: type: string amount_max: type: string include_expired: type: string enum: &a81 - "true" - "false" expiring_soon: type: string enum: &a82 - "true" - "false" has_remaining: type: string enum: &a83 - "true" - "false" has_expiration: type: string enum: &a84 - "true" - "false" date_from: type: string date_to: type: string group_by: type: string enum: &a85 - day - week - month include_projections: type: string enum: &a86 - "true" - "false" as_of_date: type: string InvoiceListQuery: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a87 - asc - desc include_items: type: string enum: &a88 - "true" - "false" include_client: type: string enum: &a89 - "true" - "false" include_billing_cycle: type: string enum: &a90 - "true" - "false" include_transactions: type: string enum: &a91 - "true" - "false" q: type: string from: type: string to: type: string format: type: string enum: &a92 - json - csv additionalProperties: type: string InvoiceExecutionIdQuery: type: object properties: execution_id: type: string reason: type: string BillingOverviewResponse: type: object properties: data: type: object additionalProperties: {} count: type: number meta: type: object additionalProperties: {} required: - data FinancialCalculateBillingBody: type: object properties: client_id: type: string format: uuid period_start: type: string period_end: type: string required: - client_id - period_start - period_end FinancialApplyCreditToInvoiceBody: type: object properties: client_id: type: string format: uuid invoice_id: type: string format: uuid requested_amount: type: number minimum: 0 required: - client_id - invoice_id - requested_amount FinancialPrepaymentInvoiceBody: type: object properties: client_id: type: string format: uuid amount: type: number minimum: 0 manual_expiration_date: type: string required: - client_id - amount FinancialTransferCreditBody: type: object properties: source_credit_id: type: string format: uuid target_client_id: type: string format: uuid amount: type: number minimum: 0 user_id: type: string format: uuid reason: type: string required: - source_credit_id - target_client_id - amount - user_id FinancialValidateCreditBody: type: object properties: client_id: type: string format: uuid required: - client_id FinancialCreateTransactionBody: type: object properties: client_id: type: string format: uuid invoice_id: type: string format: uuid amount: type: number type: type: string status: type: string parent_transaction_id: type: string format: uuid description: type: string reference_number: type: string metadata: type: object additionalProperties: {} balance_after: type: number expiration_date: type: string related_transaction_id: type: string format: uuid required: - client_id - amount - type - balance_after FinancialUpdateTransactionBody: type: object properties: client_id: type: string format: uuid invoice_id: type: string format: uuid amount: type: number type: type: string status: type: string parent_transaction_id: type: string format: uuid description: type: string reference_number: type: string metadata: type: object additionalProperties: {} balance_after: type: number expiration_date: type: string related_transaction_id: type: string format: uuid FinancialCreatePaymentMethodBody: type: object properties: client_id: type: string format: uuid type: type: string enum: - credit_card - bank_account last4: type: string minLength: 4 maxLength: 4 exp_month: type: string exp_year: type: string is_default: type: boolean is_deleted: type: boolean required: - client_id - type - last4 FinancialCalculateTaxBody: type: object properties: client_id: type: string format: uuid amount: type: number minimum: 0 tax_region: type: string date: type: string required: - client_id - amount - tax_region FinancialBulkInvoiceOperationBody: type: object properties: operation: type: string enum: - send - finalize - cancel - mark_paid invoice_ids: type: array items: type: string format: uuid minItems: 1 options: type: object additionalProperties: {} required: - operation - invoice_ids FinancialBulkTransactionOperationBody: type: object properties: operation: type: string enum: - approve - reject - void transaction_ids: type: array items: type: string format: uuid minItems: 1 options: type: object additionalProperties: {} required: - operation - transaction_ids FinancialBulkCreditOperationBody: type: object properties: operation: type: string enum: - expire - extend - transfer credit_ids: type: array items: type: string format: uuid minItems: 1 options: type: object additionalProperties: {} required: - operation - credit_ids FinancialReconciliationResolveBody: type: object properties: notes: type: string InvoiceCreateBody: type: object properties: client_id: type: string format: uuid invoice_date: type: string due_date: type: string subtotal: type: integer minimum: 0 tax: type: integer minimum: 0 total_amount: type: integer minimum: 0 status: type: string enum: &a14 - draft - sent - paid - overdue - cancelled - pending - prepayment - partially_applied credit_applied: type: integer minimum: 0 is_manual: type: boolean is_prepayment: type: boolean items: type: array items: type: object additionalProperties: {} required: - client_id - invoice_date - due_date - subtotal - tax - total_amount - status additionalProperties: {} InvoiceUpdateBody: type: object properties: client_id: type: string format: uuid invoice_date: type: string due_date: type: string subtotal: type: integer minimum: 0 tax: type: integer minimum: 0 total_amount: type: integer minimum: 0 status: type: string enum: *a14 credit_applied: type: integer minimum: 0 is_manual: type: boolean is_prepayment: type: boolean items: type: array items: type: object additionalProperties: {} additionalProperties: {} InvoiceManualBody: type: object properties: clientId: type: string format: uuid items: type: array items: type: object additionalProperties: {} minItems: 1 expirationDate: type: string isPrepayment: type: boolean required: - clientId - items InvoiceSelectorBody: type: object properties: selector_input: type: object properties: clientId: type: string format: uuid windowStart: type: string windowEnd: type: string executionWindow: type: object properties: kind: type: string enum: - client_cadence_window - contract_cadence_window identityKey: type: string cadenceOwner: type: string enum: - client - contract clientId: type: string format: uuid billingCycleId: type: - string - "null" format: uuid contractId: type: - string - "null" format: uuid contractLineId: type: - string - "null" format: uuid windowStart: type: - string - "null" windowEnd: type: - string - "null" required: - kind - identityKey - cadenceOwner required: - clientId - windowStart - windowEnd - executionWindow required: - selector_input InvoiceFinalizeBody: type: object properties: finalized_at: type: string InvoiceSendBody: type: object properties: email_addresses: type: array items: type: string format: email minItems: 1 subject: type: string message: type: string include_pdf: type: boolean required: - email_addresses InvoiceCreditBody: type: object properties: credit_amount: type: integer minimum: 0 transaction_id: type: string format: uuid required: - credit_amount InvoicePaymentBody: type: object properties: payment_amount: type: integer minimum: 0 payment_method: type: string payment_date: type: string reference_number: type: string notes: type: string required: - payment_amount - payment_method InvoiceTaxBody: type: object properties: client_id: type: string format: uuid amount: type: integer minimum: 0 tax_region: type: string calculation_date: type: string required: - client_id - amount - tax_region InvoiceBulkStatusBody: type: object properties: invoice_ids: type: array items: type: string format: uuid minItems: 1 maxItems: 100 status: type: string enum: - draft - sent - paid - overdue - cancelled - pending - prepayment - partially_applied finalized_at: type: string required: - invoice_ids - status InvoiceBulkSendBody: type: object properties: invoice_ids: type: array items: type: string format: uuid minItems: 1 maxItems: 50 email_template: type: string include_pdf: type: boolean required: - invoice_ids InvoiceBulkDeleteBody: type: object properties: ids: type: array items: type: string format: uuid minItems: 1 force: type: boolean required: - ids InvoiceBulkCreditBody: type: object properties: invoice_ids: type: array items: type: string format: uuid minItems: 1 maxItems: 100 credit_amount_per_invoice: type: integer minimum: 0 required: - invoice_ids - credit_amount_per_invoice InvoiceRecurringCreateBody: type: object properties: client_id: type: string format: uuid name: type: string frequency: type: string enum: - daily - weekly - monthly - quarterly - annually start_date: type: string end_date: type: string is_active: type: boolean invoice_template: type: object additionalProperties: {} max_generations: type: number required: - client_id - name - frequency - start_date - invoice_template KbArticle: type: object properties: article_id: type: string format: uuid tenant: type: string format: uuid document_id: type: string format: uuid description: Underlying document backing the article. title: type: string slug: type: string article_type: type: string enum: &a15 - how_to - faq - troubleshooting - reference audience: type: string enum: &a16 - internal - client - public status: type: string enum: &a17 - draft - review - published - archived category_id: type: - string - "null" format: uuid review_cycle_days: type: - integer - "null" next_review_date: type: - string - "null" published_at: type: - string - "null" published_by: type: - string - "null" format: uuid document_name: type: - string - "null" description: Joined from the documents table. created_at: type: string updated_at: type: string required: - article_id - tenant - document_id - title - slug - article_type - audience - status description: A knowledge base article and its metadata. KbArticleIdParam: type: object properties: id: type: string format: uuid description: KB article UUID. required: - id KbArticleFromTicketParam: type: object properties: ticketId: type: string format: uuid description: Source ticket UUID. required: - ticketId KbArticleCreateRequest: type: object properties: title: type: string minLength: 1 maxLength: 255 slug: type: string description: Optional; generated from the title when omitted. article_type: type: string enum: *a15 description: Defaults to how_to. audience: type: string enum: *a16 description: Defaults to internal. category_id: type: string format: uuid review_cycle_days: type: integer content: type: string description: Initial body content. content_format: type: string enum: - markdown - blocknote description: Defaults to markdown. required: - title KbArticleUpdateRequest: type: object properties: title: type: string minLength: 1 maxLength: 255 slug: type: string article_type: type: string enum: *a15 audience: type: string enum: *a16 category_id: type: string format: uuid review_cycle_days: type: integer status: type: string enum: *a17 KbArticleContentUpdateRequest: type: object properties: content: type: string minLength: 1 format: type: string enum: - markdown - blocknote description: Defaults to markdown. required: - content KbArticleListQuery: type: object properties: page: type: integer minimum: 1 limit: type: integer minimum: 1 maximum: 100 status: type: string enum: *a17 audience: type: string enum: *a16 article_type: type: string enum: *a15 category_id: type: string format: uuid search: type: string KbArticleResponse: type: object properties: data: $ref: "#/components/schemas/KbArticle" meta: type: object additionalProperties: {} required: - data PaginatedKbArticleResponse: type: object properties: data: type: array items: $ref: "#/components/schemas/KbArticle" pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination KbCategoryListResponse: type: object properties: data: type: array items: type: object properties: category_id: type: string format: uuid category_name: type: string display_order: type: integer required: - category_id - category_name required: - data KbTemplateListResponse: type: object properties: data: type: array items: type: object properties: template_id: type: string format: uuid name: type: string article_type: type: string enum: *a15 required: - template_id - name required: - data KbArticleContentResponse: type: object properties: data: type: object properties: article_id: type: string format: uuid content: type: string description: Article body rendered as readable text. required: - content required: - data PublicV1Success: type: object properties: data: anyOf: - type: object additionalProperties: {} - type: array items: type: object additionalProperties: {} meta: type: object additionalProperties: {} required: - data AiDocumentAssistBody: type: object properties: instruction: type: string description: What the assistant should do. documentContext: type: string description: Current document text/context. documentId: type: string format: uuid tenantId: type: string format: uuid connectedUserNames: type: array items: type: string required: - instruction - documentContext - tenantId SoftwareSearchQuery: type: object properties: search: type: string category: type: string software_type: type: string is_managed: type: string enum: &a93 - "true" - "false" is_security_relevant: type: string enum: &a94 - "true" - "false" client_id: type: string format: uuid page: type: integer minimum: 1 limit: type: integer minimum: 1 maximum: 200 PriorityListQuery: type: object properties: page: type: integer minimum: 1 limit: type: integer minimum: 1 maximum: 100 sort: type: string order: type: string enum: &a95 - asc - desc PriorityIdParam: type: object properties: id: type: string format: uuid required: - id ExtensionActionBody: type: object additionalProperties: {} description: Extension install/uninstall payload (handled by the EE extension service). CompanyContractLineListQuery: type: object properties: page: type: integer minimum: 1 limit: type: integer minimum: 1 maximum: 100 client_id: type: string format: uuid contract_line_id: type: string format: uuid CompanyContractLineBody: type: object properties: client_id: type: string format: uuid contract_line_id: type: string format: uuid client_contract_id: type: string format: uuid custom_rate: type: number required: - client_id - contract_line_id CompanyContractLineIdParam: type: object properties: id: type: string format: uuid required: - id XeroClientExportQuery: type: object properties: clientIds: type: string description: Comma-separated client UUIDs to limit the export. XeroClientImportQuery: type: object properties: preview: type: string enum: &a96 - "true" - "false" createNew: type: string enum: &a97 - "true" - "false" updateExisting: type: string enum: &a98 - "true" - "false" matchBy: type: string XeroTaxImportQuery: type: object properties: preview: type: string enum: &a99 - "true" - "false" AccountingBatchIdParam: type: object properties: batchId: type: string description: Export batch identifier. required: - batchId UnversionedV1Success: type: object properties: data: anyOf: - type: object additionalProperties: {} - type: array items: type: object additionalProperties: {} meta: type: object additionalProperties: {} required: - data ProjectTemplateIdParam: type: object properties: templateId: type: string format: uuid required: - templateId ProjectTemplateCopyOptions: type: object properties: copyPhases: type: boolean copyStatuses: type: boolean copyTasks: type: boolean copyDependencies: type: boolean copyChecklists: type: boolean copyServices: type: boolean assignmentOption: type: string description: Which parts of the template to copy when applying it. ProjectTemplateCreateBody: type: object properties: project_id: type: string format: uuid template_name: type: string minLength: 1 description: type: string category: type: string required: - project_id - template_name ProjectTemplateUpdateBody: type: object properties: template_name: type: string minLength: 1 description: type: string category: type: string ProjectTemplateApplyBody: type: object properties: project_name: type: string minLength: 1 client_id: type: string format: uuid start_date: type: string format: date-time assigned_to: type: string format: uuid options: $ref: "#/components/schemas/ProjectTemplateCopyOptions" required: - project_name - client_id WorkflowDefinitionIdParam: type: object properties: workflowId: type: string format: uuid required: - workflowId WorkflowDefinitionVersionParams: type: object properties: workflowId: type: string format: uuid version: type: string description: Draft version number (coerced to a positive integer). required: - workflowId - version WorkflowDefinitionDocument: type: object additionalProperties: {} description: Workflow definition DSL document (nodes, edges, triggers, payload schema, etc.). WorkflowDefinitionCreateBody: type: object properties: key: type: string pattern: ^[a-z0-9][a-z0-9._-]*$ description: Stable workflow key; generated when omitted. definition: $ref: "#/components/schemas/WorkflowDefinitionDocument" payloadSchemaMode: type: string enum: - inferred - pinned pinnedPayloadSchemaRef: type: string required: - definition WorkflowImportQuery: type: object properties: force: type: string enum: &a100 - "true" - "false" WorkflowImportBody: type: object properties: bundle: description: Legacy v1 workflow bundle document. WorkflowMetadataBody: type: object properties: key: type: string isVisible: type: boolean isPaused: type: boolean concurrencyLimit: type: integer minimum: 0 autoPauseOnFailure: type: boolean failureRateThreshold: type: number minimum: 0 maximum: 1 failureRateMinRuns: type: integer minimum: 0 retentionPolicyOverride: type: object additionalProperties: {} WorkflowDefinitionUpdateBody: type: object properties: definition: $ref: "#/components/schemas/WorkflowDefinitionDocument" required: - definition WorkflowPublishBody: type: object properties: definition: $ref: "#/components/schemas/WorkflowDefinitionDocument" WorkflowRunIdParam: type: object properties: runId: type: string required: - runId WorkflowRunActionBody: type: object properties: reason: type: string description: Audit reason for the action. source: type: string description: Origin label; defaults to 'api'. WorkflowRunCreateBody: type: object properties: workflowId: type: string workflowVersion: type: integer exclusiveMinimum: 0 payload: type: object additionalProperties: {} eventType: type: string sourcePayloadSchemaRef: type: string required: - workflowId WorkflowRunReplayBody: type: object properties: reason: type: string source: type: string payload: type: object additionalProperties: {} WorkflowEventBody: type: object properties: eventName: type: string workflowCorrelationKey: type: string correlationKey: type: string payloadSchemaRef: type: string payload: type: object additionalProperties: {} required: - eventName WorkflowEventIdParam: type: object properties: eventId: type: string required: - eventId WorkflowJsonSchemaDocument: type: object additionalProperties: {} description: A JSON Schema document. WorkflowRegistryAction: type: object properties: id: type: string description: Stable action identifier (e.g. "ticket.create"). version: type: integer description: Action version. sideEffectful: type: boolean description: Whether executing the action mutates external state. retryHint: type: - object - "null" additionalProperties: {} description: Suggested retry policy, or null. idempotency: type: object additionalProperties: {} description: Idempotency configuration for the action. ui: type: object additionalProperties: {} description: Designer UI metadata (label, group, icon, etc.). inputSchema: allOf: - $ref: "#/components/schemas/WorkflowJsonSchemaDocument" - description: JSON Schema for the action input, annotated with designer presentation metadata. outputSchema: allOf: - $ref: "#/components/schemas/WorkflowJsonSchemaDocument" - description: JSON Schema for the action output. examples: type: - array - "null" items: type: object additionalProperties: {} description: Example invocations, or null. required: - id - version - sideEffectful - retryHint - idempotency - ui - inputSchema - outputSchema - examples WorkflowRegistryNode: type: object properties: id: type: string description: Node type identifier. ui: type: object additionalProperties: {} description: Designer UI metadata for the node. configSchema: allOf: - $ref: "#/components/schemas/WorkflowJsonSchemaDocument" - description: JSON Schema for the node configuration. examples: type: - array - "null" items: type: object additionalProperties: {} description: Example configurations, or null. defaultRetry: type: - object - "null" additionalProperties: {} description: Default retry policy for the node, or null. required: - id - ui - configSchema - examples - defaultRetry WorkflowSchemaRefParam: type: object properties: schemaRef: type: string description: Registered schema reference; URL-encode it in the path. required: - schemaRef WorkflowSchemaResponse: type: object properties: ref: type: string description: The resolved schema reference. schema: $ref: "#/components/schemas/WorkflowJsonSchemaDocument" required: - ref - schema FileDownloadParams: type: object properties: fileId: type: string format: uuid description: File UUID from external_files.file_id to download. The handler does not validate UUID syntax before querying storage metadata. required: - fileId FileBinaryDownloadResponse: type: string description: Binary file bytes loaded from the configured storage provider. FileDownloadPlainTextError: type: string description: Plain text error response, such as Tenant not found or Download failed. InboundWebhookConfig: type: object properties: inboundWebhookId: type: string format: uuid tenant: type: string format: uuid name: type: string slug: type: string description: type: - string - "null" authType: type: string enum: - hmac_sha256 - bearer - ip_allowlist - path_token authConfig: type: object additionalProperties: {} description: Redacted auth configuration metadata. idempotencySource: type: - object - "null" properties: type: type: string enum: - header - jsonata value: type: string required: - type - value idempotencyWindowSeconds: type: integer handlerType: type: string enum: - direct_action - workflow handlerConfig: type: object additionalProperties: {} samplePayload: {} sampleCaptureExpiresAt: type: - string - "null" format: date-time isActive: type: boolean rateLimitPerMinute: type: integer autoDisabledAt: type: - string - "null" format: date-time createdBy: type: - string - "null" format: uuid createdAt: type: string format: date-time updatedAt: type: string format: date-time required: - inboundWebhookId - tenant - name - slug - description - authType - authConfig - idempotencySource - idempotencyWindowSeconds - handlerType - handlerConfig - sampleCaptureExpiresAt - isActive - rateLimitPerMinute - autoDisabledAt - createdBy - createdAt - updatedAt InboundWebhookDelivery: type: object properties: tenant: type: string format: uuid deliveryId: type: string format: uuid inboundWebhookId: type: - string - "null" format: uuid idempotencyKey: type: - string - "null" receivedAt: type: string format: date-time requestMethod: type: string requestPath: type: string requestHeaders: type: object additionalProperties: anyOf: - type: string - type: array items: type: string requestBody: {} sourceIp: type: - string - "null" userAgent: type: - string - "null" authStatus: type: string enum: - verified - rejected_signature - rejected_bearer - rejected_ip - rejected_no_auth dispatchStatus: type: string enum: - pending - dispatched - duplicate - failed handlerOutcome: type: - object - "null" additionalProperties: {} responseStatus: type: - integer - "null" responseBody: {} durationMs: type: - integer - "null" retryCount: type: integer isReplay: type: boolean replayedFrom: type: - string - "null" format: uuid createdAt: type: string format: date-time updatedAt: type: string format: date-time required: - tenant - deliveryId - inboundWebhookId - idempotencyKey - receivedAt - requestMethod - requestPath - requestHeaders - sourceIp - userAgent - authStatus - dispatchStatus - handlerOutcome - responseStatus - durationMs - retryCount - isReplay - replayedFrom - createdAt - updatedAt InboundActionTargetField: type: object properties: name: type: string type: type: string enum: - string - int - number - boolean - enum - object - array - ref required: type: boolean description: type: string enumValues: type: array items: type: string refEntityType: type: string required: - name - type - required - description InboundActionDefinition: type: object properties: name: type: string entityType: type: string displayName: type: string description: type: string targetFields: type: array items: $ref: "#/components/schemas/InboundActionTargetField" required: - name - entityType - displayName - description - targetFields InboundWebhookCreateInput: type: object properties: name: type: string minLength: 1 slug: type: string pattern: ^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$ description: type: - string - "null" auth_type: type: string enum: - hmac_sha256 - bearer - ip_allowlist - path_token auth_config: type: object additionalProperties: {} idempotency_source: type: - object - "null" properties: type: type: string enum: - header - jsonata value: type: string required: - type - value idempotency_window_seconds: type: integer exclusiveMinimum: 0 handler_type: type: string enum: - direct_action - workflow handler_config: type: object additionalProperties: {} is_active: type: boolean rate_limit_per_minute: type: integer exclusiveMinimum: 0 required: - name - slug - auth_type - auth_config - handler_type - handler_config InboundWebhookAuthConfig: oneOf: - type: object properties: auth_type: type: string enum: - hmac_sha256 auth_config: type: object properties: signature_header: type: string description: Header containing sha256= or raw hex HMAC. secret: type: string description: Create/update-time secret; never returned after storage. secret_vault_path: type: string description: Stored vault path metadata returned by reads. required: - signature_header required: - auth_type - auth_config - type: object properties: auth_type: type: string enum: - bearer auth_config: type: object properties: token: type: string description: Create/update-time bearer token; never returned after storage. token_vault_path: type: string description: Stored vault path metadata returned by reads. required: - auth_type - auth_config - type: object properties: auth_type: type: string enum: - ip_allowlist auth_config: type: object properties: ip_cidrs: type: array items: type: string description: Exact IP strings or CIDR ranges accepted. required: - ip_cidrs required: - auth_type - auth_config - type: object properties: auth_type: type: string enum: - path_token auth_config: type: object properties: query_param: type: string description: Query parameter name, default token. token: type: string description: Create/update-time path token; never returned after storage. token_vault_path: type: string description: Stored vault path metadata returned by reads. required: - auth_type - auth_config InboundWebhookHandlerConfig: oneOf: - type: object properties: handler_type: type: string enum: - direct_action handler_config: type: object properties: action: type: string description: Registered inbound action name. field_mapping: type: object additionalProperties: type: string description: Map of target field name to JSONata expression evaluated against the request body. required: - action - field_mapping required: - handler_type - handler_config - type: object properties: handler_type: type: string enum: - workflow handler_config: type: object properties: workflow_id: type: string format: uuid description: Workflow definition to start for verified deliveries. required: - workflow_id required: - handler_type - handler_config InboundWebhookUpdateInput: allOf: - $ref: "#/components/schemas/InboundWebhookCreateInput" - type: object properties: inbound_webhook_id: type: string format: uuid WorkflowWebhookEnvelope: type: object properties: source: type: string description: Inbound webhook slug. body: description: Parsed JSON request body as received. headers: type: object additionalProperties: anyOf: - type: string - type: array items: type: string description: Filtered safe request headers. verified: type: boolean enum: - true delivery_id: type: string format: uuid idempotency_key: type: - string - "null" received_at: type: string format: date-time required: - source - headers - verified - delivery_id - idempotency_key - received_at HealthResponse: type: object properties: status: type: string enum: - ok description: Always ok when the API process is reachable. version: type: string description: Hardcoded API version string returned by the handler. required: - status - version HealthzResponse: type: object properties: status: type: string enum: - healthy description: Always healthy when the process can serve HTTP. timestamp: type: string format: date-time description: ISO timestamp generated when the liveness check is handled. uptime: type: number minimum: 0 description: Process uptime in seconds from process.uptime(). version: type: string description: Application version from the environment/package metadata, with a fallback in the handler. environment: type: string description: NODE_ENV value returned by the Next.js /api/healthz handler. required: - status - timestamp - uptime - version ReadyzChecks: type: object properties: database: type: boolean description: True when a SELECT 1 database connectivity check succeeds. redis: type: boolean description: Redis readiness placeholder. Currently mirrors the database check result. required: - database - redis ReadyzReadyResponse: type: object properties: status: type: string enum: - ready description: All critical dependencies checked by this handler are available. timestamp: type: string format: date-time description: ISO timestamp generated when the readiness check is handled. uptime: type: number minimum: 0 description: Process uptime in seconds from process.uptime(). version: type: string description: Application version from npm_package_version, with handler fallback. checks: $ref: "#/components/schemas/ReadyzChecks" required: - status - timestamp - uptime - version - checks ReadyzNotReadyResponse: type: object properties: status: type: string enum: - not_ready description: One or more critical dependencies are unavailable. timestamp: type: string format: date-time description: ISO timestamp generated when the readiness check is handled. uptime: type: number minimum: 0 description: Process uptime in seconds. Present in the dependency-failure branch, omitted by the catch branch. version: type: string description: Application version. Present only in the ready response branch. checks: $ref: "#/components/schemas/ReadyzChecks" error: type: string description: Readiness failure reason or caught exception message. required: - status - timestamp - checks - error RunnerCanaryHeaders: type: object properties: x-canary: type: string description: Optional runner canary identifier used only for logging and cache variance. InstallLookupByHostQuery: type: object properties: host: type: string minLength: 1 description: Runner domain hostname to resolve. The implementation lowercases the value and strips any port before matching tenant_extension_install.runner_domain. required: - host InstallLookupByHostResponse: type: object properties: tenant_id: type: string description: Tenant ID from tenant_extension_install.tenant_id for the matching runner domain. extension_id: type: string format: uuid description: Extension registry UUID from tenant_extension_install.registry_id. content_hash: type: string description: Content hash from extension_bundle.content_hash for the install version. Usually sha256:<64 hex chars>. required: - tenant_id - extension_id - content_hash InstallLookupErrorResponse: type: object properties: error: type: string description: Error message, such as missing host, not found, internal error, or middleware API-key errors. required: - error InstallValidateQuery: type: object properties: tenant: type: string format: uuid description: Tenant UUID from tenant_extension_install.tenant_id. extension: type: string format: uuid description: Extension registry UUID from tenant_extension_install.registry_id. hash: type: string minLength: 1 description: "Bundle content hash to validate. The EE action accepts sha256:<64 hex chars> or a raw 64-character hex string and normalizes raw hex to sha256: form." required: - tenant - extension - hash InstallValidateResponse: type: object properties: valid: type: boolean description: True when the hash matches a bundle for the currently installed extension version; false when validation completes but does not match. required: - valid InstallValidateParameterErrorResponse: type: object properties: valid: type: boolean enum: - false description: Always false for parameter errors. error: type: string enum: - missing or invalid parameters description: Returned when tenant, extension, or hash is absent. required: - valid - error QboOAuthCallbackQuery: type: object properties: code: type: string description: OAuth 2.0 authorization code returned by Intuit. Required unless Intuit sends an error parameter. state: type: string description: Base64url-encoded JSON containing tenantId and csrf generated by the connect endpoint. realmId: type: string description: QuickBooks company/realm ID returned by Intuit. error: type: string description: OAuth error returned by Intuit when authorization fails or is denied. QboErrorResponse: type: object properties: error: type: string description: Error message returned by middleware or by the connect endpoint. required: - error QboRouteMissingResponse: type: string description: Default Next.js 404 page or not-found response. The route file listed in inventory is absent in this worktree. QuickBooksV1MappingIdParam: type: object properties: mapping_id: type: string description: Mapping identifier extracted from path segment mapping_id. required: - mapping_id QuickBooksV1SyncIdParam: type: object properties: sync_id: type: string description: Sync operation identifier extracted from path segment sync_id. required: - sync_id QuickBooksV1EntityQuery: type: object properties: page: type: string limit: type: string active: type: string enum: &a101 - "true" - "false" search: type: string entity_type: type: string force_refresh: type: string enum: &a102 - "true" - "false" QuickBooksV1SyncHistoryQuery: type: object properties: page: type: string limit: type: string status: type: string enum: &a103 - pending - in_progress - completed - failed - cancelled - partial operation_type: type: string enum: &a104 - customer_sync - invoice_export - invoice_import - payment_sync - item_sync - tax_sync - full_sync - test_connection date_from: type: string date_to: type: string QuickBooksV1OAuthInitiateBody: type: object properties: state: type: string minLength: 1 redirect_uri: type: string format: uri scope: type: string required: - state QuickBooksV1OAuthCallbackBody: type: object properties: code: type: string minLength: 1 state: type: string minLength: 1 realmId: type: string minLength: 1 error: type: string error_description: type: string required: - code - state - realmId QuickBooksV1ConnectionTestBody: type: object properties: testType: type: string enum: - clientInfo - items - customers - full forceRefresh: type: boolean QuickBooksV1CustomerSyncBody: type: object properties: client_id: type: string format: uuid sync_type: type: string enum: - create - update - bidirectional force_update: type: boolean include_inactive: type: boolean QuickBooksV1InvoiceExportBody: type: object properties: invoice_id: type: string format: uuid date_range: type: object properties: start_date: type: string end_date: type: string required: - start_date - end_date status_filter: type: array items: type: string enum: - draft - sent - paid - overdue - cancelled client_id: type: string format: uuid export_format: type: string enum: - qbo - json include_line_items: type: boolean auto_create_items: type: boolean skip_existing: type: boolean QuickBooksV1InvoiceImportBody: type: object properties: qbo_invoice_id: type: string date_range: type: object properties: start_date: type: string end_date: type: string required: - start_date - end_date import_payments: type: boolean auto_create_clients: type: boolean update_existing: type: boolean QuickBooksV1PaymentSyncBody: type: object properties: payment_id: type: string format: uuid invoice_id: type: string format: uuid date_range: type: object properties: start_date: type: string end_date: type: string required: - start_date - end_date sync_type: type: string enum: - create - update - bidirectional include_unapplied: type: boolean QuickBooksV1AccountMappingsBody: type: object properties: mappings: type: array items: type: object properties: account_type: type: string enum: - income - expense - asset - liability - equity alga_account_name: type: string qbo_account_id: type: string is_default: type: boolean required: - account_type - alga_account_name - qbo_account_id minItems: 1 replace_existing: type: boolean required: - mappings QuickBooksV1TaxMappingsBody: type: object properties: mappings: type: array items: type: object properties: alga_tax_region: type: string qbo_tax_code_id: type: string is_default: type: boolean required: - alga_tax_region - qbo_tax_code_id minItems: 1 replace_existing: type: boolean required: - mappings QuickBooksV1DataMappingBody: type: object properties: entity_type: type: string enum: - customer - invoice - payment - item - tax_code mapping_name: type: string field_mappings: type: array items: type: object properties: alga_field: type: string qbo_field: type: string transform_function: type: string is_required: type: boolean default_value: {} validation_rule: type: string required: - alga_field - qbo_field minItems: 1 is_default: type: boolean description: type: string required: - entity_type - mapping_name - field_mappings QuickBooksV1BulkSyncBody: type: object properties: operations: type: array items: type: object properties: operation_type: type: string enum: - customer_sync - invoice_export - invoice_import - payment_sync - item_sync - tax_sync - full_sync - test_connection entity_ids: type: array items: type: string format: uuid qbo_entity_ids: type: array items: type: string date_range: type: object properties: start_date: type: string end_date: type: string required: - start_date - end_date parameters: type: object additionalProperties: {} required: - operation_type minItems: 1 maxItems: 10 execution_mode: type: string enum: - sequential - parallel stop_on_error: type: boolean notification_email: type: string format: email required: - operations QuickBooksV1HealthConfigBody: type: object properties: monitoring_enabled: type: boolean check_interval: type: integer minimum: 1 alert_thresholds: type: object additionalProperties: {} QuickBooksV1ApiError: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error QuickBooksV1ApiSuccess: type: object properties: data: anyOf: - type: object additionalProperties: {} - type: array items: type: object additionalProperties: {} meta: type: object additionalProperties: {} required: - data QuickBooksV1ApiPaginated: type: object properties: data: type: array items: type: object additionalProperties: {} pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination BoardIdParams: type: object properties: id: type: string format: uuid description: Board UUID. required: - id BoardApiResponse: type: object properties: board_id: type: string format: uuid board_name: type: string description: type: - string - "null" display_order: type: number is_default: type: boolean is_inactive: type: boolean category_type: type: - string - "null" enum: - custom - itil priority_type: type: - string - "null" enum: - custom - itil display_itil_impact: type: - boolean - "null" display_itil_urgency: type: - boolean - "null" default_assigned_to: type: - string - "null" format: uuid inbound_reply_reopen_enabled: type: boolean inbound_reply_reopen_cutoff_hours: type: integer inbound_reply_reopen_status_id: type: - string - "null" format: uuid inbound_reply_ai_ack_suppression_enabled: type: boolean enable_live_ticket_timer: type: - boolean - "null" tenant: type: string format: uuid required: - board_id - board_name - description - display_order - is_default - is_inactive - category_type - priority_type - display_itil_impact - display_itil_urgency - default_assigned_to - enable_live_ticket_timer - tenant BoardEnvelope: type: object properties: data: $ref: "#/components/schemas/BoardApiResponse" required: - data BoardListEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/BoardApiResponse" required: - data BoardCreateRequest: type: object properties: board_name: type: string minLength: 1 maxLength: 255 description: type: string maxLength: 1000 is_default: type: boolean is_inactive: type: boolean category_type: type: string enum: &a18 - custom - itil priority_type: type: string enum: &a19 - custom - itil default_assigned_to: type: - string - "null" format: uuid display_itil_impact: type: boolean display_itil_urgency: type: boolean enable_live_ticket_timer: type: boolean required: - board_name description: Payload for creating a new board. BoardUpdateRequest: type: object properties: board_name: type: string minLength: 1 maxLength: 255 description: type: string maxLength: 1000 is_default: type: boolean is_inactive: type: boolean category_type: type: string enum: *a18 priority_type: type: string enum: *a19 default_assigned_to: type: - string - "null" format: uuid display_itil_impact: type: boolean display_itil_urgency: type: boolean enable_live_ticket_timer: type: boolean description: Payload for updating a board. All fields are optional. StatusIdParams: type: object properties: id: type: string format: uuid description: Status UUID. required: - id StatusApiResponse: type: object properties: status_id: type: string format: uuid name: type: string status_type: type: string enum: - ticket - project - project_task - interaction order_number: type: number is_closed: type: boolean is_default: type: - boolean - "null" item_type: type: - string - "null" standard_status_id: type: - string - "null" is_custom: type: - boolean - "null" tenant: type: string format: uuid required: - status_id - name - status_type - order_number - is_closed - is_default - item_type - standard_status_id - is_custom - tenant StatusEnvelope: type: object properties: data: $ref: "#/components/schemas/StatusApiResponse" required: - data StatusListEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/StatusApiResponse" required: - data StatusCreateRequest: type: object properties: name: type: string minLength: 1 maxLength: 255 status_type: type: string enum: - ticket - project - project_task - interaction board_id: type: string format: uuid is_closed: type: boolean is_default: type: boolean order_number: type: integer minimum: 0 color: type: string pattern: ^#[0-9A-Fa-f]{6}$ icon: type: string maxLength: 50 required: - name - status_type description: Payload for creating a new status. For ticket statuses, board_id is required. StatusUpdateRequest: type: object properties: name: type: string minLength: 1 maxLength: 255 is_closed: type: boolean is_default: type: boolean order_number: type: integer minimum: 0 color: type: string pattern: ^#[0-9A-Fa-f]{6}$ icon: type: string maxLength: 50 description: Payload for updating a status. All fields are optional. SearchQuery: type: object properties: query: type: string minLength: 1 maxLength: 200 description: Full-text query. A concise expression of likely record words, identifiers, names, or quoted phrases — not a full sentence. Supports OR for alternatives (e.g. "laptop OR workstation"). types: type: string description: "Comma-separated list of object types to restrict the search (e.g. \"ticket,project\"). Omit to search every type the API key's user is permitted to read. Allowed values: client, contact, user, ticket, ticket_comment, project, project_phase, project_task, project_task_comment, asset, invoice, invoice_item, invoice_annotation, contract, client_contract, document, kb_article, service_catalog, service_request_submission, service_request_definition, workflow_task, interaction, schedule_entry, time_entry, board, category, tag, status." limit: type: integer minimum: 1 maximum: 100 description: Maximum number of results to return. Defaults to 30; capped at 100. cursor: type: string description: Opaque pagination cursor copied from a prior response's nextCursor. sort: type: string enum: &a105 - relevance - recent description: Result ordering. "relevance" (default) ranks by full-text score; "recent" orders by last update. required: - query SearchResultRow: type: object properties: type: type: string enum: - client - contact - user - ticket - ticket_comment - project - project_phase - project_task - project_task_comment - asset - invoice - invoice_item - invoice_annotation - contract - client_contract - document - kb_article - service_catalog - service_request_submission - service_request_definition - workflow_task - interaction - schedule_entry - time_entry - board - category - tag - status description: Indexed business object type. id: type: string description: Object identifier within its type. parentId: type: string description: Identifier of the parent record for nested results (e.g. the ticket of a ticket comment). title: type: string description: Primary display label for the record. subtitle: type: string description: Secondary context line. snippet: type: string description: Matched-text excerpt with tags around the highlighted terms. url: type: string description: Relative in-app URL pointing at the record. score: type: number description: Relevance score; higher is more relevant. updatedAt: type: string format: date-time description: Source record last-updated timestamp. required: - type - id - title - url - score - updatedAt SearchResultData: type: object properties: results: type: array items: $ref: "#/components/schemas/SearchResultRow" description: Matching records for this page, ordered by the requested sort. groups: type: object additionalProperties: type: integer description: Total match counts keyed by object type (across all pages), before the page limit is applied. totalCount: type: integer description: Total number of matches across all permitted types. nextCursor: type: string description: Cursor for the next page; absent when the result set fits within the page. required: - results - groups - totalCount SearchResponse: type: object properties: data: allOf: - $ref: "#/components/schemas/SearchResultData" - description: Search payload returned by createSuccessResponse. required: - data SearchApiErrorEnvelope: type: object properties: error: type: object properties: code: type: string description: Machine-readable error code such as VALIDATION_ERROR, UNAUTHORIZED, or INTERNAL_ERROR. message: type: string description: Human-readable error message. details: description: Optional structured details, including Zod validation errors. required: - code - message required: - error ServiceCategory: type: object properties: tenant: type: string format: uuid category_id: type: string format: uuid category_name: type: string description: type: - string - "null" display_order: type: integer default: 0 is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time created_by: type: string format: uuid updated_by: type: string format: uuid tags: type: array items: type: string required: - tenant - category_id - category_name - is_active - created_at - updated_at - created_by - updated_by description: Service category resource. ServiceCategoryCreateRequest: type: object properties: category_name: type: string minLength: 1 maxLength: 255 description: type: string maxLength: 1000 is_active: type: boolean required: - category_name description: Payload for creating a service category. ServiceCategoryListQuery: type: object properties: search: type: string is_active: type: boolean page: type: integer minimum: 1 limit: type: integer minimum: 1 maximum: 100 description: Query parameters for listing service categories. CategoryIdParam: type: object properties: id: type: string format: uuid description: Category UUID from service_categories.category_id or categories.category_id. required: - id CategoryBoardIdParam: type: object properties: boardId: type: string format: uuid description: Board UUID used by ticket category tree queries. required: - boardId TicketCategory: type: object properties: category_id: type: string format: uuid category_name: type: string parent_category: type: - string - "null" format: uuid board_id: type: - string - "null" format: uuid display_order: type: number is_from_itil_standard: type: - boolean - "null" created_by: type: string format: uuid created_at: type: string format: date-time tenant: type: string format: uuid children: type: array items: {} depth: type: number path: type: string children_count: type: number required: - category_id - category_name - board_id - created_by - tenant description: Ticket category resource from the categories table, including optional hierarchy fields. The categories table has no description/updated_by/updated_at columns. TicketCategoryCreateRequest: type: object properties: category_name: type: string minLength: 1 maxLength: 255 board_id: type: string format: uuid parent_category: type: string format: uuid required: - category_name - board_id TicketCategoryUpdateRequest: type: object properties: category_name: type: string minLength: 1 maxLength: 255 board_id: type: string format: uuid parent_category: type: string format: uuid TicketCategoryListQuery: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a106 - asc - desc search: type: string created_from: type: string format: date-time created_to: type: string format: date-time updated_from: type: string format: date-time updated_to: type: string format: date-time category_name: type: string board_id: type: string format: uuid parent_category: type: string format: uuid is_parent: type: string enum: &a107 - "true" - "false" is_child: type: string enum: &a108 - "true" - "false" depth: type: string active: type: string enum: &a109 - "true" - "false" offset: type: string sort_by: type: string sort_order: type: string enum: &a110 - asc - desc include_hierarchy: type: string enum: &a111 - "true" - "false" category_type: type: string enum: &a112 - service - ticket CategoryMoveRequest: type: object properties: category_id: type: string format: uuid new_parent_id: type: - string - "null" format: uuid position: type: integer minimum: 0 required: - category_id CategorySearchQuery: type: object properties: search_term: type: string minLength: 1 category_type: type: string enum: &a113 - service - ticket board_id: type: string format: uuid include_inactive: type: string enum: &a114 - "true" - "false" limit: type: string offset: type: string required: - search_term CategoryAnalyticsQuery: type: object properties: category_type: type: string enum: &a115 - service - ticket board_id: type: string format: uuid date_from: type: string format: date-time date_to: type: string format: date-time include_usage: type: string enum: &a116 - "true" - "false" CategoryAnalyticsResponse: type: object properties: data: type: object properties: analytics: type: object additionalProperties: {} description: Aggregated category analytics from CategoryService.getCategoryAnalytics. generated_at: type: string format: date-time required: - analytics - generated_at required: - data CategoryTreeResponse: type: object properties: data: type: object properties: tree: type: array items: {} description: Hierarchical category tree nodes from CategoryService.getCategoryTree. total_categories: type: integer minimum: 0 required: - tree - total_categories required: - data BulkDeleteCategoriesRequest: type: object properties: category_ids: type: array items: type: string format: uuid minItems: 1 maxItems: 50 category_type: type: string enum: - service - ticket force: anyOf: - type: string enum: - "true" - "false" - type: boolean description: Optional force flag; schema accepts both boolean and string boolean values. required: - category_ids - category_type BulkDeleteCategoriesResponse: type: object properties: data: type: object properties: message: type: string success: type: integer minimum: 0 failed: type: integer minimum: 0 errors: type: array items: type: object additionalProperties: {} required: - message - success - failed required: - data PaginatedTicketCategoryResponse: type: object properties: data: type: array items: $ref: "#/components/schemas/TicketCategory" pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination PaginatedServiceCategoryResponse: type: object properties: data: type: array items: $ref: "#/components/schemas/ServiceCategory" pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination ServiceIdParams: type: object properties: id: type: string format: uuid description: Service UUID. required: - id ServicePrice: type: object properties: currency_code: type: string minLength: 3 maxLength: 3 rate: type: number required: - currency_code - rate ServiceCatalogEntry: type: object properties: service_id: type: string format: uuid tenant: type: string format: uuid service_name: type: string custom_service_type_id: type: string format: uuid billing_method: type: string enum: - fixed - hourly - usage default_rate: type: number unit_of_measure: type: string category_id: type: - string - "null" format: uuid tax_rate_id: type: - string - "null" format: uuid description: type: - string - "null" item_kind: type: string enum: - service - product is_active: type: boolean sku: type: - string - "null" cost: type: - number - "null" cost_currency: type: - string - "null" minLength: 3 maxLength: 3 vendor: type: - string - "null" manufacturer: type: - string - "null" product_category: type: - string - "null" is_license: type: boolean license_term: type: - string - "null" license_billing_cadence: type: - string - "null" service_type_name: type: string prices: type: array items: $ref: "#/components/schemas/ServicePrice" required: - service_id - tenant - service_name - custom_service_type_id - billing_method - default_rate - unit_of_measure description: Service catalog entry. ServiceEnvelope: type: object properties: data: $ref: "#/components/schemas/ServiceCatalogEntry" meta: type: object additionalProperties: {} required: - data PaginatedServiceEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/ServiceCatalogEntry" pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination ProductIdParams: type: object properties: id: type: string format: uuid description: Product UUID. required: - id ProductPrice: type: object properties: currency_code: type: string minLength: 3 maxLength: 3 rate: type: number required: - currency_code - rate ProductCatalogEntry: type: object properties: service_id: type: string format: uuid tenant: type: string format: uuid service_name: type: string custom_service_type_id: type: string format: uuid billing_method: type: string enum: - usage default_rate: type: number unit_of_measure: type: string category_id: type: - string - "null" format: uuid tax_rate_id: type: - string - "null" format: uuid description: type: - string - "null" item_kind: type: string enum: - product is_active: type: boolean sku: type: - string - "null" cost: type: - number - "null" cost_currency: type: - string - "null" minLength: 3 maxLength: 3 vendor: type: - string - "null" manufacturer: type: - string - "null" product_category: type: - string - "null" is_license: type: boolean license_term: type: - string - "null" license_billing_cadence: type: - string - "null" service_type_name: type: string prices: type: array items: $ref: "#/components/schemas/ProductPrice" required: - service_id - tenant - service_name - custom_service_type_id - billing_method - default_rate - unit_of_measure - item_kind description: Product catalog entry. ProductEnvelope: type: object properties: data: $ref: "#/components/schemas/ProductCatalogEntry" meta: type: object additionalProperties: {} required: - data PaginatedProductEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/ProductCatalogEntry" pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination ServiceTypeIdParams: type: object properties: id: type: string format: uuid description: Service type UUID. required: - id ServiceTypeListQuery: type: object properties: search: type: string is_active: type: boolean page: type: integer minimum: 1 limit: type: integer minimum: 1 maximum: 100 ServiceTypeResource: type: object properties: id: type: string format: uuid tenant: type: string format: uuid name: type: string is_active: type: boolean description: type: - string - "null" order_number: type: integer created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - tenant - name - is_active - order_number - created_at - updated_at description: Tenant-specific service type. ServiceTypeEnvelope: type: object properties: data: $ref: "#/components/schemas/ServiceTypeResource" meta: type: object additionalProperties: {} required: - data PaginatedServiceTypeEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/ServiceTypeResource" pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination WebhookIdParamV1: type: object properties: id: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: - id WebhookDeliveryParamsV1: type: object properties: id: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. delivery_id: type: string format: uuid description: Delivery UUID from webhook_deliveries.delivery_id (URL-derived). required: - id - delivery_id WebhookListQueryV1: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a122 - asc - desc name: type: string url: type: string event_type: type: string is_active: type: string enum: &a123 - "true" - "false" is_test_mode: type: string enum: &a124 - "true" - "false" payload_format: type: string enum: &a125 - json - xml - form_data - custom has_failures: type: string enum: &a126 - "true" - "false" last_delivery_from: type: string last_delivery_to: type: string delivery_rate_min: type: string delivery_rate_max: type: string query: type: string WebhookAnalyticsQueryV1: type: object properties: webhook_id: type: string format: uuid date_from: type: string format: date-time date_to: type: string format: date-time WebhookDeliveryQueryV1: type: object properties: page: type: string limit: type: string status: type: string enum: &a127 - pending - delivered - failed - retrying - abandoned from_date: type: string format: date-time to_date: type: string format: date-time TicketWebhookEventV1: type: string enum: - ticket.created - ticket.updated - ticket.status_changed - ticket.assigned - ticket.closed - ticket.comment.added description: Ticket-domain webhook events emitted by the eventBus subscriber. WebhookEventTypeV1: type: string enum: - ticket.created - ticket.updated - ticket.status_changed - ticket.assigned - ticket.closed - ticket.comment.added - project.created - project.updated - project.status_changed - project.assigned - project.closed - project.completed - project.task.created - project.task.updated - project.task.status_changed - project.task.assigned - project.task.completed - client.created - client.updated - contact.created - contact.updated - time.entry.created - time.entry.updated - time.entry.approved - invoice.created - invoice.finalized - invoice.sent - invoice.paid - asset.created - asset.updated - asset.maintenance.scheduled - asset.maintenance.completed - system.backup.completed - system.backup.failed - system.maintenance.started - system.maintenance.completed - workflow.execution.started - workflow.execution.completed - workflow.execution.failed - custom.event CreateWebhookBodyV1: type: object properties: name: type: string minLength: 1 description: type: string url: type: string format: uri method: type: string enum: - GET - POST - PUT - PATCH - DELETE event_types: type: array items: $ref: "#/components/schemas/WebhookEventTypeV1" minItems: 1 security: type: object additionalProperties: {} payload_format: type: string enum: - json - xml - form_data - custom content_type: type: string custom_headers: type: object additionalProperties: type: string event_filter: type: object additionalProperties: {} payload_fields: type: - object - "null" properties: ticket: type: - array - "null" items: type: string enum: &a20 - ticket_number - title - url - status_id - status_name - is_closed - previous_status_id - previous_status_name - priority_id - priority_name - client_id - client_name - contact_name_id - contact_name - contact_email - assigned_to - assigned_to_name - assigned_team_id - board_id - board_name - category_id - subcategory_id - entered_at - updated_at - closed_at - due_date - tags - comment - changes - comments project: type: - array - "null" items: type: string enum: &a21 - project_name - wbs_code - description - status_id - status_name - is_closed - previous_status_id - previous_status_name - client_id - client_name - contact_name_id - contact_name - contact_email - assigned_to - assigned_to_name - start_date - end_date - budgeted_hours - url - changes - phases - task_counts - task_id - phase_id - phase_name - task_name - estimated_hours - actual_hours - due_date - priority_id - priority_name - tags description: "Per-entity payload allowlist. null/{} = full payload everywhere. { ticket: null } = full ticket payload. { ticket: [] } = required-only. { ticket: [a,b] } = explicit allowlist plus required keys. Unknown entities and fields are rejected by WEBHOOK_PAYLOAD_FIELDS_BY_ENTITY in lib/webhooks/payloadFields. Supported fields: ticket: ticket_number, title, url, status_id, status_name, is_closed, previous_status_id, previous_status_name, priority_id, priority_name, client_id, client_name, contact_name_id, contact_name, contact_email, assigned_to, assigned_to_name, assigned_team_id, board_id, board_name, category_id, subcategory_id, entered_at, updated_at, closed_at, due_date, tags, comment, changes, comments; project: project_name, wbs_code, description, status_id, status_name, is_closed, previous_status_id, previous_status_name, client_id, client_name, contact_name_id, contact_name, contact_email, assigned_to, assigned_to_name, start_date, end_date, budgeted_hours, url, changes, phases, task_counts, task_id, phase_id, phase_name, task_name, estimated_hours, actual_hours, due_date, priority_id, priority_name, tags." payload_transformation: type: object additionalProperties: {} retry_config: type: object additionalProperties: {} is_active: type: boolean is_test_mode: type: boolean verify_ssl: type: boolean secret_token: type: string rate_limit: type: object additionalProperties: {} metadata: type: object additionalProperties: {} tags: type: array items: type: string required: - name - url - event_types WebhookTestBodyV1: type: object properties: webhook_id: type: string format: uuid test_event_type: $ref: "#/components/schemas/WebhookEventTypeV1" test_payload: type: object additionalProperties: {} override_url: type: string format: uri required: - test_event_type WebhookTemplateBodyV1: type: object properties: name: type: string description: type: string category: type: string default_config: type: object additionalProperties: {} required_fields: type: array items: type: string supported_events: type: array items: $ref: "#/components/schemas/WebhookEventTypeV1" is_system_template: type: boolean required: - name - category - default_config WebhookTemplateCreateBodyV1: type: object properties: name: type: string minLength: 1 url: type: string format: uri custom_config: type: object additionalProperties: {} required: - name - url WebhookSignatureBodyV1: type: object properties: algorithm: type: string enum: - sha1 - sha256 - sha512 description: Only sha256 is currently honored; other values yield valid=false. signature: type: string description: Either the raw v1 signature, or the canonical "t=,v1=" header value. When raw and a timestamp is supplied, the controller assembles the canonical form before verifying. timestamp: type: number description: Unix-seconds timestamp paired with a raw v1 signature. body: type: string description: Exact request body bytes to verify against. webhook_id: type: string format: uuid description: Resolves the signing secret from webhooks.signing_secret_vault_path. secret_vault_path: type: string description: Vault key (basename of secret_vault_path) used when no webhook_id is supplied. webhook_id or secret_vault_path is required. required: - algorithm - signature - body description: "Verification request: webhook_id OR secret_vault_path is required." WebhookApiErrorV1: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error WebhookRecordV1: type: object properties: webhook_id: type: string format: uuid tenant: type: string format: uuid name: type: string description: type: - string - "null" url: type: string method: type: string enum: - GET - POST - PUT - PATCH - DELETE event_types: type: array items: $ref: "#/components/schemas/WebhookEventTypeV1" security: type: - object - "null" additionalProperties: {} payload_format: type: string enum: - json - xml - form_data - custom content_type: type: string custom_headers: type: - object - "null" additionalProperties: type: string event_filter: type: - object - "null" additionalProperties: {} payload_fields: type: - object - "null" properties: ticket: type: - array - "null" items: type: string enum: *a20 project: type: - array - "null" items: type: string enum: *a21 description: "Per-entity payload allowlist. null/{} = full payload everywhere. { ticket: null } = full ticket payload. { ticket: [] } = required-only. { ticket: [a,b] } = explicit allowlist plus required keys. Unknown entities and fields are rejected by WEBHOOK_PAYLOAD_FIELDS_BY_ENTITY in lib/webhooks/payloadFields. Supported fields: ticket: ticket_number, title, url, status_id, status_name, is_closed, previous_status_id, previous_status_name, priority_id, priority_name, client_id, client_name, contact_name_id, contact_name, contact_email, assigned_to, assigned_to_name, assigned_team_id, board_id, board_name, category_id, subcategory_id, entered_at, updated_at, closed_at, due_date, tags, comment, changes, comments; project: project_name, wbs_code, description, status_id, status_name, is_closed, previous_status_id, previous_status_name, client_id, client_name, contact_name_id, contact_name, contact_email, assigned_to, assigned_to_name, start_date, end_date, budgeted_hours, url, changes, phases, task_counts, task_id, phase_id, phase_name, task_name, estimated_hours, actual_hours, due_date, priority_id, priority_name, tags." payload_transformation: type: - object - "null" additionalProperties: {} retry_config: type: - object - "null" additionalProperties: {} is_active: type: boolean is_test_mode: type: boolean verify_ssl: type: boolean total_deliveries: type: integer successful_deliveries: type: integer failed_deliveries: type: integer last_delivery_at: type: - string - "null" format: date-time last_success_at: type: - string - "null" format: date-time last_failure_at: type: - string - "null" format: date-time auto_disabled_at: type: - string - "null" format: date-time created_at: type: string format: date-time updated_at: type: string format: date-time tags: type: array items: type: string required: - webhook_id - tenant - name - description - url - method - event_types - custom_headers - is_active - verify_ssl - total_deliveries - successful_deliveries - failed_deliveries - created_at - updated_at WebhookDeliveryRecordV1: type: object properties: tenant: type: string format: uuid delivery_id: type: string format: uuid webhook_id: type: string format: uuid event_id: type: string event_type: type: string request_headers: type: - object - "null" additionalProperties: type: string request_body: {} response_status_code: type: - integer - "null" response_headers: type: - object - "null" additionalProperties: type: string response_body: type: - string - "null" status: type: string enum: - pending - delivered - failed - retrying - abandoned attempt_number: type: integer duration_ms: type: - integer - "null" error_message: type: - string - "null" next_retry_at: type: - string - "null" format: date-time is_test: type: boolean attempted_at: type: string format: date-time completed_at: type: - string - "null" format: date-time required: - tenant - delivery_id - webhook_id - event_id - event_type - request_headers - response_status_code - response_headers - response_body - status - attempt_number - duration_ms - error_message - next_retry_at - is_test - attempted_at - completed_at WebhookHealthV1: type: object properties: webhook_id: type: string format: uuid status: type: string enum: - healthy - failing - disabled is_active: type: boolean auto_disabled_at: type: - string - "null" format: date-time total_deliveries: type: integer successful_deliveries: type: integer failed_deliveries: type: integer success_rate: type: number description: Fraction in [0,1]; 1 when there are no deliveries yet. last_delivery_at: type: - string - "null" format: date-time last_success_at: type: - string - "null" format: date-time last_failure_at: type: - string - "null" format: date-time checked_at: type: string format: date-time required: - webhook_id - status - is_active - auto_disabled_at - total_deliveries - successful_deliveries - failed_deliveries - success_rate - last_delivery_at - last_success_at - last_failure_at - checked_at WebhookTestResultV1: type: object properties: test_id: type: string format: uuid description: event_id stamped on the test envelope. delivery_id: type: string format: uuid success: type: boolean status_code: type: - integer - "null" response_time_ms: type: - integer - "null" response_body: type: - string - "null" error_message: type: - string - "null" tested_at: type: string format: date-time required: - test_id - delivery_id - success - tested_at WebhookSecretRotationV1: type: object properties: webhook_id: type: string format: uuid signing_secret: type: string description: 32-byte base64url secret; only returned at rotation time. required: - webhook_id - signing_secret WebhookSubscriptionsResponseV1: type: object properties: webhook_id: type: string format: uuid event_types: type: array items: $ref: "#/components/schemas/WebhookEventTypeV1" required: - webhook_id - event_types WebhookSignatureValidationV1: type: object properties: valid: type: boolean required: - valid WebhookEventListV1: type: array items: $ref: "#/components/schemas/WebhookEventTypeV1" WebhookAnalyticsResponseV1: type: object properties: webhook_id: type: string format: uuid date_from: type: string format: date-time date_to: type: string format: date-time metrics: type: object properties: total_deliveries: type: integer successful_deliveries: type: integer failed_deliveries: type: integer success_rate: type: number average_response_time: type: number deliveries_by_status: type: object additionalProperties: type: integer deliveries_by_event_type: type: object additionalProperties: type: integer deliveries_timeline: type: array items: type: object properties: date: type: string successful: type: integer failed: type: integer required: - date - successful - failed response_time_percentiles: type: object properties: p50: type: number p90: type: number p95: type: number p99: type: number required: - p50 - p90 - p95 - p99 required: - total_deliveries - successful_deliveries - failed_deliveries - success_rate - average_response_time - deliveries_by_status - deliveries_by_event_type - deliveries_timeline required: - date_from - date_to - metrics WebhookTemplateRecordV1: type: object properties: template_id: type: string format: uuid name: type: string description: type: string category: type: string default_config: type: object properties: url_template: type: string method: type: string enum: - GET - POST - PUT - PATCH - DELETE headers: type: object additionalProperties: type: string payload_template: type: string security_type: type: string enum: - none - basic_auth - bearer_token - api_key - hmac_signature - oauth2 required: - method - payload_template required_fields: type: array items: type: string supported_events: type: array items: $ref: "#/components/schemas/WebhookEventTypeV1" is_system_template: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time tenant: type: - string - "null" format: uuid required: - template_id - name - category - default_config - created_at - updated_at WebhookListResponseV1: type: object properties: data: type: array items: $ref: "#/components/schemas/WebhookRecordV1" pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination WebhookDeliveryListResponseV1: type: object properties: data: type: array items: $ref: "#/components/schemas/WebhookDeliveryRecordV1" pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination WebhookEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookRecordV1" meta: type: object additionalProperties: {} required: - data WebhookDeliveryEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookDeliveryRecordV1" meta: type: object additionalProperties: {} required: - data WebhookHealthEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookHealthV1" meta: type: object additionalProperties: {} required: - data WebhookTestResultEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookTestResultV1" meta: type: object additionalProperties: {} required: - data WebhookSecretRotationEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookSecretRotationV1" meta: type: object additionalProperties: {} required: - data WebhookSubscriptionsEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookSubscriptionsResponseV1" meta: type: object additionalProperties: {} required: - data WebhookSignatureValidationEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookSignatureValidationV1" meta: type: object additionalProperties: {} required: - data WebhookEventListEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookEventListV1" meta: type: object additionalProperties: {} required: - data WebhookAnalyticsEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookAnalyticsResponseV1" meta: type: object additionalProperties: {} required: - data WebhookTemplateListEnvelopeV1: type: object properties: data: type: array items: $ref: "#/components/schemas/WebhookTemplateRecordV1" meta: type: object additionalProperties: {} required: - data WebhookTemplateEnvelopeV1: type: object properties: data: $ref: "#/components/schemas/WebhookTemplateRecordV1" meta: type: object additionalProperties: {} required: - data TicketWebhookChangeEntryV1: type: object properties: previous: {} new: {} TicketWebhookCommentBlockV1: type: object properties: text: type: string author: type: - string - "null" timestamp: type: string format: date-time is_internal: type: boolean required: - text - author - timestamp - is_internal TicketWebhookCommentsEntryV1: type: object properties: comment_id: type: string format: uuid text: type: string author: type: - string - "null" is_internal: type: boolean is_resolution: type: boolean created_at: type: string format: date-time updated_at: type: - string - "null" format: date-time required: - comment_id - text - author - is_internal - is_resolution - created_at - updated_at TicketWebhookDataV1: type: object properties: ticket_id: type: string format: uuid description: Always present; the correlation key. ticket_number: type: - string - "null" title: type: - string - "null" url: type: string format: uri status_id: type: - string - "null" format: uuid status_name: type: - string - "null" is_closed: type: boolean previous_status_id: type: - string - "null" format: uuid description: Only populated on ticket.status_changed. previous_status_name: type: - string - "null" description: Only populated on ticket.status_changed. priority_id: type: - string - "null" format: uuid priority_name: type: - string - "null" client_id: type: - string - "null" format: uuid client_name: type: - string - "null" contact_name_id: type: - string - "null" format: uuid contact_name: type: - string - "null" contact_email: type: - string - "null" assigned_to: type: - string - "null" format: uuid assigned_to_name: type: - string - "null" assigned_team_id: type: - string - "null" format: uuid board_id: type: - string - "null" format: uuid board_name: type: - string - "null" category_id: type: - string - "null" format: uuid subcategory_id: type: - string - "null" format: uuid entered_at: type: - string - "null" format: date-time updated_at: type: - string - "null" format: date-time closed_at: type: - string - "null" format: date-time due_date: type: - string - "null" tags: type: array items: type: string changes: type: object additionalProperties: $ref: "#/components/schemas/TicketWebhookChangeEntryV1" description: Field-level diff. Only on ticket.updated. comment: allOf: - $ref: "#/components/schemas/TicketWebhookCommentBlockV1" - description: Newly-added comment. Only on ticket.comment.added. Attachments are never included. comments: type: array items: $ref: "#/components/schemas/TicketWebhookCommentsEntryV1" description: Full comment thread, oldest first. Only included when the webhook subscription opted into the `comments` field. required: - ticket_id WebhookOutboundHeadersV1: type: object properties: x-alga-signature: type: string description: "`t=,v1=` over `${timestamp}.${raw_body}`." x-alga-webhook-id: type: string format: uuid x-alga-event-id: type: string format: uuid x-alga-event-type: $ref: "#/components/schemas/WebhookEventTypeV1" x-alga-delivery-id: type: string format: uuid x-alga-delivery-attempt: type: string description: Stringified attempt count, starts at 1. required: - x-alga-signature - x-alga-webhook-id - x-alga-event-id - x-alga-event-type - x-alga-delivery-id - x-alga-delivery-attempt TicketCreatedDeliveryV1: type: object properties: event_id: type: string format: uuid event_type: type: string enum: - ticket.created occurred_at: type: string format: date-time tenant_id: type: string format: uuid data: $ref: "#/components/schemas/TicketWebhookDataV1" required: - event_id - event_type - occurred_at - tenant_id - data TicketUpdatedDeliveryV1: type: object properties: event_id: type: string format: uuid event_type: type: string enum: - ticket.updated occurred_at: type: string format: date-time tenant_id: type: string format: uuid data: $ref: "#/components/schemas/TicketWebhookDataV1" required: - event_id - event_type - occurred_at - tenant_id - data TicketStatusChangedDeliveryV1: type: object properties: event_id: type: string format: uuid event_type: type: string enum: - ticket.status_changed occurred_at: type: string format: date-time tenant_id: type: string format: uuid data: $ref: "#/components/schemas/TicketWebhookDataV1" required: - event_id - event_type - occurred_at - tenant_id - data TicketAssignedDeliveryV1: type: object properties: event_id: type: string format: uuid event_type: type: string enum: - ticket.assigned occurred_at: type: string format: date-time tenant_id: type: string format: uuid data: $ref: "#/components/schemas/TicketWebhookDataV1" required: - event_id - event_type - occurred_at - tenant_id - data TicketClosedDeliveryV1: type: object properties: event_id: type: string format: uuid event_type: type: string enum: - ticket.closed occurred_at: type: string format: date-time tenant_id: type: string format: uuid data: $ref: "#/components/schemas/TicketWebhookDataV1" required: - event_id - event_type - occurred_at - tenant_id - data TicketCommentAddedDeliveryV1: type: object properties: event_id: type: string format: uuid event_type: type: string enum: - ticket.comment.added occurred_at: type: string format: date-time tenant_id: type: string format: uuid data: $ref: "#/components/schemas/TicketWebhookDataV1" required: - event_id - event_type - occurred_at - tenant_id - data WorkflowV1MissingApiError: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error WorkflowV1MissingRouteResponse: type: string description: Default Next.js not-found response body for missing route handlers. ProjectIdParams: type: object properties: id: type: string format: uuid description: Project UUID. required: - id ProjectPhaseTaskParams: type: object properties: id: type: string format: uuid description: Project UUID. phaseId: type: string format: uuid description: Project phase UUID. required: - id - phaseId ProjectTaskIdParams: type: object properties: taskId: type: string format: uuid description: Project task UUID. required: - taskId ProjectTaskApiResponse: type: object properties: task_id: type: string format: uuid phase_id: type: string format: uuid task_name: type: string description: type: - string - "null" assigned_to: type: - string - "null" format: uuid estimated_hours: type: - number - "null" actual_hours: type: - number - "null" project_status_mapping_id: type: string format: uuid due_date: type: - string - "null" format: date-time priority_id: type: - string - "null" format: uuid task_type_key: type: string wbs_code: type: string order_key: type: string created_at: type: string format: date-time updated_at: type: string format: date-time tenant: type: string format: uuid tags: type: array items: type: string required: - task_id - phase_id - task_name - description - assigned_to - estimated_hours - actual_hours - project_status_mapping_id - priority_id - task_type_key - wbs_code - created_at - updated_at - tenant ProjectTaskEnvelope: type: object properties: data: $ref: "#/components/schemas/ProjectTaskApiResponse" required: - data ProjectTaskListEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/ProjectTaskApiResponse" required: - data ProjectTaskStatusMappingApiResponse: type: object properties: project_status_mapping_id: type: string format: uuid project_id: type: string format: uuid status_id: type: - string - "null" format: uuid standard_status_id: type: - string - "null" format: uuid is_standard: type: boolean custom_name: type: - string - "null" display_order: type: number is_visible: type: boolean tenant: type: string format: uuid status_name: type: string name: type: string is_closed: type: boolean required: - project_status_mapping_id - project_id - is_standard - custom_name - display_order - is_visible - tenant - status_name - name - is_closed ProjectTaskStatusMappingListEnvelope: type: object properties: data: type: array items: $ref: "#/components/schemas/ProjectTaskStatusMappingApiResponse" required: - data ProjectTaskUpdateRequest: type: object properties: task_name: type: string minLength: 1 maxLength: 255 description: type: string assigned_to: type: string format: uuid estimated_hours: type: number minimum: 0 due_date: type: string format: date-time priority_id: type: string format: uuid task_type_key: type: string default: general project_status_mapping_id: type: string format: uuid wbs_code: type: string tags: type: array items: type: string description: Payload for updating a project task. To change task status, send project_status_mapping_id as a UUID. This endpoint does not accept project_id, phase_id, or human-readable status names. ProjectTaskCreateRequest: type: object properties: task_name: type: string minLength: 1 maxLength: 255 description: type: string assigned_to: type: string format: uuid estimated_hours: type: number minimum: 0 due_date: type: string format: date-time priority_id: type: string format: uuid task_type_key: type: string default: general project_status_mapping_id: type: string format: uuid wbs_code: type: string tags: type: array items: type: string required: - task_name - project_status_mapping_id description: Payload for creating a project task within a phase. Provide project_status_mapping_id as a UUID from the project task status mappings endpoint. The phaseId path parameter selects which phase will receive the task. WorkV1IdParam: type: object properties: id: type: string format: uuid description: UUID path identifier from underlying resource tables. required: - id WorkV1ProjectPhaseParams: type: object properties: id: type: string format: uuid description: Project UUID from projects.project_id. phaseId: type: string format: uuid description: Project phase UUID from project_phases.phase_id. required: - id - phaseId WorkV1ProjectTaskParam: type: object properties: taskId: type: string format: uuid description: Project task UUID from project_tasks.task_id. required: - taskId WorkV1SessionParam: type: object properties: sessionId: type: string description: Active time-tracking session identifier. required: - sessionId WorkV1TagEntityParams: type: object properties: entityType: type: string description: Tagged entity type from route segment. entityId: type: string description: Tagged entity id from route segment. required: - entityType - entityId WorkV1ListQuery: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a128 - asc - desc fields: type: string search: type: string query: type: string WorkV1GenericBody: type: object additionalProperties: {} description: Controller/service-specific payload; see source route/controller for exact required shape. WorkV1CreateProjectBody: type: object properties: project_name: type: string status: type: string start_date: type: string end_date: type: string assigned_to: type: string format: uuid assigned_team_id: type: string format: uuid client_id: type: string format: uuid required: - project_name WorkV1CreateTicketBody: type: object properties: title: type: string summary: type: string client_id: type: string format: uuid board_id: type: string format: uuid priority_id: type: string format: uuid status_id: type: string format: uuid WorkV1CreateTagBody: type: object properties: tag_text: type: string text: type: string color: type: string background_color: type: string required: - tag_text WorkV1CreateTimeEntryBody: type: object properties: work_item_type: type: string work_item_id: type: string user_id: type: string format: uuid started_at: type: string ended_at: type: string duration_minutes: type: number billable_minutes: type: number notes: type: string WorkV1CreateTimeSheetBody: type: object properties: user_id: type: string format: uuid period_id: type: string format: uuid status: type: string notes: type: string WorkV1ApiError: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error WorkV1ApiSuccess: type: object properties: data: anyOf: - type: object additionalProperties: {} - type: array items: type: object additionalProperties: {} meta: type: object additionalProperties: {} required: - data WorkV1ApiPaginated: type: object properties: data: type: array items: type: object additionalProperties: {} pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer hasNext: type: boolean hasPrev: type: boolean required: - page - limit - total - totalPages - hasNext - hasPrev meta: type: object additionalProperties: {} required: - data - pagination WorkV1TicketCommentParams: type: object properties: id: type: string format: uuid description: Ticket UUID. commentId: type: string format: uuid description: Comment UUID. required: - id - commentId WorkV1TicketDocumentParams: type: object properties: id: type: string format: uuid description: Ticket UUID. documentId: type: string format: uuid description: Document UUID. required: - id - documentId WorkV1TicketStatusesQuery: type: object properties: board_id: type: string format: uuid description: Filter statuses to this board. WorkV1TicketCommentUpdateBody: type: object properties: comment_text: type: string minLength: 1 maxLength: 5000 description: Updated comment text (1–5000 visible chars). required: - comment_text WorkV1TicketReactionBody: type: object properties: emoji: type: string description: Emoji to toggle on the comment. required: - emoji WorkV1TicketMaterialBody: type: object properties: service_id: type: string format: uuid quantity: type: number exclusiveMinimum: 0 rate: type: number minimum: 0 currency_code: type: string minLength: 3 maxLength: 3 description: type: - string - "null" maxLength: 1000 required: - service_id - quantity - rate - currency_code QuoteIdParamV1: type: object properties: id: type: string format: uuid description: Quote UUID from quotes.quote_id. required: - id QuoteItemParamsV1: type: object properties: id: type: string format: uuid description: Quote UUID from quotes.quote_id. itemId: type: string format: uuid description: Quote item UUID from quote_items.quote_item_id. required: - id - itemId ContractLineParamsV1: type: object properties: contractId: type: string format: uuid description: Contract UUID from contracts.contract_id. contractLineId: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: - contractId - contractLineId ContractIdParamV1: type: object properties: contractId: type: string format: uuid description: Contract UUID from contracts.contract_id. required: - contractId QuotesContractsListQueryV1: type: object properties: page: type: string limit: type: string sort: type: string order: type: string enum: &a129 - asc - desc search: type: string status: type: string include_items: type: string enum: &a130 - "true" - "false" include_client: type: string enum: &a131 - "true" - "false" QuotesContractsGenericBodyV1: type: object additionalProperties: {} description: Controller/service-specific payload; see quote/contract controller schemas for exact required fields. CreateQuoteBodyV1: type: object properties: client_id: type: string format: uuid title: type: string quote_number: type: string valid_until: type: string notes: type: string terms: type: string items: type: array items: type: object additionalProperties: {} required: - client_id CreateContractBodyV1: type: object properties: client_id: type: string format: uuid contract_name: type: string start_date: type: string end_date: type: string billing_frequency: type: string required: - client_id QuotesContractsApiErrorV1: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error QuotesContractsApiSuccessV1: type: object properties: data: anyOf: - type: object additionalProperties: {} - type: array items: type: object additionalProperties: {} meta: type: object additionalProperties: {} required: - data QuotesContractsApiPaginatedV1: type: object properties: data: type: array items: type: object additionalProperties: {} pagination: type: object properties: page: type: integer limit: type: integer total: type: integer totalPages: type: integer required: - page - limit - total - totalPages meta: type: object additionalProperties: {} _links: type: object additionalProperties: {} required: - data FeatureFlagsPostBodyV1: type: object properties: flags: type: array items: type: string context: type: object properties: userRole: type: string companySize: type: string enum: - small - medium - large - enterprise subscriptionPlan: type: string customProperties: type: object additionalProperties: {} FeatureAccessBodyV1: type: object properties: user_id: type: string format: uuid feature_name: type: string required: - feature_name MetaUtilityApiErrorV1: type: object properties: error: {} message: type: string details: {} success: type: boolean MetaUtilityApiSuccessV1: type: object properties: data: anyOf: - type: object additionalProperties: {} - type: array items: type: object additionalProperties: {} - type: string - type: number - type: boolean - type: "null" flags: type: object additionalProperties: {} context: type: object additionalProperties: {} enabled: type: boolean reason: type: string usageStatsEnabled: type: boolean controlledBy: type: string message: type: string success: type: boolean EeInventoryApiError: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error EeInventoryMissingRouteResponse: type: string description: Default Next.js not-found response body for missing route handlers. MiddlewareUnauthorizedResponse: type: object properties: error: type: string description: "Middleware authentication error message, such as Unauthorized: API key missing." required: - error SoftwareOneAgreement: type: object properties: id: type: string description: SoftwareOne agreement identifier, such as agr-001. This is an external SoftwareOne-style ID, not an Alga UUID. name: type: string description: Human-readable agreement name. product: type: string description: Product or SKU name associated with the agreement. vendor: type: string description: Software vendor name, such as Microsoft or Adobe. consumer: type: string description: End-customer organization name for the agreement. status: type: string enum: - active - inactive - pending - expired description: Agreement status. currency: type: string description: Three-letter billing currency code, such as USD. spxy: type: number description: Annual SPx value from SoftwareOne dummy data. marginRpxy: type: number description: Margin RPxY value from SoftwareOne dummy data. operations: type: string enum: - visible - hidden - restricted description: Operational visibility state for the agreement. billingConfigId: type: string description: SoftwareOne billing configuration identifier associated with the agreement. localConfig: type: object properties: autoRenewal: type: boolean description: Whether local auto-renewal is enabled. notificationDays: type: integer description: Days before renewal/expiry to notify. markup: type: number description: Optional local markup percentage used by richer SoftwareOne schemas. notes: type: string description: Optional local notes. tags: type: array items: type: string description: Optional local tags. description: Locally editable configuration metadata. Current MVP data includes autoRenewal and notificationDays. required: - id - name - product - vendor - consumer - status - currency - spxy - marginRpxy - operations - billingConfigId SoftwareOneAgreementDetail: allOf: - $ref: "#/components/schemas/SoftwareOneAgreement" - type: object properties: startDate: type: string description: Agreement start date in YYYY-MM-DD format. endDate: type: string description: Agreement end date in YYYY-MM-DD format. billingCycle: type: string description: Billing cycle cadence, such as monthly or annual. paymentTerms: type: string description: Payment terms, such as Net 30. description: type: string description: Free-text agreement description. contactPerson: type: string description: Primary contact name for the agreement. contactEmail: type: string format: email description: Primary contact email address. licenseCount: type: integer description: Number of licenses covered by the agreement. pricePerLicense: type: number description: Price per license in the agreement currency. SoftwareOneStatement: type: object properties: id: type: string description: SoftwareOne statement identifier, such as stmt-001. This is an external SoftwareOne-style ID, not an Alga UUID. statementNumber: type: string description: Human-readable statement number, such as STMT-2024-001. period: type: string description: Billing period in YYYY-MM format. consumer: type: string description: End-customer organization name. consumerId: type: string description: SoftwareOne consumer identifier. agreementName: type: string description: Human-readable name of the associated agreement. agreementId: type: string description: SoftwareOne agreement identifier associated with this statement. totalAmount: type: number description: Total statement amount in the billing currency. currency: type: string description: Three-letter billing currency code, such as USD. lineItemCount: type: integer description: Number of line-item charges on the statement. status: type: string enum: - draft - finalized - imported description: Statement lifecycle status used by the MVP handler. dueDate: type: string description: Payment due date in YYYY-MM-DD format. createdAt: type: string description: ISO 8601 timestamp when the statement was created. importedAt: type: - string - "null" description: ISO 8601 timestamp when imported into Alga, or null if not imported. subtotal: type: number description: Statement subtotal before tax. Present on detail responses. taxAmount: type: number description: Statement tax amount. Present on detail responses. description: type: string description: Statement description. Present on detail responses. billingAddress: type: object properties: client: type: string description: Billing client organization name. street: type: string description: Street address. city: type: string description: City. state: type: string description: State or province. zipCode: type: string description: Postal or ZIP code. country: type: string description: Country. required: - client - street - city - state - zipCode - country description: Billing address. Present on detail responses. required: - id - statementNumber - period - consumer - consumerId - agreementName - agreementId - totalAmount - currency - lineItemCount - status - dueDate - createdAt - importedAt SoftwareOnePaginationMeta: type: object properties: total: type: integer description: Total records returned by the current dummy implementation. page: type: integer description: Current page number. Currently hardcoded to 1. pageSize: type: integer description: Page size. Currently hardcoded to 50. required: - total - page - pageSize SoftwareOneAgreementsListResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: type: array items: $ref: "#/components/schemas/SoftwareOneAgreement" description: SoftwareOne agreement records. meta: $ref: "#/components/schemas/SoftwareOnePaginationMeta" required: - success - data - meta SoftwareOneAgreementDetailResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: $ref: "#/components/schemas/SoftwareOneAgreementDetail" required: - success - data SoftwareOneStatementsListResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: type: array items: $ref: "#/components/schemas/SoftwareOneStatement" description: SoftwareOne statement records. meta: $ref: "#/components/schemas/SoftwareOnePaginationMeta" required: - success - data - meta SoftwareOneStatementDetailResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: $ref: "#/components/schemas/SoftwareOneStatement" required: - success - data SoftwareOneCharge: type: object properties: id: type: string description: SoftwareOne charge identifier, unique within the statement, such as 1-1. statementId: type: string description: Parent SoftwareOne statement identifier, such as stmt-001. description: type: string description: Human-readable line item description. product: type: string description: Product or SKU for the charge. quantity: type: number description: Quantity billed for this line item. unitPrice: type: number description: Unit price in the statement currency. totalAmount: type: number description: Total line amount. agreementId: type: string description: Related SoftwareOne agreement identifier, such as agr-001. period: type: string description: Billing period in YYYY-MM format. category: type: string description: Charge category, such as Software License, Compute, Storage, or Support. required: - id - statementId - description - product - quantity - unitPrice - totalAmount - agreementId - period - category SoftwareOneChargesListResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: type: array items: $ref: "#/components/schemas/SoftwareOneCharge" description: Charge line items for the requested statement. Unknown statement IDs return an empty array. meta: type: object properties: total: type: integer description: Number of charge records returned. statementId: type: string description: Statement ID from the path parameter. required: - total - statementId required: - success - data - meta SoftwareOneFullSyncResponse: type: object properties: success: type: boolean enum: - true description: Sync request completed successfully. message: type: string description: Human-readable sync result message. data: type: object properties: agreementsCount: type: integer description: Number of agreements synced. Zero when syncAgreements is false. statementsCount: type: integer description: Number of statements synced. Zero when syncStatements is false. syncedAt: type: string format: date-time description: ISO timestamp when the dummy sync completed. required: - agreementsCount - statementsCount - syncedAt required: - success - message - data ExtensionIdParams: type: object properties: extensionId: type: string description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. required: - extensionId ExtensionScopedIdParams: type: object properties: extensionId: type: string description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. id: type: string description: SoftwareOne-style external record identifier, such as agr-001 or stmt-001. This is not an Alga UUID. required: - extensionId - id GenericExtensionAgreementsListResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: type: array items: $ref: "#/components/schemas/SoftwareOneAgreement" description: Agreement records returned by the generic extension MVP handler. meta: type: object properties: total: type: integer description: Number of agreements returned. extensionId: type: string description: Extension ID echoed from the path. required: - total - extensionId required: - success - data - meta GenericExtensionAgreementDetailResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: $ref: "#/components/schemas/SoftwareOneAgreementDetail" meta: type: object properties: extensionId: type: string description: Extension ID echoed from the path. required: - extensionId required: - success - data - meta GenericExtensionStatementsListResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: type: array items: $ref: "#/components/schemas/SoftwareOneStatement" description: Statement records returned by the generic extension MVP handler. meta: type: object properties: total: type: integer description: Number of statements returned. extensionId: type: string description: Extension ID echoed from the path. required: - total - extensionId required: - success - data - meta GenericExtensionStatementDetailResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: $ref: "#/components/schemas/SoftwareOneStatement" meta: type: object properties: extensionId: type: string description: Extension ID echoed from the path. required: - extensionId required: - success - data - meta GenericExtensionChargesListResponse: type: object properties: success: type: boolean enum: - true description: Request succeeded. data: type: array items: $ref: "#/components/schemas/SoftwareOneCharge" description: Charge line items. Unknown statement IDs return an empty array. meta: type: object properties: total: type: integer description: Number of charge records returned. statementId: type: string description: Statement ID from the path parameter. extensionId: type: string description: Extension ID echoed from the path. required: - total - statementId - extensionId required: - success - data - meta GenericExtensionSyncResponse: type: object properties: success: type: boolean enum: - true description: Sync request completed successfully. message: type: string description: Human-readable sync result message. data: type: object properties: agreementsCount: type: integer description: Number of agreements synced. Zero when syncAgreements is false. statementsCount: type: integer description: Number of statements synced. Zero when syncStatements is false. syncedAt: type: string format: date-time description: ISO timestamp when the dummy sync completed. extensionId: type: string description: Extension ID echoed from the path. required: - agreementsCount - statementsCount - syncedAt - extensionId required: - success - message - data SoftwareOneSyncResponse: type: object properties: success: type: boolean enum: - true description: Sync request completed successfully. message: type: string description: Human-readable sync result message. count: type: integer description: Number of dummy records included in the sync result. required: - success - message - count SoftwareOneSyncRequest: type: object properties: fullSync: type: boolean description: Optional future full-sync flag. Currently ignored by the MVP handlers. syncStatements: type: boolean description: Optional future statement sync flag. Currently ignored by the MVP handlers. syncAgreements: type: boolean description: Optional future agreement sync flag. Currently ignored by the MVP handlers. description: Sync options. The current SoftwareOne MVP handlers parse JSON but ignore all body fields. SoftwareOneErrorResponse: type: object properties: success: type: boolean enum: - false description: Request failed. error: type: string description: Human-readable error message. required: - success - error SoftwareOneIdParams: type: object properties: id: type: string description: SoftwareOne external identifier, such as agr-001 or stmt-001. This is not an Alga UUID. required: - id StoragePutRequest: type: object properties: value: {} metadata: type: object additionalProperties: {} ttlSeconds: type: integer exclusiveMinimum: 0 ifRevision: type: integer minimum: 0 schemaVersion: type: integer exclusiveMinimum: 0 StoragePutResponse: type: object properties: namespace: type: string key: type: string revision: type: integer exclusiveMinimum: 0 ttlExpiresAt: type: - string - "null" format: date-time createdAt: type: string format: date-time updatedAt: type: string format: date-time required: - namespace - key - revision - ttlExpiresAt - createdAt - updatedAt StorageGetResponse: type: object properties: namespace: type: string key: type: string revision: type: integer exclusiveMinimum: 0 value: {} metadata: type: object additionalProperties: {} ttlExpiresAt: type: - string - "null" format: date-time createdAt: type: string format: date-time updatedAt: type: string format: date-time required: - namespace - key - revision - metadata - ttlExpiresAt - createdAt - updatedAt StorageListQuery: type: object properties: limit: type: integer minimum: 1 maximum: 100 cursor: type: string keyPrefix: type: string maxLength: 256 includeValues: type: boolean includeMetadata: type: boolean StorageListItem: type: object properties: namespace: type: string key: type: string revision: type: integer exclusiveMinimum: 0 value: {} metadata: type: object additionalProperties: {} ttlExpiresAt: type: - string - "null" format: date-time createdAt: type: string format: date-time updatedAt: type: string format: date-time required: - namespace - key - revision - ttlExpiresAt - createdAt - updatedAt StorageListResponse: type: object properties: items: type: array items: $ref: "#/components/schemas/StorageListItem" nextCursor: type: - string - "null" required: - items - nextCursor StorageBulkPutRequest: type: object properties: items: type: array items: type: object properties: key: type: string minLength: 1 maxLength: 256 value: {} metadata: type: object additionalProperties: {} ttlSeconds: type: integer exclusiveMinimum: 0 ifRevision: type: integer minimum: 0 schemaVersion: type: integer exclusiveMinimum: 0 required: - key minItems: 1 required: - items StorageBulkPutResponse: type: object properties: namespace: type: string items: type: array items: type: object properties: key: type: string revision: type: integer exclusiveMinimum: 0 ttlExpiresAt: type: - string - "null" format: date-time required: - key - revision - ttlExpiresAt required: - namespace - items StorageNamespaceParams: type: object properties: namespace: type: string minLength: 1 maxLength: 128 required: - namespace StorageNamespaceKeyParams: allOf: - $ref: "#/components/schemas/StorageNamespaceParams" - type: object properties: key: type: string minLength: 1 maxLength: 256 required: - key StorageIfRevisionHeader: type: object properties: if-revision-match: type: string StorageDeleteQuery: type: object properties: ifRevision: type: - integer - "null" minimum: 0 parameters: {} paths: /api/auth/google/callback: get: summary: Handle Google OAuth callback description: Browser popup callback for the Gmail email-provider OAuth flow. Google redirects here with an authorization code and state. The handler decodes the state to find the tenant and email provider, exchanges the code for Google access and refresh tokens, stores them on the provider configuration, marks the provider connected, and may provision Gmail watch/Pub/Sub resources. This endpoint is public and protected by the OAuth state parameter; it always responds with text/html that posts the success or error payload to the opener window rather than returning JSON. tags: - Auth security: [] x-alga-products: - psa parameters: - schema: type: string description: OAuth 2.0 authorization code. Required unless the provider returned error. required: false description: OAuth 2.0 authorization code. Required unless the provider returned error. name: code in: query - schema: type: string description: Base64-encoded JSON state object generated when the OAuth flow was initiated. It carries tenant context, providerId, redirectUri, timestamp, and nonce values used to complete the callback. required: false description: Base64-encoded JSON state object generated when the OAuth flow was initiated. It carries tenant context, providerId, redirectUri, timestamp, and nonce values used to complete the callback. name: state in: query - schema: type: string description: OAuth error code returned by the provider, such as access_denied. required: false description: OAuth error code returned by the provider, such as access_denied. name: error in: query - schema: type: string description: Human-readable OAuth error description returned by the provider. required: false description: Human-readable OAuth error description returned by the provider. name: error_description in: query responses: "200": description: HTML popup callback page. The embedded postMessage payload reports success, provider=google, token expiry, and echoed code/state, or an OAuth/configuration/token-exchange error. content: text/html: schema: $ref: "#/components/schemas/OAuthCallbackHtmlResponse" /api/auth/microsoft/callback: get: summary: Handle Microsoft OAuth callback description: Browser popup callback for the Microsoft Graph email-provider OAuth flow. Microsoft redirects here with an authorization code and state. The handler decodes tenant/provider context from state, resolves the tenant Microsoft profile credentials, exchanges the code for Microsoft Graph tokens, stores them on the email provider, marks the provider connected, and best-effort registers a Graph webhook subscription. This endpoint is public and protected by the OAuth state parameter; it always responds with text/html that posts the success or error payload to the opener window rather than returning JSON. tags: - Auth security: [] x-alga-products: - psa parameters: - schema: type: string description: OAuth 2.0 authorization code. Required unless the provider returned error. required: false description: OAuth 2.0 authorization code. Required unless the provider returned error. name: code in: query - schema: type: string description: Base64-encoded JSON state object generated when the OAuth flow was initiated. It carries tenant context, providerId, redirectUri, timestamp, and nonce values used to complete the callback. required: false description: Base64-encoded JSON state object generated when the OAuth flow was initiated. It carries tenant context, providerId, redirectUri, timestamp, and nonce values used to complete the callback. name: state in: query - schema: type: string description: OAuth error code returned by the provider, such as access_denied. required: false description: OAuth error code returned by the provider, such as access_denied. name: error in: query - schema: type: string description: Human-readable OAuth error description returned by the provider. required: false description: Human-readable OAuth error description returned by the provider. name: error_description in: query responses: "200": description: HTML popup callback page. The embedded postMessage payload reports success, provider=microsoft, token expiry, and echoed code/state, or an OAuth/configuration/token-exchange error. content: text/html: schema: $ref: "#/components/schemas/OAuthCallbackHtmlResponse" /api/auth/{nextauth}: get: summary: Handle NextAuth GET action description: "Catch-all Auth.js/NextAuth GET endpoint. The nextauth path segment selects the action: csrf returns a CSRF token and sets the CSRF cookie, providers returns configured provider metadata, session returns the current session or {}, signin/signout/error/verify-request render or redirect to configured pages, and callback/{provider} handles OAuth provider redirects. This route is the authentication surface itself and does not require API-key authentication." tags: - Auth security: [] x-alga-products: - psa parameters: - schema: type: string description: NextAuth catch-all action path. Common values include csrf, providers, signin, signout, session, error, verify-request, webauthn-options, callback/credentials, callback/google, callback/azure-ad, and callback/keycloak. required: true description: NextAuth catch-all action path. Common values include csrf, providers, signin, signout, session, error, verify-request, webauthn-options, callback/credentials, callback/google, callback/azure-ad, and callback/keycloak. name: nextauth in: path - schema: type: string description: Optional URL to redirect to after sign-in or sign-out flows. required: false description: Optional URL to redirect to after sign-in or sign-out flows. name: callbackUrl in: query - schema: type: string description: Optional NextAuth/OAuth error code shown by sign-in or error pages. required: false description: Optional NextAuth/OAuth error code shown by sign-in or error pages. name: error in: query - schema: type: string description: OAuth authorization code for provider callback sub-routes. required: false description: OAuth authorization code for provider callback sub-routes. name: code in: query - schema: type: string description: OAuth state value for provider callback sub-routes. required: false description: OAuth state value for provider callback sub-routes. name: state in: query - schema: type: string description: Human-readable provider error description for OAuth callback sub-routes. required: false description: Human-readable provider error description for OAuth callback sub-routes. name: error_description in: query responses: "200": description: Successful JSON or HTML response for the selected NextAuth action. Examples include { csrfToken }, provider maps, session objects, {}, or built-in HTML pages. content: application/json: schema: $ref: "#/components/schemas/NextAuthGetResponse" "302": description: Redirect to the configured sign-in, sign-out, callback, or error destination. content: application/json: schema: $ref: "#/components/schemas/RedirectResponse" "404": description: No content when a built-in action is unavailable or disabled. post: summary: Handle NextAuth POST action description: "Catch-all Auth.js/NextAuth POST endpoint. The nextauth path segment selects the action: callback/credentials authenticates email and password credentials, callback/{provider} handles OAuth callback form posts, signout clears the current session, session returns or updates session data, and csrf returns a CSRF token. Mutating actions require the csrfToken body field matching the Auth.js CSRF cookie. Credential success sets the encrypted Auth.js session cookie and redirects; failures typically redirect to /auth/signin with an error code." tags: - Auth security: [] x-alga-products: - psa parameters: - schema: type: string description: NextAuth catch-all action path. Common values include csrf, providers, signin, signout, session, error, verify-request, webauthn-options, callback/credentials, callback/google, callback/azure-ad, and callback/keycloak. required: true description: NextAuth catch-all action path. Common values include csrf, providers, signin, signout, session, error, verify-request, webauthn-options, callback/credentials, callback/google, callback/azure-ad, and callback/keycloak. name: nextauth in: path requestBody: description: Form fields consumed by the selected NextAuth POST action. required: true content: application/x-www-form-urlencoded: schema: $ref: "#/components/schemas/NextAuthPostBody" description: Form fields consumed by the selected NextAuth POST action. responses: "200": description: JSON response for session or csrf POST actions. content: application/json: schema: anyOf: - $ref: "#/components/schemas/AuthSessionAuthenticatedResponse" - $ref: "#/components/schemas/EmptyObjectResponse" - $ref: "#/components/schemas/CsrfTokenResponse" - $ref: "#/components/schemas/EmptyObjectResponse" "302": description: Redirect after sign-in, OAuth callback, sign-out, or error handling. Session cookies may be set or cleared. content: application/json: schema: $ref: "#/components/schemas/RedirectResponse" /api/auth/session: get: summary: Get current Auth.js session description: Returns the current Auth.js/NextAuth session by reading the session cookie and running the full auth handler, including session revocation checks. Authenticated responses include the user profile, tenant context, session_id from the sessions table, and login method. If no valid session cookie is present, the route still returns HTTP 200 with an empty object. tags: - Auth security: - SessionCookieAuth: [] x-alga-products: - psa responses: "200": description: Authenticated session object, or {} when the request is unauthenticated. content: application/json: schema: $ref: "#/components/schemas/AuthSessionResponse" "500": description: Unexpected session retrieval failure. content: application/json: schema: $ref: "#/components/schemas/FlatErrorResponse" /api/auth/validate-api-key: post: summary: Validate API key description: Validates a plaintext API key supplied in the x-api-key header. The key is hashed before lookup. If the api_keys record exists, is active, has not expired, and has not exhausted its usage limit, the response returns the owning user UUID and tenant from that record. This route is the credential validation endpoint itself and does not require a separate session, tenant header, or RBAC permission. tags: - Auth security: [] x-alga-products: - psa parameters: - schema: type: string minLength: 1 description: Plaintext API key to validate. The service hashes this value before looking up the api_keys record. required: true description: Plaintext API key to validate. The service hashes this value before looking up the api_keys record. name: x-api-key in: header responses: "200": description: API key is valid and active. content: application/json: schema: $ref: "#/components/schemas/ValidateApiKeyResponse" "401": description: The x-api-key header is missing, or the key is invalid, inactive, expired, or usage-exhausted. content: application/json: schema: $ref: "#/components/schemas/FlatErrorResponse" "500": description: Unexpected error while validating the API key. content: application/json: schema: $ref: "#/components/schemas/FlatErrorResponse" /api/auth/validate-token: post: summary: Validate session token description: "Checks whether the request carries a valid Auth.js session token, either in the session cookie or in an Authorization: Bearer header. A valid token returns the user type and tenant copied from the session JWT. No request body is read." tags: - Auth security: - SessionCookieAuth: [] - BearerAuth: [] x-alga-products: - psa parameters: - schema: type: string description: Optional Bearer token fallback. The route also accepts the Auth.js session token cookie. required: false description: Optional Bearer token fallback. The route also accepts the Auth.js session token cookie. name: authorization in: header responses: "200": description: Session token is valid. content: application/json: schema: $ref: "#/components/schemas/ValidateTokenSuccessResponse" "401": description: No valid session token was found. content: application/json: schema: $ref: "#/components/schemas/ValidateTokenUnauthorizedResponse" "500": description: Unexpected token validation error. content: application/json: schema: $ref: "#/components/schemas/FlatErrorResponse" /api/v1/admin/telemetry-settings: get: summary: Get telemetry settings description: Returns tenant admin telemetry status derived from the ALGA_USAGE_STATS environment variable. The handler resolves the tenant with createTenantKnex, requires an authenticated current user, and checks the tenant-scoped users.role value for admin or owner. The route does not read or write tenant telemetry settings from the database. Because this session-authenticated route is not currently in apiKeySkipPaths, API middleware also requires an x-api-key header to be present before the handler can run. tags: - Admin - Telemetry security: - ApiKeyAuth: [] SessionCookieAuth: [] extensions: x-rbac-roles: - admin - owner x-tenant-scoped: true x-controlled-by: ALGA_USAGE_STATS x-middleware-api-key-required-currently: true x-alga-products: - psa responses: "200": description: Current telemetry setting returned successfully. content: application/json: schema: $ref: "#/components/schemas/TelemetrySettingsGetResponse" "401": description: No authenticated current user, no tenant context, or x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AdminTelemetryErrorResponse" "403": description: Authenticated user is not an admin or owner in the tenant. content: application/json: schema: $ref: "#/components/schemas/AdminTelemetryErrorResponse" "500": description: Unexpected failure while loading telemetry settings. content: application/json: schema: $ref: "#/components/schemas/AdminTelemetryErrorResponse" post: summary: Check telemetry settings update status description: No-op endpoint for telemetry settings. The handler authenticates the current user, verifies the tenant-scoped users.role is admin or owner, ignores the request body, performs no database write, and returns the current ALGA_USAGE_STATS-derived status with a message explaining that telemetry cannot be changed through the API. Because this session-authenticated route is not currently in apiKeySkipPaths, API middleware also requires an x-api-key header to be present before the handler can run. tags: - Admin - Telemetry security: - ApiKeyAuth: [] SessionCookieAuth: [] extensions: x-rbac-roles: - admin - owner x-tenant-scoped: true x-controlled-by: ALGA_USAGE_STATS x-request-body-ignored: true x-runtime-mutation: false x-middleware-api-key-required-currently: true x-alga-products: - psa responses: "200": description: Telemetry status returned; no setting was changed. content: application/json: schema: $ref: "#/components/schemas/TelemetrySettingsPostResponse" "401": description: No authenticated current user, no tenant context, or x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AdminTelemetryErrorResponse" "403": description: Authenticated user is not an admin or owner in the tenant. content: application/json: schema: $ref: "#/components/schemas/AdminTelemetryErrorResponse" "500": description: Unexpected failure while processing the no-op update request. content: application/json: schema: $ref: "#/components/schemas/AdminTelemetryErrorResponse" /api/v1/permission-checks: post: summary: Check user permissions description: Checks one or more resource/action pairs for the requested user (or current API-key user). tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: permission x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: checkUserPermissions x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessPermissionChecksBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for permission:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/permissions: get: summary: List permissions description: Lists permissions with optional resource/action filters. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: permission x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listPermissions x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a22 required: false name: order in: query - schema: type: string required: false name: resource in: query - schema: type: string required: false name: action in: query responses: "200": description: Paginated result set returned. content: application/json: schema: $ref: "#/components/schemas/AccessApiPaginatedV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for permission:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" post: summary: Create permission description: Creates one tenant-scoped permission row. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: permission x-rbac-action: create x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: createPermission x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessCreatePermissionBodyV1" responses: "201": description: Resource created successfully. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for permission:create. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/permissions/categories: get: summary: List permission categories description: Returns grouped permissions by resource. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: permission x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getPermissionCategories x-alga-products: - psa responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for permission:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/permissions/{id}: get: summary: Get permission description: Loads one permission by permission UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: permission x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getPermissionById x-alga-products: - psa parameters: - schema: type: string format: uuid description: Permission UUID from permissions.permission_id. required: true description: Permission UUID from permissions.permission_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for permission:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" put: summary: Update permission description: Updates permission metadata by permission UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: permission x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: updatePermission x-alga-products: - psa parameters: - schema: type: string format: uuid description: Permission UUID from permissions.permission_id. required: true description: Permission UUID from permissions.permission_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessUpdatePermissionBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for permission:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" delete: summary: Delete permission description: Deletes a permission by permission UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: permission x-rbac-action: delete x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: deletePermission x-alga-products: - psa parameters: - schema: type: string format: uuid description: Permission UUID from permissions.permission_id. required: true description: Permission UUID from permissions.permission_id. name: id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for permission:delete. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/permissions/{id}/roles: get: summary: List roles using permission description: Lists roles currently assigned the specified permission UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: permission x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getRolesByPermission x-alga-products: - psa parameters: - schema: type: string format: uuid description: Permission UUID from permissions.permission_id. required: true description: Permission UUID from permissions.permission_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for permission:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/rbac/analytics: get: summary: Get RBAC analytics description: Returns access-control metrics from PermissionRoleService.getAccessControlMetrics(). tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getAccessControlMetrics x-alga-products: - psa responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/rbac/audit: get: summary: Get RBAC audit log description: Lists RBAC audit-log entries from audit_logs (roles, permissions, role_permissions, user_roles), newest first. Supports page/limit pagination and user_id, operation, table_name, record_id, start_date, and end_date filters. Gated on role:read. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listRbacAudit x-alga-products: - psa responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/roles: get: summary: List roles description: Lists tenant roles with role-name and permission filters. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listRoles x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a23 required: false name: order in: query - schema: type: string required: false name: role_name in: query - schema: type: string enum: *a24 required: false name: has_permissions in: query - schema: type: string required: false name: permission_resource in: query - schema: type: string required: false name: permission_action in: query - schema: type: string enum: *a25 required: false name: is_template in: query responses: "200": description: Paginated result set returned. content: application/json: schema: $ref: "#/components/schemas/AccessApiPaginatedV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" post: summary: Create role description: Creates one tenant role, optionally with initial permission assignments. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: create x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: createRole x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessCreateRoleBodyV1" responses: "201": description: Resource created successfully. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:create. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/roles/bulk: post: summary: Bulk create roles description: Processes an array of role payloads and returns per-item success/error entries. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: create x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: bulkCreateRoles x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessBulkRolesBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:create. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/roles/templates: get: summary: List role templates description: Returns predefined role templates for the tenant context. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getRoleTemplates x-alga-products: - psa responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/roles/{id}: get: summary: Get role description: Loads role by role UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getRoleById x-alga-products: - psa parameters: - schema: type: string format: uuid description: Role UUID from roles.role_id. required: true description: Role UUID from roles.role_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" put: summary: Update role description: Updates role metadata and optional permission references. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: updateRole x-alga-products: - psa parameters: - schema: type: string format: uuid description: Role UUID from roles.role_id. required: true description: Role UUID from roles.role_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessUpdateRoleBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" delete: summary: Delete role description: Deletes role by role UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: delete x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: deleteRole x-alga-products: - psa parameters: - schema: type: string format: uuid description: Role UUID from roles.role_id. required: true description: Role UUID from roles.role_id. name: id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:delete. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/roles/{id}/clone: post: summary: Clone role description: Clones role configuration into a new role record. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: create x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: cloneRole x-alga-products: - psa parameters: - schema: type: string format: uuid description: Role UUID from roles.role_id. required: true description: Role UUID from roles.role_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessRoleCloneBodyV1" responses: "201": description: Resource created successfully. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:create. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/roles/{id}/permissions: get: summary: Get role permissions description: Returns permission set currently linked to the role UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getRolePermissions x-alga-products: - psa parameters: - schema: type: string format: uuid description: Role UUID from roles.role_id. required: true description: Role UUID from roles.role_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" put: summary: Replace role permissions description: Assigns provided permission UUIDs to the role and returns updated role payload. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: role x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: assignRolePermissions x-alga-products: - psa parameters: - schema: type: string format: uuid description: Role UUID from roles.role_id. required: true description: Role UUID from roles.role_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessRolePermissionsBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for role:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams: get: summary: List teams description: Lists teams through ApiBaseController list behavior. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listTeams x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a26 required: false name: order in: query - schema: type: string required: false name: team_name in: query - schema: type: string format: uuid required: false name: manager_id in: query - schema: type: string required: false name: fields in: query responses: "200": description: Paginated result set returned. content: application/json: schema: $ref: "#/components/schemas/AccessApiPaginatedV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" post: summary: Create team description: Creates one team with optional manager and embedded members. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: create x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: createTeam x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessCreateTeamBodyV1" responses: "201": description: Resource created successfully. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:create. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/bulk: put: summary: Bulk update teams description: Updates many teams using {team_ids, updates} payload. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: bulkUpdateTeams x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessTeamBulkUpdateBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" delete: summary: Bulk delete teams description: Deletes many teams using {team_ids} payload. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: delete x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: bulkDeleteTeams x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessTeamBulkDeleteBodyV1" responses: "204": description: Operation completed with no response body. "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:delete. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/hierarchy: get: summary: Get team hierarchy description: Current controller parses team id from URL tail; this route passes literal "hierarchy" as id and can fail validation/service lookup. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getTeamHierarchyRoot x-route-controller-mismatch: true x-alga-products: - psa - algadesk responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/search: get: summary: Search teams description: Runs advanced team search filters and returns paginated data. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: searchTeams x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: query in: query - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string format: uuid required: false name: manager_id in: query - schema: type: string enum: *a27 required: false name: has_manager in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a28 required: false name: order in: query responses: "200": description: Paginated result set returned. content: application/json: schema: $ref: "#/components/schemas/AccessApiPaginatedV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/stats: get: summary: Get team stats description: Returns aggregate team statistics for the tenant. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getTeamStats x-alga-products: - psa - algadesk responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}: get: summary: Get team description: Loads team by team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getTeamById x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" put: summary: Update team description: Updates team metadata by team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: updateTeam x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessUpdateTeamBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" delete: summary: Delete team description: Deletes a team by team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: delete x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: deleteTeam x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:delete. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}/analytics: get: summary: Get team analytics description: Returns team analytics for the target team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getTeamAnalytics x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path - schema: type: string required: false name: start_date in: query - schema: type: string required: false name: end_date in: query - schema: type: string description: Controller query parser provides strings; schema expects metric array. required: false description: Controller query parser provides strings; schema expects metric array. name: include_metrics in: query - schema: type: string enum: *a29 required: false name: granularity in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}/hierarchy: post: summary: Attach team to parent hierarchy description: Creates parent relationship for team UUID using parent_team_id payload. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: createTeamHierarchy x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessTeamHierarchyBodyV1" responses: "201": description: Resource created successfully. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" delete: summary: Detach team from hierarchy description: Removes hierarchy relationship for team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: removeTeamHierarchy x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}/manager: put: summary: Assign team manager description: Assigns manager_id to team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: assignTeamManager x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessAssignTeamManagerBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}/members: get: summary: List team members description: Returns members for team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listTeamMembers x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" post: summary: Add team member description: Adds one user to team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: addTeamMember x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessAddTeamMemberBodyV1" responses: "201": description: Resource created successfully. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}/members/bulk: post: summary: Bulk add team members description: Adds many users to team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: bulkAddTeamMembers x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessBulkAddTeamMembersBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}/members/{userId}: delete: summary: Remove team member description: Removes one user from team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: removeTeamMember x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: userId in: path responses: "204": description: Operation completed with no response body. "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}/permissions: get: summary: List team permissions description: Lists ACL records attached to team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listTeamPermissions x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" post: summary: Grant team permission description: Creates one permission grant for team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: grantTeamPermission x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessTeamPermissionGrantBodyV1" responses: "201": description: Resource created successfully. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}/permissions/{permissionId}: delete: summary: Revoke team permission description: Revokes permission grant. Controller extracts permission id from path and does not use team id during revocation call. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: revokeTeamPermission x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path - schema: type: string format: uuid description: Permission UUID from permissions.permission_id. required: true description: Permission UUID from permissions.permission_id. name: permissionId in: path responses: "204": description: Operation completed with no response body. "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/teams/{id}/projects: get: summary: List team projects description: Lists projects associated with team UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: team x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listTeamProjects x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for team:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/user-roles: get: summary: List users with roles description: Returns paginated users plus their role assignments. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listUsersWithRoles x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: search in: query - schema: type: string enum: *a30 required: false name: is_inactive in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a31 required: false name: order in: query responses: "200": description: Paginated result set returned. content: application/json: schema: $ref: "#/components/schemas/AccessApiPaginatedV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users: get: summary: List users description: Lists users using base list behavior and user query filters. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listUsers x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a32 required: false name: order in: query - schema: type: string required: false name: username in: query - schema: type: string required: false name: first_name in: query - schema: type: string required: false name: last_name in: query - schema: type: string required: false name: email in: query - schema: type: string enum: *a33 required: false name: user_type in: query - schema: type: string format: uuid required: false name: role_id in: query - schema: type: string format: uuid required: false name: team_id in: query - schema: type: string enum: *a34 required: false name: is_inactive in: query - schema: type: string enum: *a35 required: false name: include_permissions in: query - schema: type: string enum: *a36 required: false name: include_teams in: query - schema: type: string required: false name: fields in: query responses: "200": description: Paginated result set returned. content: application/json: schema: $ref: "#/components/schemas/AccessApiPaginatedV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" post: summary: Create user description: Creates one user using createUserSchema validation. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: create x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: createUser x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessCreateUserBodyV1" responses: "201": description: Resource created successfully. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:create. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/activity: get: summary: List global user activity description: Returns paginated activity feed across users. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: listUserActivity x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: from_date in: query - schema: type: string required: false name: to_date in: query - schema: type: string description: Controller converts single query value to one-element array for service filter. required: false description: Controller converts single query value to one-element array for service filter. name: activity_type in: query - schema: type: string required: false name: ip_address in: query responses: "200": description: Paginated result set returned. content: application/json: schema: $ref: "#/components/schemas/AccessApiPaginatedV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/bulk/create: post: summary: Bulk create users (route currently mapped to single create) description: Route currently delegates to ApiUserController.create(), so behavior is single-user create schema rather than bulk payload handling. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: create x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: bulkCreateUsersRouteMismatch x-route-controller-mismatch: true x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessCreateUserBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:create. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/bulk/deactivate: put: summary: Bulk deactivate users (route currently mapped to update-by-id) description: Route currently delegates to ApiUserController.update(); id extraction reads "bulk" from path and fails UUID validation. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: bulkDeactivateUsersRouteMismatch x-route-controller-mismatch: true x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessUpdateUserBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Current route fails UUID extraction because ApiBaseController.update() treats path segment "bulk" as {id}. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/search: get: summary: Search users description: Searches users with optional NM-store system context support and query validation. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: searchUsers x-alga-products: - psa - algadesk parameters: - schema: type: string required: true name: query in: query - schema: type: string description: Controller query parser sends strings; schema expects an array of field names. required: false description: Controller query parser sends strings; schema expects an array of field names. name: fields in: query - schema: type: string enum: *a37 required: false name: user_type in: query - schema: type: string format: uuid required: false name: role_id in: query - schema: type: string format: uuid required: false name: team_id in: query - schema: type: string enum: *a38 required: false name: include_inactive in: query - schema: type: string required: false name: limit in: query responses: "200": description: Paginated result set returned. content: application/json: schema: $ref: "#/components/schemas/AccessApiPaginatedV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/stats: get: summary: Get user stats description: Returns aggregate user statistics. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getUserStats x-alga-products: - psa - algadesk responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}: get: summary: Get user description: Loads user by user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getUserById x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" put: summary: Update user description: Updates user by user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: updateUser x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessUpdateUserBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" delete: summary: Delete user description: Deletes user by user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: delete x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: deleteUser x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:delete. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/2fa/disable: delete: summary: Disable user 2FA description: Disables two-factor authentication for target user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: disableUser2FA x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/2fa/enable: post: summary: Enable user 2FA description: Enables two-factor authentication using secret/token payload. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: enableUser2FA x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessEnable2FABodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/activity: get: summary: Get user activity description: Returns activity log for one user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getUserActivityById x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: from_date in: query - schema: type: string required: false name: to_date in: query - schema: type: string description: Controller converts single query value to one-element array for service filter. required: false description: Controller converts single query value to one-element array for service filter. name: activity_type in: query - schema: type: string required: false name: ip_address in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/avatar: post: summary: Upload user avatar description: Uploads avatar file from multipart form field avatar. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: uploadUserAvatar x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path requestBody: required: true content: application/json: schema: type: object properties: avatar: type: string description: "Multipart file field name expected by controller: avatar." required: - avatar responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" delete: summary: Delete user avatar description: Deletes avatar for target user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: deleteUserAvatar x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/password: put: summary: Change user password description: Changes password for self or another user with user:update permission. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: changeUserPassword x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessChangePasswordBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/permissions: get: summary: Get user effective permissions description: Returns explicit/effective permissions and roles for user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getUserPermissions x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/preferences: get: summary: Get user preferences description: Returns user preference map for user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getUserPreferences x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" put: summary: Update user preferences description: Updates user preference payload without route-level schema validation. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: updateUserPreferences x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessUserPreferenceBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/roles: get: summary: List user roles description: Lists roles assigned to user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getUserRoles x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" post: summary: Assign user roles description: Assigns provided role_ids to user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: assignUserRoles x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessUserRoleIdsBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" delete: summary: Remove user roles description: Removes provided role_ids from user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: removeUserRoles x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessUserRoleIdsBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" put: summary: Replace user roles description: Replaces all role links for user UUID using transaction over user_roles. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: update x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: replaceUserRoles x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessUserRoleIdsBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:update. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/teams: get: summary: List user teams description: Returns teams associated with user UUID. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: read x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: getUserTeams x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:read. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" post: summary: Add user to team (route currently mapped to user create) description: Route currently delegates to ApiUserController.create(); payload is interpreted as create-user body rather than team membership. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: create x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: userTeamsCreateRouteMismatch x-route-controller-mismatch: true x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AccessCreateUserBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/AccessApiSuccessV1" "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:create. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/users/{id}/teams/{teamId}: delete: summary: Remove user from team (route currently mapped to user delete) description: Route currently delegates to ApiUserController.delete(); extracted id is user UUID and teamId path segment is ignored. tags: - Access Control & Users v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: user x-rbac-action: delete x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or equivalent controller-specific auth path x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-controller-handler: userTeamsDeleteRouteMismatch x-route-controller-mismatch: true x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: User UUID from users.user_id. required: true description: User UUID from users.user_id. name: id in: path - schema: type: string format: uuid description: Team UUID from teams.team_id. required: true description: Team UUID from teams.team_id. name: teamId in: path responses: "204": description: Current handler delegates to ApiUserController.delete(); this removes the user record, not just team membership. "400": description: Validation failed (payload/query/path parsing). content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "403": description: RBAC denied for user:delete. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "404": description: User not found. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/AccessApiErrorV1" /api/v1/assets: get: summary: List assets description: Lists assets for the authenticated tenant with pagination, sorting, and asset filters. The controller validates query parameters with assetListQuerySchema, queries assets filtered by assets.tenant, joins clients for client_name, computes warranty_status, and adds HATEOAS links from asset_id. The route is authenticated and tenant-scoped via withApiKeyRouteAuth (req.context is populated before the handler runs). tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: read x-unapplied-validated-filters: - maintenance_due - is_active - search - created_from - created_to - updated_from - updated_to x-alga-products: - psa parameters: - schema: type: string description: Page number as a query string. Defaults to 1 after validation. required: false description: Page number as a query string. Defaults to 1 after validation. name: page in: query - schema: type: string description: Page size as a query string. Must parse to 1 through 100; defaults to 25. required: false description: Page size as a query string. Must parse to 1 through 100; defaults to 25. name: limit in: query - schema: type: string description: Sort column. Defaults to created_at. required: false description: Sort column. Defaults to created_at. name: sort in: query - schema: type: string enum: *a39 description: Sort direction. Defaults to desc. required: false description: Sort direction. Defaults to desc. name: order in: query - schema: type: string description: General search filter accepted by the shared filter schema. The current AssetService.list implementation does not apply this filter. required: false description: General search filter accepted by the shared filter schema. The current AssetService.list implementation does not apply this filter. name: search in: query - schema: type: string format: date-time description: Accepted by validation, but not currently applied by AssetService.list. required: false description: Accepted by validation, but not currently applied by AssetService.list. name: created_from in: query - schema: type: string format: date-time description: Accepted by validation, but not currently applied by AssetService.list. required: false description: Accepted by validation, but not currently applied by AssetService.list. name: created_to in: query - schema: type: string format: date-time description: Accepted by validation, but not currently applied by AssetService.list. required: false description: Accepted by validation, but not currently applied by AssetService.list. name: updated_from in: query - schema: type: string format: date-time description: Accepted by validation, but not currently applied by AssetService.list. required: false description: Accepted by validation, but not currently applied by AssetService.list. name: updated_to in: query - schema: type: string enum: *a40 description: Accepted by validation, but not currently applied by AssetService.list. required: false description: Accepted by validation, but not currently applied by AssetService.list. name: is_active in: query - schema: type: string description: Partial asset tag match using ILIKE. required: false description: Partial asset tag match using ILIKE. name: asset_tag in: query - schema: type: string description: Partial asset name match using ILIKE. required: false description: Partial asset name match using ILIKE. name: name in: query - schema: type: string format: uuid description: Client UUID from clients.client_id. required: false description: Client UUID from clients.client_id. name: client_id in: query - schema: type: string format: uuid description: Client location UUID from client_locations.location_id. required: false description: Client location UUID from client_locations.location_id. name: location_id in: query - schema: type: string enum: *a2 description: Asset type stored in assets.asset_type. required: false description: Asset type stored in assets.asset_type. name: asset_type in: query - schema: type: string description: Exact asset status match. required: false description: Exact asset status match. name: status in: query - schema: type: string description: Partial location match using ILIKE. required: false description: Partial location match using ILIKE. name: location in: query - schema: type: string description: Partial client name match; joins clients on client_id and tenant. required: false description: Partial client name match; joins clients on client_id and tenant. name: client_name in: query - schema: type: string enum: *a41 description: true requires warranty_end_date to be non-null; false requires it to be null. required: false description: true requires warranty_end_date to be non-null; false requires it to be null. name: has_warranty in: query - schema: type: string enum: *a42 description: true filters warranty_end_date before now; false filters future warranty dates or no warranty. required: false description: true filters warranty_end_date before now; false filters future warranty dates or no warranty. name: warranty_expired in: query - schema: type: string enum: *a43 description: Accepted by validation, but not currently applied by AssetService.list. required: false description: Accepted by validation, but not currently applied by AssetService.list. name: maintenance_due in: query - schema: type: string format: date-time description: Filter purchase_date greater than or equal to this timestamp. required: false description: Filter purchase_date greater than or equal to this timestamp. name: purchase_date_from in: query - schema: type: string format: date-time description: Filter purchase_date less than or equal to this timestamp. required: false description: Filter purchase_date less than or equal to this timestamp. name: purchase_date_to in: query - schema: type: string format: date-time description: Filter warranty_end_date greater than or equal to this timestamp. required: false description: Filter warranty_end_date greater than or equal to this timestamp. name: warranty_end_from in: query - schema: type: string format: date-time description: Filter warranty_end_date less than or equal to this timestamp. required: false description: Filter warranty_end_date less than or equal to this timestamp. name: warranty_end_to in: query responses: "200": description: Paginated asset list returned successfully. The pagination and links are nested under the top-level data envelope. content: application/json: schema: $ref: "#/components/schemas/AssetListResponse" "400": description: Query parameter validation failed. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to read assets when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" post: summary: Create asset description: Creates an asset for the authenticated tenant. The request body is validated with createAssetWithExtensionSchema; client_id, asset_type, asset_tag, name, and status are required. AssetService.create writes assets.tenant from the request context, inserts the asset, optionally upserts asset-type-specific extension_data, publishes an ASSET_CREATED event, and returns getWithDetails with HATEOAS links. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: create x-publishes-event: ASSET_CREATED x-alga-products: - psa requestBody: description: Asset fields plus optional asset-type-specific extension_data. required: true content: application/json: schema: $ref: "#/components/schemas/AssetCreateRequest" description: Asset fields plus optional asset-type-specific extension_data. responses: "201": description: Asset created successfully. content: application/json: schema: $ref: "#/components/schemas/AssetResourceResponse" "400": description: Request body validation failed. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to create assets when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/bulk-status: put: summary: Bulk update asset status description: Updates the status field for up to 50 assets in the authenticated tenant. The controller validates asset_ids and status with bulkAssetStatusSchema, then calls AssetService.update for each asset_id with { status }. Each update is tenant-scoped by assets.asset_id and assets.tenant and publishes an ASSET_UPDATED event. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-max-items: 50 x-publishes-event: ASSET_UPDATED x-alga-products: - psa requestBody: description: Asset IDs and the new status to apply to all assets. required: true content: application/json: schema: $ref: "#/components/schemas/AssetBulkStatusRequest" description: Asset IDs and the new status to apply to all assets. responses: "200": description: Status updated for all requested assets. content: application/json: schema: $ref: "#/components/schemas/AssetBulkUpdateResponse" "400": description: Request body validation failed. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to update assets when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/bulk-update: put: summary: Bulk update assets description: Updates up to 50 assets in the authenticated tenant. Each array item supplies an asset_id and partial update data validated with updateAssetSchema. The controller calls AssetService.update for every item, tenant-scoping each update by asset_id and context.tenant and publishing ASSET_UPDATED events. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-max-items: 50 x-publishes-event: ASSET_UPDATED x-alga-products: - psa requestBody: description: Array of asset_id plus partial update data objects. required: true content: application/json: schema: $ref: "#/components/schemas/AssetBulkUpdateRequest" description: Array of asset_id plus partial update data objects. responses: "200": description: Assets updated successfully. content: application/json: schema: $ref: "#/components/schemas/AssetBulkUpdateResponse" "400": description: Request body validation failed. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to update assets when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/documents/{associationId}: delete: summary: Remove asset document association description: Removes a document association row by document_associations.association_id for the authenticated tenant. The service deletes rows where association_id and tenant match and does not verify entity_type in this method. The controller intends to return an empty success response after deletion, but currently calls createApiResponse(null, 204) inside NextResponse.json, which can throw because JSON responses cannot use status 204 with a body. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-current-204-json-response-bug: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Document association UUID from document_associations.association_id. required: true description: Document association UUID from document_associations.association_id. name: associationId in: path responses: "204": description: Intended successful deletion response with no body. "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to update asset documents when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error, including the current 204 JSON response construction issue. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/export: get: summary: Export assets description: Exports all assets for the authenticated tenant (paginated internally, not capped to the default list page). Optional set filters asset_types, statuses, and client_ids narrow the result; fields restricts the exported columns. format=csv (default) returns text/csv with Content-Disposition attachment filename=assets.csv; format=json returns the success envelope with the rows in data. The route is authenticated and tenant-scoped via withApiKeyRouteAuth. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: false x-rbac-resource: asset x-rbac-action: read x-csv-content-disposition: attachment; filename=assets.csv x-alga-products: - psa parameters: - schema: type: string enum: *a44 description: Export format. csv (default) returns text/csv as an attachment; json returns the success envelope with the rows in data. required: false description: Export format. csv (default) returns text/csv as an attachment; json returns the success envelope with the rows in data. name: format in: query - schema: type: array items: type: string enum: *a2 description: Filter to these asset types. Repeat the param or pass a comma-separated list. required: false description: Filter to these asset types. Repeat the param or pass a comma-separated list. name: asset_types in: query - schema: type: array items: type: string description: Filter to these asset statuses. Repeat the param or pass a comma-separated list. required: false description: Filter to these asset statuses. Repeat the param or pass a comma-separated list. name: statuses in: query - schema: type: array items: type: string format: uuid description: Filter to these client UUIDs. Repeat the param or pass a comma-separated list. required: false description: Filter to these client UUIDs. Repeat the param or pass a comma-separated list. name: client_ids in: query - schema: type: array items: type: string description: Restrict exported columns to this set. Repeat the param or pass a comma-separated list. required: false description: Restrict exported columns to this set. Repeat the param or pass a comma-separated list. name: fields in: query responses: "200": description: Asset export returned successfully. For format=csv (or omitted) the handler returns text/csv with an attachment filename; for format=json it returns this JSON envelope. content: application/json: schema: $ref: "#/components/schemas/AssetExportJsonResponse" "400": description: Query parameter validation failed. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks asset:read. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/maintenance/{scheduleId}: delete: summary: Delete asset maintenance schedule description: Deletes a maintenance schedule by asset_maintenance_schedules.schedule_id for the authenticated tenant. The service scopes deletion by schedule_id and context.tenant and performs no existence check, so missing or cross-tenant IDs are silent no-ops. The controller intends to return 204 with no body, but currently constructs a JSON response with status 204, which can throw in NextResponse. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: delete x-idempotent: true x-no-existence-check: true x-current-204-json-response-bug: true x-no-event-published: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Maintenance schedule UUID from asset_maintenance_schedules.schedule_id. required: true description: Maintenance schedule UUID from asset_maintenance_schedules.schedule_id. name: scheduleId in: path responses: "204": description: Maintenance schedule deleted successfully, or it was already absent. "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to delete or update asset maintenance schedules when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error, including the current 204 JSON response construction issue. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" put: summary: Update asset maintenance schedule description: Updates a maintenance schedule by asset_maintenance_schedules.schedule_id for the authenticated tenant. All request fields are optional because updateMaintenanceScheduleSchema is a partial form of the create schema. If frequency, frequency_interval, or start_date are supplied, the service loads the existing schedule for the tenant and recalculates next_maintenance. Missing or cross-tenant schedule IDs result in a 200 response with an undefined nested data value rather than 404. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-recalculates-next-maintenance: true x-no-not-found-on-missing-id: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Maintenance schedule UUID from asset_maintenance_schedules.schedule_id. required: true description: Maintenance schedule UUID from asset_maintenance_schedules.schedule_id. name: scheduleId in: path requestBody: description: Partial maintenance schedule update data. required: true content: application/json: schema: $ref: "#/components/schemas/AssetMaintenanceScheduleUpdateRequest" description: Partial maintenance schedule update data. responses: "200": description: Maintenance schedule updated successfully. If the ID is not found, the nested data field may be absent. content: application/json: schema: $ref: "#/components/schemas/AssetMaintenanceScheduleResponse" "400": description: Request body validation failed. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to update asset maintenance schedules when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/relationships/{relationshipId}: delete: summary: Delete asset relationship description: Deletes an asset relationship by asset_relationships.relationship_id for the authenticated tenant. The service hard-deletes rows where relationship_id and context.tenant match, publishes no event, and performs no existence check; missing or cross-tenant IDs are silent no-ops. The controller intends to return 204 with no body, but currently constructs a JSON response with status 204, which can throw in NextResponse. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-idempotent: true x-no-existence-check: true x-current-204-json-response-bug: true x-no-event-published: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset relationship UUID from asset_relationships.relationship_id. required: true description: Asset relationship UUID from asset_relationships.relationship_id. name: relationshipId in: path responses: "204": description: Relationship deleted successfully, or it was already absent. "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to update asset relationships when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error, including the current 204 JSON response construction issue. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/search: get: summary: Search assets description: Searches tenant assets with a required query term and optional field, asset type, status, client, extension-data, and limit parameters. The service searches assets scoped to context.tenant, joins clients for client_name, and optionally loads asset-type-specific extension data per result. The response is not paginated and includes HATEOAS links for each asset; the top-level search link currently points at /api/v2/assets/search. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: read x-not-paginated: true x-response-links-path-version: v2 x-alga-products: - psa parameters: - schema: type: string minLength: 1 description: Required search term used in ILIKE clauses. required: true description: Required search term used in ILIKE clauses. name: query in: query - schema: type: array items: type: string enum: *a45 description: Search fields. If omitted, the service searches asset_tag, name, serial_number, and location. required: false description: Search fields. If omitted, the service searches asset_tag, name, serial_number, and location. name: fields in: query - schema: type: array items: type: string enum: *a2 description: Optional asset type filters. required: false description: Optional asset type filters. name: asset_types in: query - schema: type: array items: type: string description: Optional status filters. required: false description: Optional status filters. name: statuses in: query - schema: type: array items: type: string format: uuid description: Optional client UUID filters. required: false description: Optional client UUID filters. name: client_ids in: query - schema: type: string enum: *a46 description: When true, the service fetches asset-type-specific extension data for every result. required: false description: When true, the service fetches asset-type-specific extension data for every result. name: include_extension_data in: query - schema: type: string description: Maximum result count as a query string. Must parse to 1 through 100; defaults to 25. required: false description: Maximum result count as a query string. Must parse to 1 through 100; defaults to 25. name: limit in: query responses: "200": description: Matching assets returned successfully. content: application/json: schema: $ref: "#/components/schemas/AssetSearchResponse" "400": description: Query parameter validation failed, including missing required query. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to read assets when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/stats: get: summary: Get asset statistics description: Returns tenant-scoped aggregate asset statistics including total counts, counts by type/status/client, warranty counts, and maintenance due/overdue counts. The service runs multiple aggregate queries filtered by context.tenant; assets_by_client is limited to the top 10 client names. The response links currently point at /api/v2/assets paths. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: read x-assets-by-client-limit: 10 x-response-links-path-version: v2 x-alga-products: - psa responses: "200": description: Asset statistics returned successfully. content: application/json: schema: $ref: "#/components/schemas/AssetStatsResponse" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to read assets when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}: get: summary: Get asset details description: Returns detailed asset information for the authenticated tenant, including joined client_name, computed warranty_status, client details, type-specific extension_data, relationships, document associations, maintenance schedules, and HATEOAS links. The service first loads assets by asset_id and context.tenant, then loads related data in parallel. If the asset is not found, the controller returns a 404 error envelope. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: read x-includes-related-resources: - client - extension_data - relationships - documents - maintenance_schedules x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Asset details returned successfully. content: application/json: schema: $ref: "#/components/schemas/AssetResourceResponse" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to read assets when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: No asset exists for the supplied asset_id in the authenticated tenant. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" put: summary: Update asset description: Partially updates base asset fields for the authenticated tenant. The request body is validated with updateAssetSchema, where all fields are optional. AssetService.update scopes the update by asset_id and context.tenant, writes updated_at, publishes ASSET_UPDATED, and returns the refreshed base asset with joined client_name and warranty_status. This REST path does not update extension data, create asset history records, or wrap the update in a transaction. Missing assets currently lead to a 500 when the controller tries to add links to a null result rather than a clean 404. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-publishes-event: ASSET_UPDATED x-extension-data-handled: false x-history-recorded: false x-transactional: false x-no-clean-not-found-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path requestBody: description: Partial base asset update data. Extension data is not accepted by this REST endpoint. required: true content: application/json: schema: $ref: "#/components/schemas/AssetUpdateData" description: Partial base asset update data. Extension data is not accepted by this REST endpoint. responses: "200": description: Asset updated successfully. content: application/json: schema: $ref: "#/components/schemas/AssetResourceResponse" "400": description: Request body validation failed, or the database rejected an invalid reference. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to update assets when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Intended not-found response for missing assets; the current controller path may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "409": description: Database unique constraint conflict, such as a duplicate asset tag if enforced by schema. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error, including null asset result handling. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" delete: summary: Delete asset description: Hard-deletes an asset for the authenticated tenant. AssetService.delete first loads the asset by asset_id and context.tenant, deletes asset-type-specific extension data, deletes tenant_external_entity_mappings for the asset, deletes the assets row, and publishes ASSET_DELETED. The method overrides the BaseService softDelete configuration and does not explicitly clean every related table handled by the server-action delete path. Missing assets throw a generic Error and currently surface as 500 via handleApiError rather than 404. The controller also constructs a JSON response with status 204, which can throw in NextResponse. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: delete x-hard-delete: true x-publishes-event: ASSET_DELETED x-current-204-json-response-bug: true x-no-clean-not-found-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "204": description: Asset deleted successfully. Intended response has no body. "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to delete assets when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Intended not-found response for missing assets; the current service throws a generic Error that may surface as 500. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error, including generic Asset not found errors or the current 204 JSON response construction issue. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/documents: get: summary: List asset document associations description: Returns document_associations rows for an asset in the authenticated tenant where entity_type is asset and entity_id is the path asset ID. The service joins documents to add original_filename, file_size, mime_type, and uploaded_at. It does not check whether the asset exists first, so nonexistent or cross-tenant asset IDs return 200 with an empty array. Response links currently point at /api/v2/assets paths. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: read x-no-asset-existence-check: true x-response-links-path-version: v2 x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Document associations returned successfully. Empty when no associations exist or the asset is not found. content: application/json: schema: $ref: "#/components/schemas/AssetDocumentListResponse" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to read asset documents when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" post: summary: Associate document with asset description: Creates a document_associations row that links the path asset ID to the supplied document_id. The body is validated with createAssetDocumentSchema; document_id is required and notes is optional. The service inserts entity_type=asset, entity_id from the path, document_id, notes, tenant from context, and created_at, then returns the inserted row. It does not verify that the asset or document belongs to the same tenant before insert, does not set created_by, and publishes no event. Foreign-key or unique constraint errors surface through handleApiError. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-no-asset-existence-check: true x-no-tenant-cross-check-for-document: true x-created-by-set: false x-no-event-published: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path requestBody: description: Document UUID and optional association notes. required: true content: application/json: schema: $ref: "#/components/schemas/AssetDocumentAssociationRequest" description: Document UUID and optional association notes. responses: "201": description: Document association created successfully. content: application/json: schema: $ref: "#/components/schemas/AssetDocumentAssociationResponse" "400": description: Request body validation failed or a database foreign-key reference is invalid. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to update asset documents when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "409": description: Duplicate association rejected by a database unique constraint. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/history: get: summary: List asset maintenance history description: Returns all maintenance history rows for the path asset ID in the authenticated tenant, ordered by performed_at descending. The service joins users to add performed_by_user_name and filters asset_maintenance_history by asset_id and context.tenant. It performs no asset existence check, so nonexistent or cross-tenant asset IDs return 200 with an empty array. Response links currently point at /api/v2/assets paths. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: read x-no-asset-existence-check: true x-not-paginated: true x-response-links-path-version: v2 x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Maintenance history rows returned successfully. content: application/json: schema: $ref: "#/components/schemas/AssetMaintenanceHistoryResponse" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to read asset history when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/maintenance: get: summary: List asset maintenance schedules description: Returns maintenance schedule rows for the path asset ID in the authenticated tenant. The service filters asset_maintenance_schedules by asset_id and context.tenant and joins users to add assigned_user_name. It performs no asset existence check, so nonexistent or cross-tenant asset IDs return 200 with an empty array. Response links currently point at /api/v2/assets paths. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: read x-no-asset-existence-check: true x-response-links-path-version: v2 x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Maintenance schedules returned successfully. content: application/json: schema: $ref: "#/components/schemas/AssetMaintenanceScheduleListResponse" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to read asset maintenance schedules when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" post: summary: Create asset maintenance schedule description: Creates a maintenance schedule for the path asset ID in the authenticated tenant. The request body is validated with createMaintenanceScheduleSchema; schedule_type and frequency are required, while start_date is optional in the current shared date schema and the service falls back to now when absent. The service inserts asset_id from the path, tenant from context, timestamps, and a calculated next_maintenance value. It does not verify asset existence, does not set created_by, and publishes no event. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-no-asset-existence-check: true x-calculates-next-maintenance: true x-created-by-set: false x-no-event-published: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path requestBody: description: Maintenance schedule creation data. required: true content: application/json: schema: $ref: "#/components/schemas/AssetMaintenanceScheduleCreateRequest" description: Maintenance schedule creation data. responses: "201": description: Maintenance schedule created successfully. content: application/json: schema: $ref: "#/components/schemas/AssetMaintenanceScheduleResponse" "400": description: Request body validation failed or the database rejected an invalid reference. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to create or update asset maintenance schedules when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "409": description: Database unique constraint conflict if one is enforced. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/maintenance/record: post: summary: Record asset maintenance description: Inserts an asset_maintenance_history row for the path asset ID in the authenticated tenant. The request body requires maintenance_type, performed_by, and performed_at; schedule_id, duration, cost, notes, parts, and structured maintenance_data are optional. If schedule_id is supplied and a matching tenant schedule exists, the service updates that schedule last_maintenance and next_maintenance. It does not verify asset existence or performed_by before insert, does not set created_by, and publishes no event. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-no-asset-existence-check: true x-performed-by-not-validated: true x-schedule-update-on-linked: true x-created-by-set: false x-no-event-published: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path requestBody: description: Maintenance history record data. required: true content: application/json: schema: $ref: "#/components/schemas/AssetRecordMaintenanceRequest" description: Maintenance history record data. responses: "201": description: Maintenance record created successfully. content: application/json: schema: $ref: "#/components/schemas/AssetRecordMaintenanceResponse" "400": description: Request body validation failed or the database rejected an invalid reference. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to update asset maintenance records when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "409": description: Database unique constraint conflict if one is enforced. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/relationships: get: summary: List asset relationships description: Returns asset_relationships rows for the path asset ID in the authenticated tenant, joined with the related assets table for display fields. The service filters by asset_relationships.asset_id and context.tenant and joins related assets on matching tenant. It performs no parent asset existence check and does not filter soft-deleted related assets. Response links currently point at /api/v2/assets paths. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: read x-no-asset-existence-check: true x-related-asset-soft-delete-filter: false x-response-links-path-version: v2 x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Asset relationships returned successfully. content: application/json: schema: $ref: "#/components/schemas/AssetRelationshipListResponse" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to read asset relationships when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" post: summary: Create asset relationship description: Creates a relationship row between the path asset ID and related_asset_id for the authenticated tenant. The request body requires related_asset_id and non-empty relationship_type. The service rejects self relationships and duplicate source/related pairs, but currently throws generic Errors for those cases, which surface as 500 rather than 400 or 409. The inserted row is returned without joined related asset details. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: true x-rbac-resource: asset x-rbac-action: update x-self-relationship-check: true x-duplicate-check: true x-self-relationship-error-is-500: true x-duplicate-error-is-500: true x-no-event-published: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path requestBody: description: Relationship creation data. required: true content: application/json: schema: $ref: "#/components/schemas/AssetRelationshipCreateRequest" description: Relationship creation data. responses: "201": description: Asset relationship created successfully. content: application/json: schema: $ref: "#/components/schemas/AssetRelationshipResponse" "400": description: Request body validation failed or a database reference is invalid. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key is missing at middleware. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Authenticated request context lacks permission to update asset relationships when auth wiring is present. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "409": description: Intended duplicate conflict response; current duplicate check throws a generic Error that may surface as 500. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error, including self-relationship or duplicate-relationship errors in the current implementation. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/tickets: get: summary: List tickets linked to an asset description: Returns tickets associated with the path asset ID in the authenticated tenant, read from asset_associations where entity_type is ticket, joined to tickets and statuses. Results include the association relationship_type and linked_at and are ordered by ticket updated_at descending. This mirrors the asset detail UI and the assets.find_associated_tickets workflow action. The route is authenticated and tenant-scoped via withApiKeyRouteAuth (req.context is populated and RLS is active) and enforces BOTH asset:read and ticket:read because the response joins ticket data. It performs no asset existence check, so a valid caller hitting a nonexistent or cross-tenant asset ID gets 200 with an empty array (tenant scoping prevents cross-tenant leakage; this is not an authorization bypass). operationId: listAssetTickets tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: false x-rbac-resource: asset x-rbac-action: read x-rbac-additional-required: ticket:read x-no-asset-existence-check: true x-not-paginated: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Linked tickets returned successfully. Empty when no associations exist or the asset is not found. content: application/json: schema: $ref: "#/components/schemas/AssetTicketListResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks asset:read or ticket:read. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" post: summary: Link a ticket to an asset description: Creates an asset_associations row (entity_type=ticket) linking the path asset to the ticket in the request body. This is the same table the asset detail UI, GET /api/v1/assets/{id}/tickets, and GET /api/v1/tickets/{id}/assets read, so the link is immediately visible from both sides. relationship_type defaults to affected. The route is authenticated and tenant-scoped via withApiKeyRouteAuth and enforces asset:update (the asset associations are being mutated) plus ticket:read (the ticket is only referenced). Both the asset and the ticket must exist in the tenant (404 otherwise), and a duplicate link returns 409. operationId: linkTicketToAsset tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: false x-rbac-resource: asset x-rbac-action: update x-rbac-additional-required: ticket:read x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path requestBody: description: The ticket to link plus optional relationship_type and notes. required: true content: application/json: schema: $ref: "#/components/schemas/AssetTicketLinkRequest" description: The ticket to link plus optional relationship_type and notes. responses: "201": description: Ticket linked. Returns the inserted asset_associations row. content: application/json: schema: $ref: "#/components/schemas/AssetTicketLinkResponse" "400": description: Request body validation failed. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks asset:update or ticket:read. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset or ticket not found in the tenant. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "409": description: Ticket is already linked to this asset. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/tickets/{id}/assets: get: summary: List assets linked to a ticket description: Returns assets associated with the path ticket ID in the authenticated tenant, read from asset_associations where entity_type is ticket, joined to assets and clients. Each row includes the asset fields plus the association relationship_type, association_notes, and linked_at, ordered by link time descending. The route is authenticated and tenant-scoped via ApiBaseController.authenticate + runWithTenant (RLS active); it enforces ticket:read, a per-ticket authorization-kernel check (assertTicketReadAllowed), AND asset:read because the response exposes asset records. The response uses the apiMiddleware envelope ({ data } with no top-level success field). It performs no asset existence check beyond the ticket authorization, so an authorized caller on a ticket with no linked assets gets 200 with an empty array. operationId: listTicketAssets tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-rbac-resource: ticket x-rbac-action: read x-rbac-additional-required: asset:read x-per-record-authorization: assertTicketReadAllowed x-not-paginated: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Linked assets returned successfully. Empty when the ticket has no linked assets. content: application/json: schema: $ref: "#/components/schemas/TicketAssetListResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks ticket:read (or per-ticket authorization) or asset:read. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Ticket not found / not authorized for the caller. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" post: summary: Link an asset to a ticket description: Creates an asset_associations row (entity_type=ticket) linking the asset in the request body to the path ticket. Same table GET /api/v1/tickets/{id}/assets and the asset detail UI read, so the link is visible from both sides. relationship_type defaults to affected. The route is authenticated and tenant-scoped via ApiBaseController.authenticate + runWithTenant; it enforces ticket:update plus a per-ticket authorization-kernel check (assertTicketReadAllowed) AND asset:read (the asset is referenced). The response uses the apiMiddleware envelope ({ data } with no top-level success field). Both the ticket and asset must exist (404 otherwise); a duplicate link returns 409. operationId: linkAssetToTicket tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-rbac-resource: ticket x-rbac-action: update x-rbac-additional-required: asset:read x-per-record-authorization: assertTicketReadAllowed x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path requestBody: description: The asset to link plus optional relationship_type and notes. required: true content: application/json: schema: $ref: "#/components/schemas/TicketAssetLinkRequest" description: The asset to link plus optional relationship_type and notes. responses: "201": description: Asset linked. Returns the inserted asset_associations row. content: application/json: schema: $ref: "#/components/schemas/TicketAssetLinkResponse" "400": description: Request body validation failed. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks ticket:update (or per-ticket authorization) or asset:read. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Ticket or asset not found in the tenant. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "409": description: Asset is already linked to this ticket. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/tickets/{ticketId}: delete: summary: Unlink a ticket from an asset description: Deletes the asset_associations row (entity_type=ticket) linking the path asset and ticket for the authenticated tenant. The route is authenticated and tenant-scoped via withApiKeyRouteAuth and enforces asset:update plus ticket:read. Returns 404 when no such link exists. operationId: unlinkTicketFromAsset tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-current-auth-wiring-missing: false x-rbac-resource: asset x-rbac-action: update x-rbac-additional-required: ticket:read x-idempotent: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path - schema: type: string format: uuid description: Ticket UUID from tickets.ticket_id. required: true description: Ticket UUID from tickets.ticket_id. name: ticketId in: path responses: "204": description: Link removed. "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks asset:update or ticket:read. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset-ticket association not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/tickets/{id}/assets/{assetId}: delete: summary: Unlink an asset from a ticket description: Deletes the asset_associations row (entity_type=ticket) linking the path asset and ticket for the authenticated tenant. Authenticated and tenant-scoped via ApiBaseController.authenticate + runWithTenant; enforces ticket:update plus the per-ticket authorization check and asset:read. Returns 404 when no such link exists. operationId: unlinkAssetFromTicket tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-rbac-resource: ticket x-rbac-action: update x-rbac-additional-required: asset:read x-per-record-authorization: assertTicketReadAllowed x-idempotent: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: Ticket UUID from tickets.ticket_id. required: true description: Ticket UUID from tickets.ticket_id. name: id in: path - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: assetId in: path responses: "204": description: Link removed. "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks ticket:update (or per-ticket authorization) or asset:read. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset-ticket association not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/notes: get: summary: Get asset notes description: Returns the BlockNote content of the asset notes document, or an empty result when no notes exist. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Asset notes content. content: application/json: schema: $ref: "#/components/schemas/AssetNotesResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" put: summary: Update asset notes description: Creates or updates the BlockNote notes document linked to the asset. Returns the document id. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: update x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AssetNotesUpdateBody" responses: "200": description: Notes saved. content: application/json: schema: type: object properties: document_id: type: string format: uuid required: - document_id "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" delete: summary: Delete asset notes description: Unlinks the notes document from the asset. Pass delete_document=true to also hard-delete the document and its block content. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: update x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path - schema: type: string enum: - "true" - "false" required: false name: delete_document in: query responses: "204": description: Notes unlinked/deleted. "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/rmm: get: summary: Get cached RMM data description: Returns the cached RMM device data synced from the RMM provider. Enterprise Edition feature — on Community Edition this returns null. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: read x-edition-feature: ee-rmm x-ce-behavior: returns null or success:false EE-required message x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Cached RMM data (null on CE). content: application/json: schema: $ref: "#/components/schemas/AssetRmmResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/rmm/reboot: post: summary: Reboot device via RMM description: Sends a reboot command to the RMM-managed device. Enterprise Edition feature — on Community Edition this returns { success:false } with an EE-required message. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: update x-edition-feature: ee-rmm x-ce-behavior: returns null or success:false EE-required message x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Reboot result. content: application/json: schema: $ref: "#/components/schemas/AssetRmmActionResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/rmm/refresh: post: summary: Refresh RMM data for device description: Triggers a single-device RMM sync and returns the refreshed data. Enterprise Edition feature — on Community Edition this returns null. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: update x-edition-feature: ee-rmm x-ce-behavior: returns null or success:false EE-required message x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Refreshed RMM data (null on CE). content: application/json: schema: $ref: "#/components/schemas/AssetRmmResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/rmm/remote-control: get: summary: Get remote-control session URL description: Generates a remote-control URL for the device using the protocol given by the type query param. Enterprise Edition feature — on Community Edition this returns null. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: read x-edition-feature: ee-rmm x-ce-behavior: returns null or success:false EE-required message x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path - schema: type: string enum: *a47 description: Remote-control protocol (default splashtop). required: false description: Remote-control protocol (default splashtop). name: type in: query responses: "200": description: Remote-control URL (null on CE). content: application/json: schema: $ref: "#/components/schemas/AssetRemoteControlResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/rmm/script: post: summary: Run a script via RMM description: Runs the script identified by scriptId on the RMM-managed device. Enterprise Edition feature — on Community Edition this returns { success:false } with an EE-required message. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: update x-edition-feature: ee-rmm x-ce-behavior: returns null or success:false EE-required message x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AssetRmmScriptBody" responses: "200": description: Script run result. content: application/json: schema: $ref: "#/components/schemas/AssetRmmActionResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/software: get: summary: List asset software inventory description: Returns the paginated software inventory for the asset (from the normalized software tables), with filters for category, software_type, search, and include_uninstalled, plus a summary of totals. tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path - schema: type: integer minimum: 1 required: false name: page in: query - schema: type: integer minimum: 1 maximum: 200 required: false name: limit in: query - schema: type: string required: false name: category in: query - schema: type: string required: false name: software_type in: query - schema: type: string required: false name: search in: query - schema: type: string enum: *a48 required: false name: include_uninstalled in: query responses: "200": description: Asset software inventory. content: application/json: schema: $ref: "#/components/schemas/AssetSoftwareResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/assets/{id}/summary: get: summary: Get asset summary metrics description: "Returns computed asset metrics: health status/reason, security status/issues, warranty status and days remaining, and open ticket count." tags: - Assets security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: asset x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid description: Asset UUID from assets.asset_id. required: true description: Asset UUID from assets.asset_id. name: id in: path responses: "200": description: Asset summary metrics. content: application/json: schema: $ref: "#/components/schemas/AssetSummaryResponse" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/AssetMiddlewareUnauthorizedResponse" "403": description: Caller lacks the required asset permission. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "404": description: Asset not found. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/AssetApiErrorEnvelope" /api/v1/automation/executions: get: summary: List automation executions description: Returns a paginated list of automation executions for the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id; the controller validates the API key, resolves the user and tenant, runs under tenant context, and requires automation:read permission. The service forces tenant into the execution query conditions. Current service code appears to wrap the execution array in another array before createPaginatedResponse, which may produce nested data in practice. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: read x-service-data-wrapping-bug: true x-alga-products: - psa parameters: - schema: type: string description: Page number as a query string. Defaults to 1. required: false description: Page number as a query string. Defaults to 1. name: page in: query - schema: type: string description: Page size as a query string. Must parse to 1 through 100; defaults to 25. required: false description: Page size as a query string. Must parse to 1 through 100; defaults to 25. name: limit in: query - schema: type: string description: Accepted by shared list query validation; the service currently orders executions by started_at desc. required: false description: Accepted by shared list query validation; the service currently orders executions by started_at desc. name: sort in: query - schema: type: string enum: *a49 description: Accepted by shared list query validation. required: false description: Accepted by shared list query validation. name: order in: query - schema: type: string description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: search in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: created_from in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: created_to in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: updated_from in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: updated_to in: query - schema: type: string enum: *a50 description: Accepted by shared filter validation and transformed to boolean. required: false description: Accepted by shared filter validation and transformed to boolean. name: is_active in: query - schema: type: string format: uuid description: Filter executions by parent automation rule UUID. required: false description: Filter executions by parent automation rule UUID. name: automation_rule_id in: query - schema: type: string enum: *a4 description: Filter by execution status. required: false description: Filter by execution status. name: status in: query - schema: type: string format: date-time description: Filter executions started at or after this timestamp. required: false description: Filter executions started at or after this timestamp. name: started_from in: query - schema: type: string format: date-time description: Filter executions started at or before this timestamp. required: false description: Filter executions started at or before this timestamp. name: started_to in: query - schema: type: number minimum: 0 description: Minimum execution duration in milliseconds. required: false description: Minimum execution duration in milliseconds. name: duration_min_ms in: query - schema: type: number minimum: 0 description: Maximum execution duration in milliseconds. required: false description: Maximum execution duration in milliseconds. name: duration_max_ms in: query - schema: type: string enum: *a51 description: Filter by whether the execution has errors; transformed to boolean by validation. required: false description: Filter by whether the execution has errors; transformed to boolean by validation. name: has_errors in: query - schema: type: string enum: *a3 description: Filter by automation trigger type. required: false description: Filter by automation trigger type. name: trigger_type in: query responses: "200": description: Automation executions returned successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationExecutionListResponse" "400": description: Query parameter validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:read permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected automation execution listing failure. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/executions/{id}: get: summary: Get automation execution description: Returns one automation execution by execution_id for the authenticated tenant, with HATEOAS links to the parent rule and retry endpoint when the status is failed. Authentication uses x-api-key with optional x-tenant-id; the controller validates the API key, resolves tenant context, validates the UUID path parameter, and requires automation:read permission. The service scopes lookup by execution_id and tenant. Missing executions currently throw a generic Error and may surface as 500 rather than 404. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: read x-no-clean-not-found-currently: true x-generic-resource-links-may-include-unimplemented-methods: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Automation execution UUID from automation_executions.execution_id. required: true description: Automation execution UUID from automation_executions.execution_id. name: id in: path responses: "200": description: Automation execution returned successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationExecutionResponse" "400": description: Invalid execution UUID format. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:read permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "404": description: Intended not-found response for a missing execution; current service may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected failure, including current generic not-found errors. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/executions/{id}/retry: post: summary: Retry automation execution description: Retries a failed automation execution. The controller authenticates with x-api-key, requires automation:execute permission, validates the execution UUID, resets a failed execution to pending, clears completion/error counters, queues the execution, publishes automation.execution.retried, and returns the updated execution with links. The service only allows status=failed; missing executions and non-failed executions currently throw generic Errors and may surface as 500 rather than 404 or 400. The queueExecution helper is currently a stub. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: execute x-requires-current-status: failed x-queues-execution-stubbed: true x-publishes-event: automation.execution.retried x-no-clean-not-found-currently: true x-not-failed-error-is-500-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Automation execution UUID from automation_executions.execution_id. required: true description: Automation execution UUID from automation_executions.execution_id. name: id in: path responses: "200": description: Execution reset and queued for retry. content: application/json: schema: $ref: "#/components/schemas/AutomationExecutionResponse" "400": description: Invalid execution UUID format, or intended response when execution is not failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:execute permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "404": description: Intended not-found response for a missing execution; current service may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected failure, including current generic not-found or not-failed errors. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/rules: get: summary: List automation rules description: Returns a paginated list of automation rules scoped to the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id, then RBAC requires automation:read. The controller validates query params with automationRulesListSchema, parses page/limit from the URL, and the service enforces tenant filtering on automation_rules. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: read x-id-provenance: rule_id: automation_rules.rule_id tenant: automation_rules.tenant x-alga-products: - psa parameters: - schema: type: string description: Page number as a query string. Defaults to 1. required: false description: Page number as a query string. Defaults to 1. name: page in: query - schema: type: string description: Page size as a query string. Must parse to 1 through 100; defaults to 25. required: false description: Page size as a query string. Must parse to 1 through 100; defaults to 25. name: limit in: query - schema: type: string description: Accepted by shared list query validation; service currently orders rules by created_at desc. required: false description: Accepted by shared list query validation; service currently orders rules by created_at desc. name: sort in: query - schema: type: string enum: *a52 description: Accepted by shared list query validation. required: false description: Accepted by shared list query validation. name: order in: query - schema: type: string description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: search in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: created_from in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: created_to in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: updated_from in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: updated_to in: query - schema: type: string enum: *a53 description: Accepted by shared filter validation and transformed to boolean. required: false description: Accepted by shared filter validation and transformed to boolean. name: is_active in: query - schema: type: string description: Optional rule name filter. required: false description: Optional rule name filter. name: name in: query - schema: type: string enum: *a6 description: Filter by automation rule status. required: false description: Filter by automation rule status. name: status in: query - schema: type: string enum: *a3 description: Filter by trigger type. required: false description: Filter by trigger type. name: trigger_type in: query - schema: type: string enum: *a7 description: Filter by priority level. required: false description: Filter by priority level. name: priority in: query - schema: type: string description: Filter template category. required: false description: Filter template category. name: template_category in: query - schema: type: string format: uuid description: Filter by creator user UUID from automation_rules.created_by. required: false description: Filter by creator user UUID from automation_rules.created_by. name: created_by in: query - schema: type: string format: date-time description: Filter for rules last executed at or after timestamp. required: false description: Filter for rules last executed at or after timestamp. name: last_executed_from in: query - schema: type: string format: date-time description: Filter for rules last executed at or before timestamp. required: false description: Filter for rules last executed at or before timestamp. name: last_executed_to in: query - schema: type: integer minimum: 0 description: Minimum execution count filter. required: false description: Minimum execution count filter. name: execution_count_min in: query - schema: type: integer minimum: 0 description: Maximum execution count filter. required: false description: Maximum execution count filter. name: execution_count_max in: query responses: "200": description: Automation rules returned successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationRuleListResponse" "400": description: Query parameter validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:read permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected automation rules listing failure. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" post: summary: Create automation rule description: Creates a tenant-scoped automation rule in automation_rules. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:create. The controller validates request body via createAutomationRuleSchema, and the service validates trigger/action config, inserts the rule with crypto.randomUUID generated rule_id, and emits automation.rule.created + audit log events. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: create x-id-provenance: rule_id: automation_rules.rule_id (crypto.randomUUID) created_by: API key context userId x-publishes-event: automation.rule.created x-audit-log-action: automation_rule_created x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateAutomationRuleRequest" responses: "201": description: Automation rule created successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationRuleResponse" "400": description: Body validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:create permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected automation rule creation failure. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/rules/{id}: get: summary: Get automation rule description: Returns one automation rule by rule_id for the authenticated tenant with generated links and execution statistics. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:read. The service scopes by {rule_id, tenant}. Missing rules currently throw generic Error and surface as 500 rather than 404. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: read x-id-provenance: rule_id: automation_rules.rule_id x-no-clean-not-found-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Automation rule UUID from automation_rules.rule_id. required: true description: Automation rule UUID from automation_rules.rule_id. name: id in: path responses: "200": description: Automation rule returned successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationRuleResponse" "400": description: Invalid rule UUID format. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:read permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "404": description: Intended not-found response for missing rules; current service may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected failure, including current generic not-found errors. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" put: summary: Update automation rule description: Updates an automation rule by rule_id for the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:update. The controller validates partial updates with updateAutomationRuleSchema and the service revalidates trigger/action config when changed, updates automation_rules, and emits automation.rule.updated + audit log events. Missing rules currently surface as 500. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: update x-publishes-event: automation.rule.updated x-audit-log-action: automation_rule_updated x-no-clean-not-found-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Automation rule UUID from automation_rules.rule_id. required: true description: Automation rule UUID from automation_rules.rule_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateAutomationRuleRequest" responses: "200": description: Automation rule updated successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationRuleResponse" "400": description: Invalid UUID format or body validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:update permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "404": description: Intended not-found response for missing rules; current service may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected failure, including current generic not-found errors. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" delete: summary: Delete automation rule description: Deletes one automation rule by rule_id for the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:delete. The service blocks deletion when pending/running executions exist, unschedules active rules, deletes automation_rules row, and emits automation.rule.deleted + audit log events. Missing rules and delete constraints currently bubble as 500 errors. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: delete x-publishes-event: automation.rule.deleted x-audit-log-action: automation_rule_deleted x-no-clean-not-found-currently: true x-delete-blocked-when-running-executions: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Automation rule UUID from automation_rules.rule_id. required: true description: Automation rule UUID from automation_rules.rule_id. name: id in: path responses: "204": description: Automation rule deleted successfully. "400": description: Invalid rule UUID format. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:delete permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "404": description: Intended not-found response for missing rules; current service may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected failure, including running-execution constraints and generic not-found errors. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/rules/{id}/execute: post: summary: Execute automation rule manually description: Starts a manual execution for one automation rule identified by path rule_id. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:execute. The current request schema requires automation_rule_id in the body, but controller/service execute the path rule ID and do not cross-check the body ID. For dry_run=false the service creates automation_executions row and queues execution via a currently stubbed queue helper. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: execute x-body-automation-rule-id-not-used: true x-id-provenance: execution_id: automation_executions.execution_id (crypto.randomUUID) automation_rule_id: URL path param /rules/{id} x-publishes-event: automation.execution.started x-audit-log-action: automation_execution_started x-queues-execution-stubbed: true x-no-clean-not-found-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Automation rule UUID from automation_rules.rule_id. required: true description: Automation rule UUID from automation_rules.rule_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ManualExecutionRequest" responses: "201": description: Manual execution created successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationExecutionResponse" "400": description: Invalid UUID format or body validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:execute permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "404": description: Intended not-found response for missing rules; current service may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected failure, including current generic not-found and inactive-rule errors. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/rules/bulk-status: post: summary: Bulk update automation rule status description: Updates status for up to 100 automation rules under the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:update. The controller validates ids/status with bulkStatusUpdateSchema and calls updateAutomationRule per id. Failures are collected into an errors array and still return HTTP 200 with partial-success details. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: update x-partial-failures-return-200: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkStatusUpdateRequest" responses: "200": description: Bulk status update attempted for all ids; includes per-id errors. content: application/json: schema: $ref: "#/components/schemas/BulkStatusUpdateResponse" "400": description: Body validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:update permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected controller or service failure before result aggregation. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/rules/bulk-execute: post: summary: Bulk execute automation rules description: Starts execution attempts for up to 20 automation rules for the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:execute. The controller validates bulkExecutionSchema and calls executeAutomationRule per id. sequential_execution=true runs serially; otherwise Promise.all is used. Per-rule errors are returned in a 200 response. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: execute x-partial-failures-return-200: true x-sequential-execution-supported: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkExecuteRequest" responses: "200": description: Bulk execution attempted for all ids; includes started count and per-id errors. content: application/json: schema: $ref: "#/components/schemas/BulkExecuteResponse" "400": description: Body validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:execute permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected controller or service failure before result aggregation. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/templates: get: summary: List automation templates description: Returns a paginated list of automation templates for the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:read. The controller validates query params with templatesListSchema and the service filters automation_templates by tenant. Current service code wraps template array before createPaginatedResponse, which can produce nested data in practice. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: read x-service-data-wrapping-bug: true x-alga-products: - psa parameters: - schema: type: string description: Page number as a query string. Defaults to 1. required: false description: Page number as a query string. Defaults to 1. name: page in: query - schema: type: string description: Page size as a query string. Must parse to 1 through 100; defaults to 25. required: false description: Page size as a query string. Must parse to 1 through 100; defaults to 25. name: limit in: query - schema: type: string description: Accepted by shared list query validation; service currently orders templates by created_at desc. required: false description: Accepted by shared list query validation; service currently orders templates by created_at desc. name: sort in: query - schema: type: string enum: *a54 description: Accepted by shared list query validation. required: false description: Accepted by shared list query validation. name: order in: query - schema: type: string description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: search in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: created_from in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: created_to in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: updated_from in: query - schema: type: string format: date-time description: Accepted by shared filter validation. required: false description: Accepted by shared filter validation. name: updated_to in: query - schema: type: string enum: *a55 description: Accepted by shared filter validation and transformed to boolean. required: false description: Accepted by shared filter validation and transformed to boolean. name: is_active in: query - schema: type: string description: Filter templates by category. required: false description: Filter templates by category. name: category in: query - schema: type: string description: Filter templates by compatibility version tag. required: false description: Filter templates by compatibility version tag. name: compatible_version in: query - schema: type: string description: Filter templates by author/user id value saved on the template. required: false description: Filter templates by author/user id value saved on the template. name: author in: query - schema: type: integer minimum: 0 description: Minimum usage_count filter. required: false description: Minimum usage_count filter. name: usage_count_min in: query - schema: type: integer minimum: 0 description: Maximum usage_count filter. required: false description: Maximum usage_count filter. name: usage_count_max in: query responses: "200": description: Automation templates returned successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationTemplateListResponse" "400": description: Query parameter validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:read permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected automation templates listing failure. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" post: summary: Create automation template from rule description: Creates a template row by copying one source automation rule into automation_templates.template_config. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:create. The controller validates createTemplateFromRuleSchema and service emits automation.template.created + audit log events. Missing source rules currently throw generic Error and surface as 500. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: create x-id-provenance: template_id: automation_templates.template_id (crypto.randomUUID) automation_rule_id: automation_rules.rule_id x-publishes-event: automation.template.created x-audit-log-action: automation_template_created x-no-clean-not-found-currently: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateAutomationTemplateRequest" responses: "201": description: Automation template created successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationTemplateResponse" "400": description: Body validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:create permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "404": description: Intended not-found response for missing source rules; current service may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected failure, including current generic source-rule not-found errors. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/templates/{id}: get: summary: Get automation template description: Returns one automation template by template_id for the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:read. Service lookup is scoped by {template_id, tenant}. Missing templates currently throw generic Error and surface as 500 rather than 404. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: read x-id-provenance: template_id: automation_templates.template_id x-no-clean-not-found-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Automation template UUID from automation_templates.template_id. required: true description: Automation template UUID from automation_templates.template_id. name: id in: path responses: "200": description: Automation template returned successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationTemplateResponse" "400": description: Invalid template UUID format. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:read permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "404": description: Intended not-found response for missing templates; current service may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected failure, including current generic not-found errors. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/templates/{id}/use: post: summary: Create automation rule from template description: Uses one template_id to create a new automation rule under the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:create. The controller validates `{ variables }`, then service loads template, applies substitutions into template_config, creates rule via createAutomationRule, and increments automation_templates.usage_count/last_used. Missing templates surface as 500. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: create x-id-provenance: template_id: automation_templates.template_id rule_id: automation_rules.rule_id (crypto.randomUUID from createAutomationRule) x-uses-template-config-clone: true x-no-clean-not-found-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Automation template UUID from automation_templates.template_id. required: true description: Automation template UUID from automation_templates.template_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UseAutomationTemplateRequest" responses: "201": description: Automation rule created from template. content: application/json: schema: $ref: "#/components/schemas/AutomationRuleResponse" "400": description: Invalid template UUID format or body validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:create permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "404": description: Intended not-found response for missing templates; current service may surface this as 500. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected failure, including current generic template not-found errors. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/statistics: get: summary: Get automation statistics description: Returns tenant-scoped automation aggregate counts (rules and executions) plus HATEOAS links. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:read. The service computes counts from automation_rules and automation_executions plus period-based execution totals and success rate. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: read x-analytics-from-tables: - automation_rules - automation_executions x-alga-products: - psa responses: "200": description: Automation statistics returned successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationStatisticsResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:read permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected automation statistics failure. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/performance: get: summary: Get automation performance metrics description: Returns performance metrics calculated by AutomationService.calculatePerformanceMetrics for the authenticated tenant. Authentication uses x-api-key with optional x-tenant-id; RBAC requires automation:read. Query is validated with performanceMetricsRequestSchema; because validateQueryParams maps URL values to strings, array filters (rule_ids, metrics) currently have parsing limitations and may fail validation unless encoded specially. tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: read x-query-array-parsing-gap: true x-alga-products: - psa parameters: - schema: type: string format: date-time description: Optional lower bound for performance window. required: false description: Optional lower bound for performance window. name: date_from in: query - schema: type: string format: date-time description: Optional upper bound for performance window. required: false description: Optional upper bound for performance window. name: date_to in: query - schema: type: string enum: *a56 description: Aggregation bucket size; defaults to day. required: false description: Aggregation bucket size; defaults to day. name: group_by in: query - schema: type: string description: Raw query value copied from URL. The controller expects an array UUID schema but validateQueryParams passes string values, so array filters currently require custom caller-side encoding or fail validation. required: false description: Raw query value copied from URL. The controller expects an array UUID schema but validateQueryParams passes string values, so array filters currently require custom caller-side encoding or fail validation. name: rule_ids in: query - schema: type: string description: Raw query value copied from URL. The controller expects an array enum schema but validateQueryParams passes string values, so array filters currently require custom caller-side encoding or fail validation. required: false description: Raw query value copied from URL. The controller expects an array enum schema but validateQueryParams passes string values, so array filters currently require custom caller-side encoding or fail validation. name: metrics in: query responses: "200": description: Automation performance payload returned successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationPerformanceResponse" "400": description: Query parameter validation failed. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:read permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected performance metrics failure. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/v1/automation/meta: get: summary: Get automation metadata description: "Returns a static reference catalog of automation enum values: trigger types, action types, rule statuses, execution statuses, priority levels, and condition operators. Authentication uses x-api-key with optional x-tenant-id; the controller validates the API key, resolves tenant context, and requires automation:read permission. The response is hardcoded and performs no service or database lookup beyond authentication/RBAC." tags: - Automation security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: automation x-rbac-action: read x-static-reference-data: true x-alga-products: - psa responses: "200": description: Automation metadata returned successfully. content: application/json: schema: $ref: "#/components/schemas/AutomationMetaResponse" "401": description: API key is missing, invalid, expired, over limit, or the key user was not found. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "403": description: Authenticated user lacks automation:read permission. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" "500": description: Unexpected automation metadata failure. content: application/json: schema: $ref: "#/components/schemas/AutomationErrorResponse" /api/billing/licence-count: get: summary: Get tenant licence usage description: Server-to-server webhook endpoint used by the billing service to query current licence usage for a tenant. The caller supplies tenant_id and an x-webhook-signature header containing HMAC-SHA256("GET:", ALGA_WEBHOOK_SECRET). The response reports the configured licensed internal-user limit, active internal-user count, calculated remaining seats, and last licence update timestamp. tags: - Billing security: - WebhookSignatureAuth: [] extensions: x-webhook-secured: true x-server-to-server: true x-alga-products: - psa parameters: - schema: type: string description: Tenant identifier to query. This must match a tenants.tenant record. required: true description: Tenant identifier to query. This must match a tenants.tenant record. name: tenant_id in: query - schema: type: string description: HMAC-SHA256 hex digest proving the caller knows ALGA_WEBHOOK_SECRET. required: true description: HMAC-SHA256 hex digest proving the caller knows ALGA_WEBHOOK_SECRET. name: x-webhook-signature in: header responses: "200": description: Licence usage returned successfully. content: application/json: schema: $ref: "#/components/schemas/LicenceUsageResponse" "400": description: Missing tenant_id query parameter. content: application/json: schema: $ref: "#/components/schemas/LicenceCountErrorResponse" "401": description: Webhook signature missing or invalid. content: application/json: schema: $ref: "#/components/schemas/LicenceCountErrorResponse" "404": description: Tenant not found. content: application/json: schema: $ref: "#/components/schemas/LicenceCountErrorResponse" "500": description: Unexpected internal error. content: application/json: schema: $ref: "#/components/schemas/LicenceCountErrorResponse" post: summary: Update tenant licensed user count description: Server-to-server webhook endpoint used by the billing service to synchronize a tenant's licensed internal-user count from a Stripe subscription quantity. The x-webhook-signature header must be the HMAC-SHA256 hex digest of the raw JSON request body using ALGA_WEBHOOK_SECRET. When event_id is provided, the handler treats tenants.stripe_event_id as an idempotency marker and skips duplicate Stripe events. tags: - Billing security: - WebhookSignatureAuth: [] extensions: x-webhook-secured: true x-server-to-server: true x-alga-products: - psa parameters: - schema: type: string description: HMAC-SHA256 hex digest proving the caller knows ALGA_WEBHOOK_SECRET. required: true description: HMAC-SHA256 hex digest proving the caller knows ALGA_WEBHOOK_SECRET. name: x-webhook-signature in: header requestBody: description: Licence count update payload from the billing service. required: true content: application/json: schema: $ref: "#/components/schemas/LicenceCountUpdateRequest" description: Licence count update payload from the billing service. responses: "200": description: Licence count update accepted, or duplicate event safely ignored. content: application/json: schema: $ref: "#/components/schemas/LicenceCountUpdateResponse" "400": description: tenant_id or license_count is missing or invalid. content: application/json: schema: $ref: "#/components/schemas/LicenceCountErrorResponse" "401": description: Webhook signature missing or invalid. content: application/json: schema: $ref: "#/components/schemas/LicenceCountErrorResponse" "404": description: Tenant not found. content: application/json: schema: $ref: "#/components/schemas/LicenceCountErrorResponse" "500": description: Unexpected internal error. content: application/json: schema: $ref: "#/components/schemas/LicenceCountErrorResponse" /api/chat/stream/title: post: summary: Generate chat title stream description: Enterprise-only AI endpoint that generates a short title from conversation messages. Requires a valid Auth.js session and the aiAssistant experimental feature enabled for the tenant. The handler sends the messages to OpenRouter and returns Server-Sent Events; the implementation emits a generated title event and a completion event rather than a conventional JSON response. tags: - Chat security: - SessionCookieAuth: [] extensions: x-edition-gated: enterprise x-feature-flag: aiAssistant x-streaming: sse x-alga-products: - psa requestBody: description: Conversation messages to summarize into a title. required: true content: application/json: schema: $ref: "#/components/schemas/ChatTitleStreamRequest" description: Conversation messages to summarize into a title. responses: "200": description: SSE stream of title-generation events. content: text/event-stream: schema: $ref: "#/components/schemas/ChatStreamEvent" "403": description: AI Assistant feature is not enabled for the tenant. content: application/json: schema: $ref: "#/components/schemas/ChatStreamError" "404": description: Chat streaming is not available in this edition. content: application/json: schema: type: string description: Edition-gate error message. "500": description: Malformed request, missing model credentials, or another internal streaming failure. content: application/json: schema: $ref: "#/components/schemas/ChatStreamError" /api/chat/stream/{slug}: get: summary: Get chat stream placeholder description: Placeholder GET handler for the chat stream catch-all route. The slug path segment is accepted by the Next.js route but is not inspected. The handler currently returns the plain text string "Hello World" and does not require authentication. tags: - Chat security: [] x-alga-products: - psa parameters: - schema: type: string description: Catch-all chat stream path segment. The current handler accepts the value but does not use it. required: true description: Catch-all chat stream path segment. The current handler accepts the value but does not use it. name: slug in: path responses: "200": description: Plain text placeholder response. content: text/plain: schema: type: string description: Always returns Hello World. post: summary: Stream AI chat response description: Enterprise-only AI chat endpoint that accepts conversation messages and returns an assistant response via Server-Sent Events. Requires a valid Auth.js session and the aiAssistant experimental feature enabled for the tenant. The slug path segment is accepted by the catch-all route but is not used by the implementation. API-key authentication is skipped for /api/chat; tenant context comes from the session. tags: - Chat security: - SessionCookieAuth: [] extensions: x-edition-gated: enterprise x-feature-flag: aiAssistant x-streaming: sse x-alga-products: - psa parameters: - schema: type: string description: Catch-all chat stream path segment. The current handler accepts the value but does not use it. required: true description: Catch-all chat stream path segment. The current handler accepts the value but does not use it. name: slug in: path requestBody: description: Conversation messages and optional legacy metadata for the chat model. required: true content: application/json: schema: $ref: "#/components/schemas/ChatStreamRequest" description: Conversation messages and optional legacy metadata for the chat model. responses: "200": description: SSE stream of chat response events. Each data frame contains content and type. content: text/event-stream: schema: $ref: "#/components/schemas/ChatStreamEvent" "403": description: AI Assistant feature is not enabled for the tenant. content: application/json: schema: $ref: "#/components/schemas/ChatStreamError" "404": description: Chat streaming is not available in this edition. content: application/json: schema: type: string description: Edition-gate error message. "500": description: Malformed request, missing OpenRouter API key, or another internal streaming failure. content: application/json: schema: $ref: "#/components/schemas/ChatStreamError" /api/v1/clients: get: summary: List clients description: Inherited ApiBaseController list route for clients. Requires API-key auth and client:read permission. tags: - Clients security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: client x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a57 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string format: date-time required: false name: created_from in: query - schema: type: string format: date-time required: false name: created_to in: query - schema: type: string format: date-time required: false name: updated_from in: query - schema: type: string format: date-time required: false name: updated_to in: query - schema: type: string required: false name: client_name in: query - schema: type: string required: false name: email in: query - schema: type: string required: false name: client_type in: query - schema: type: string enum: *a58 required: false name: billing_cycle in: query - schema: type: string enum: *a59 required: false name: is_inactive in: query - schema: type: string enum: *a60 required: false name: is_tax_exempt in: query - schema: type: string format: uuid required: false name: account_manager_id in: query - schema: type: string required: false name: region_code in: query - schema: type: string required: false name: credit_balance_min in: query - schema: type: string required: false name: credit_balance_max in: query - schema: type: string enum: *a61 required: false name: has_credit_limit in: query - schema: type: string required: false name: industry in: query - schema: type: string required: false name: company_size in: query responses: "200": description: Paginated clients returned. content: application/json: schema: $ref: "#/components/schemas/PaginatedClientEnvelope" "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for client read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected client listing failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" post: summary: Create client description: Inherited ApiBaseController create route for clients. Requires API-key auth and client:create permission. tags: - Clients security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: client x-rbac-action: create x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ClientBody" responses: "201": description: Client created. content: application/json: schema: $ref: "#/components/schemas/ClientEnvelope" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for client create. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected client creation failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/clients/{id}: get: summary: Get client description: Inherited ApiBaseController get route for one client_id. tags: - Clients security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: client x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path responses: "200": description: Client returned. content: application/json: schema: $ref: "#/components/schemas/ClientEnvelope" "400": description: Invalid client id format. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for client read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "404": description: Client not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected client retrieval failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" put: summary: Update client description: Inherited ApiBaseController update route for one client_id. tags: - Clients security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: client x-rbac-action: update x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ClientBody" responses: "200": description: Client updated. content: application/json: schema: $ref: "#/components/schemas/ClientEnvelope" "400": description: Invalid client id or request payload. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for client update. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "404": description: Client not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected client update failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" delete: summary: Delete client description: Inherited ApiBaseController delete route for one client_id. tags: - Clients security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: client x-rbac-action: delete x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path responses: "204": description: Client deleted. "400": description: Invalid client id format. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for client delete. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "404": description: Client not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected client deletion failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/clients/stats: get: summary: Get client stats description: Client statistics route with explicit API-key validation and client:read permission check. tags: - Clients security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: client x-rbac-action: read x-alga-products: - psa - algadesk responses: "200": description: Client stats returned. content: application/json: schema: $ref: "#/components/schemas/ClientStatsEnvelope" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for client read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected client stats failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/clients/{id}/contacts: get: summary: List contacts for client description: Returns paginated contacts filtered by client_id after client existence check. tags: - Clients security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: client x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path responses: "200": description: Client contacts returned. content: application/json: schema: $ref: "#/components/schemas/PaginatedContactEnvelope" "400": description: Invalid client id format. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for client read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "404": description: Client not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected client contacts failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/clients/{id}/locations: get: summary: List client locations description: Returns locations associated with client_id after client existence check. tags: - Clients security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: client x-rbac-action: read x-deprecated-route-commented: true x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path responses: "200": description: Client locations returned. content: application/json: schema: $ref: "#/components/schemas/ClientLocationsEnvelope" "400": description: Invalid client id format. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for client read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "404": description: Client not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected client locations failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" post: summary: Create client location description: Creates a location row for client_id after validation and client existence check. tags: - Clients security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: client x-rbac-action: update x-deprecated-route-commented: true x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ClientLocationBody" responses: "201": description: Client location created. content: application/json: schema: $ref: "#/components/schemas/ClientLocationEnvelope" "400": description: Invalid client id or request payload. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for client update. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "404": description: Client not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected client location creation failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/contacts: get: summary: List contacts description: Inherited ApiBaseController list route for contacts. tags: - Contacts security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: contact x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a62 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string format: date-time required: false name: created_from in: query - schema: type: string format: date-time required: false name: created_to in: query - schema: type: string format: date-time required: false name: updated_from in: query - schema: type: string format: date-time required: false name: updated_to in: query - schema: type: string required: false name: full_name in: query - schema: type: string required: false name: email in: query - schema: type: string required: false name: phone_number in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string required: false name: role in: query - schema: type: string enum: *a63 required: false name: is_inactive in: query - schema: type: string enum: *a64 required: false name: has_client in: query - schema: type: string required: false name: client_name in: query responses: "200": description: Paginated contacts returned. content: application/json: schema: $ref: "#/components/schemas/PaginatedContactEnvelope" "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for contact read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected contact listing failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" post: summary: Create contact description: Inherited ApiBaseController create route for contacts. tags: - Contacts security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: contact x-rbac-action: create x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ContactBody" responses: "201": description: Contact created. content: application/json: schema: $ref: "#/components/schemas/ClientContactEnvelope" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for contact create. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected contact creation failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/contacts/{id}: get: summary: Get contact description: Inherited ApiBaseController get route for one contact_name_id. tags: - Contacts security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: contact x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path responses: "200": description: Contact returned. content: application/json: schema: $ref: "#/components/schemas/ClientContactEnvelope" "400": description: Invalid contact id format. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for contact read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "404": description: Contact not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected contact retrieval failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" put: summary: Update contact description: Inherited ApiBaseController update route for one contact_name_id. tags: - Contacts security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: contact x-rbac-action: update x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ContactBody" responses: "200": description: Contact updated. content: application/json: schema: $ref: "#/components/schemas/ClientContactEnvelope" "400": description: Invalid contact id or request payload. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for contact update. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "404": description: Contact not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected contact update failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" delete: summary: Delete contact description: Inherited ApiBaseController delete route for one contact_name_id. tags: - Contacts security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: contact x-rbac-action: delete x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path responses: "204": description: Contact deleted. "400": description: Invalid contact id format. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for contact delete. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "404": description: Contact not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected contact deletion failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/contacts/search: get: summary: Search contacts description: Runs advanced contact search with explicit API-key auth and contact:read permission check. tags: - Contacts security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: contact x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string minLength: 1 required: true name: query in: query - schema: type: string description: Comma-separated field list; parsed by contactSearchSchema transform. required: false description: Comma-separated field list; parsed by contactSearchSchema transform. name: fields in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string enum: *a65 required: false name: include_inactive in: query - schema: type: string required: false name: limit in: query responses: "200": description: Contact search results returned. content: application/json: schema: $ref: "#/components/schemas/ContactSearchEnvelope" "400": description: Invalid search query. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for contact read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected contact search failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/contacts/export: get: summary: Export contacts description: Exports contacts as CSV or JSON using explicit API-key auth and contact:read permission. tags: - Contacts security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: contact x-rbac-action: read x-returns-csv-when-format-csv: true x-alga-products: - psa - algadesk parameters: - schema: type: string enum: *a66 required: false name: format in: query - schema: type: string enum: *a67 required: false name: include_inactive in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string description: Array schema expects parsed list, but URL values arrive as string. required: false description: Array schema expects parsed list, but URL values arrive as string. name: fields in: query responses: "200": description: Contact export response. CSV format returns text/csv body; JSON format returns standard API envelope. content: application/json: schema: $ref: "#/components/schemas/ContactExportEnvelope" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for contact read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected contact export failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/contacts/stats: get: summary: Get contact stats description: Returns contact statistics using explicit API-key auth and contact:read permission. tags: - Contacts security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: contact x-rbac-action: read x-alga-products: - psa - algadesk responses: "200": description: Contact stats returned. content: application/json: schema: $ref: "#/components/schemas/ContactStatsEnvelope" "401": description: API key missing/invalid or key user not found. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "403": description: Permission denied for contact read. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unexpected contact stats failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/client-contract-lines: get: summary: List client contract lines description: Lists client contract lines — contract_lines rows that belong to client contracts (joined via contract_id), with the owning client_id and client_contract_id surfaced. Supports client_id, contract_line_id, service_category, is_active, has_custom_rate, and start/end-date-range filters plus page/limit pagination. Authenticated and tenant-scoped via withApiKeyRouteAuth. tags: - Client Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a68 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string format: date-time required: false name: created_from in: query - schema: type: string format: date-time required: false name: created_to in: query - schema: type: string format: date-time required: false name: updated_from in: query - schema: type: string format: date-time required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: contract_line_id in: query - schema: type: string required: false name: service_category in: query - schema: type: string enum: *a69 required: false name: is_active in: query - schema: type: string enum: *a70 required: false name: has_custom_rate in: query - schema: type: string enum: *a71 required: false name: is_contractd in: query - schema: type: string format: date-time required: false name: start_date_from in: query - schema: type: string format: date-time required: false name: start_date_to in: query - schema: type: string format: date-time required: false name: end_date_from in: query - schema: type: string format: date-time required: false name: end_date_to in: query responses: "200": description: Paginated client contract lines returned. content: application/json: schema: $ref: "#/components/schemas/ClientContractLineListEnvelope" "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unhandled failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" post: summary: Assign contract line to client description: Assigns one contract line to a client by cloning a template line into the client contract, using createClientContractLineSchema validation. Authenticated and tenant-scoped via withApiKeyRouteAuth. tags: - Client Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-id-provenance: client_contract_line_id: contract_lines.contract_line_id (client-owned line model) x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ClientContractLineBody" responses: "201": description: Client contract line assignment created. content: application/json: schema: $ref: "#/components/schemas/ClientContractLineEnvelope" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unhandled assignment failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/client-contract-lines/{id}: delete: summary: Unassign contract line from client description: Deactivates the client-owned contract line for the provided id. Authenticated and tenant-scoped via withApiKeyRouteAuth. tags: - Client Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-request-context-required: true x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: id in: path responses: "204": description: Client contract line unassigned. "400": description: Invalid assignment id format. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" "500": description: Unassignment failure. content: application/json: schema: $ref: "#/components/schemas/ClientContactApiError" /api/v1/contract-lines: get: summary: List contract lines description: Lists contract lines with pagination/filtering and optional include flags. Authenticated and tenant-scoped via withApiKeyRouteAuth. Query parsing/validation uses contractLineListQuerySchema, then listWithOptions reads from contract_lines for the tenant context. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a72 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string format: date-time required: false name: created_from in: query - schema: type: string format: date-time required: false name: created_to in: query - schema: type: string format: date-time required: false name: updated_from in: query - schema: type: string format: date-time required: false name: updated_to in: query - schema: type: string required: false name: contract_line_name in: query - schema: type: string enum: *a11 required: false name: contract_line_type in: query - schema: type: string enum: *a10 required: false name: billing_frequency in: query - schema: type: string enum: *a73 required: false name: is_custom in: query - schema: type: string enum: *a74 required: false name: is_active in: query - schema: type: string required: false name: service_category in: query - schema: type: string enum: *a75 required: false name: has_services in: query - schema: type: string required: false name: clients_count_min in: query - schema: type: string required: false name: clients_count_max in: query - schema: type: string required: false name: revenue_min in: query - schema: type: string required: false name: revenue_max in: query - schema: type: string enum: *a76 description: Controller-level include flag parsed directly from query string. required: false description: Controller-level include flag parsed directly from query string. name: include_services in: query - schema: type: string enum: *a77 description: Controller-level include flag parsed directly from query string. required: false description: Controller-level include flag parsed directly from query string. name: include_usage in: query - schema: type: string enum: *a78 description: Controller-level include flag parsed directly from query string. required: false description: Controller-level include flag parsed directly from query string. name: include_clients in: query responses: "200": description: Contract lines returned. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" post: summary: Create contract line description: Creates a contract line row in contract_lines. Validation uses createContractLineSchema (including overtime/after-hours constraints). ID is generated by service with uuidv4. Route currently relies on request context presence and can fail when context is unavailable. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-id-provenance: contract_line_id: contract_lines.contract_line_id (uuidv4) x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ContractLineBody" responses: "201": description: Contract line created. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/{id}: get: summary: Get contract line description: Returns one contract line by contract_line_id, including optional related data through include query flags. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path responses: "200": description: Contract line returned. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "404": description: Contract line not found. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" put: summary: Update contract line description: Updates a contract line by contract_line_id using updateContractLineSchema validation. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateContractLineBody" responses: "200": description: Contract line updated. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" delete: summary: Delete contract line description: Deletes a contract line after dependency checks (in-use checks, service cleanup, contract detach). tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-returns-json-with-204-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path responses: "204": description: Deletion processed. "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or delete blocked by dependency rules. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/bulk: post: summary: Bulk create contract lines description: Alias route to bulkCreateContractLines; creates multiple contract lines from `plans` array. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkCreateContractLinesBody" responses: "201": description: Bulk create completed. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" put: summary: Bulk update contract lines description: Alias route to bulkUpdateContractLines; updates multiple rows by contract_line_id. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkUpdateContractLinesBody" responses: "200": description: Bulk update completed. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" delete: summary: Bulk delete contract lines description: Alias route to bulkDeleteContractLines; deletes multiple contract lines by ID list. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkDeleteContractLinesBody" responses: "200": description: Bulk delete completed. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or delete blocked by dependency rules. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/bulk/create: post: summary: Bulk create contract lines (explicit route) description: Same controller behavior as POST /api/v1/contract-lines/bulk. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkCreateContractLinesBody" responses: "201": description: Bulk create completed. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/bulk/update: put: summary: Bulk update contract lines (explicit route) description: Same controller behavior as PUT /api/v1/contract-lines/bulk. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkUpdateContractLinesBody" responses: "200": description: Bulk update completed. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/bulk/delete: delete: summary: Bulk delete contract lines (explicit route) description: Same controller behavior as DELETE /api/v1/contract-lines/bulk. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkDeleteContractLinesBody" responses: "200": description: Bulk delete completed. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or delete blocked by dependency rules. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/bulk/add-services: post: summary: Bulk add services to contract line description: Adds multiple services to one contract_line_id and returns per-service success/failure results. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-partial-failures-in-response: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkAddServicesBody" responses: "200": description: Bulk service add completed. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/bulk/remove-services: delete: summary: Bulk remove services from contract line description: Removes multiple services from one contract_line_id and returns per-service success/failure results. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-partial-failures-in-response: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkRemoveServicesBody" responses: "200": description: Bulk service removal completed. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or unhandled service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/{id}/activation: put: summary: Set contract line activation description: Activates or deactivates a contract line. Deactivation can require a reason when plan is in use. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ContractLineActivationBody" responses: "200": description: Activation state updated. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or activation business-rule failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/{id}/analytics: get: summary: Get contract line analytics description: Returns analytics aggregates for one contract line. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path responses: "200": description: Analytics payload returned. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or analytics query failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/{id}/copy: post: summary: Copy contract line description: Copies an existing contract line. Current implementation validates and uses `source_contract_line_id` from body, while path `{id}` is not consumed by service logic. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-path-id-ignored-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CopyContractLineBody" responses: "201": description: Contract line copy created. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or copy operation failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/{id}/fixed-config: get: summary: Get fixed contract line config description: Returns fixed-plan configuration for a contract line; returns 404 when not found. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path responses: "200": description: Fixed config returned. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "404": description: Fixed configuration not found. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" put: summary: Upsert fixed contract line config description: Creates or updates fixed-plan configuration for a contract line. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ContractLineFixedConfigBody" responses: "200": description: Fixed config upserted. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/{id}/services: get: summary: List contract line services description: Returns all service configurations linked to a contract line. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path responses: "200": description: Service configurations returned. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" post: summary: Add service to contract line description: Adds one service configuration to a contract line; rejects duplicates. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ContractLineAddServiceBody" responses: "201": description: Service added to contract line. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or service-level validation failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/{id}/services/{serviceId}: get: summary: Get contract line service details description: Route inventory advertises item lookup, but current route handler delegates to getContractLineServices and returns the full service list for `{id}`; `{serviceId}` is effectively ignored in the GET path. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-service-id-ignored-by-get-handler: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path - schema: type: string format: uuid description: Service UUID from service_catalog.service_id. required: true description: Service UUID from service_catalog.service_id. name: serviceId in: path responses: "200": description: Current implementation returns full service list for the contract line. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" put: summary: Update contract line service description: Updates service configuration for one `{id}` + `{serviceId}` pair. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path - schema: type: string format: uuid description: Service UUID from service_catalog.service_id. required: true description: Service UUID from service_catalog.service_id. name: serviceId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ContractLineUpdateServiceBody" responses: "200": description: Service configuration updated. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or service failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" delete: summary: Remove service from contract line description: Removes one service configuration from a contract line. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-returns-json-with-204-currently: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path - schema: type: string format: uuid description: Service UUID from service_catalog.service_id. required: true description: Service UUID from service_catalog.service_id. name: serviceId in: path responses: "204": description: Service removed. "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or service removal failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-lines/{id}/usage-metrics: get: summary: Get contract line usage metrics description: Returns usage and cost metrics for a contract line over a time window. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract line UUID from contract_lines.contract_line_id. required: true description: Contract line UUID from contract_lines.contract_line_id. name: id in: path - schema: type: string format: date-time description: Defaults to now minus 30 days when omitted. required: false description: Defaults to now minus 30 days when omitted. name: period_start in: query - schema: type: string format: date-time description: Defaults to now when omitted. required: false description: Defaults to now when omitted. name: period_end in: query responses: "200": description: Usage metrics returned. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or usage query failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-line-templates: post: summary: Create contract line template description: Creates a plan template record under plan_templates with optional default services. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-id-provenance: template_id: plan_templates.template_id (uuidv4) x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateContractLineTemplateBody" responses: "201": description: Template created. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing at middleware. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Request context missing or template creation failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/v1/contract-line-templates/{id}/create-contract-line: post: summary: Create contract line from template description: Creates a contract line from a template. The template id is taken from the path `{id}` (it takes precedence over any template_id in the body), and the rest of the body is validated with createPlanFromTemplateSchema. Authenticated and tenant-scoped via withApiKeyRouteAuth. tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence + request context requirement in controller x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Template UUID from plan_templates.template_id. required: true description: Template UUID from plan_templates.template_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateContractLineFromTemplateBody" responses: "201": description: Contract line created from template. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "401": description: x-api-key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" "500": description: Template application failure. content: application/json: schema: $ref: "#/components/schemas/ContractLineApiError" /api/documents/download/{fileId}: get: summary: Download or export document file description: Downloads a stored document file, or exports the document as PDF or Markdown based on the optional format query parameter. The fileId path value may be either a documents.document_id or an external_files.file_id. The route requires an Auth.js session cookie and runs within the session tenant. The normal download path uses document read permission and document authorization rules; PDF and Markdown export paths perform tenant-scoped document lookup and generation. tags: - Documents security: - SessionCookieAuth: [] extensions: x-download-formats: - original - pdf - markdown x-api-key-auth-skipped: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Document UUID or file UUID. The download handler resolves document_id first, then file_id. required: true description: Document UUID or file UUID. The download handler resolves document_id first, then file_id. name: fileId in: path - schema: type: string enum: *a79 description: Optional export format. pdf generates a PDF; markdown or md exports markdown; omitted downloads the original stored file. required: false description: Optional export format. pdf generates a PDF; markdown or md exports markdown; omitted downloads the original stored file. name: format in: query responses: "200": description: File bytes for the original stored file, generated PDF, or Markdown text. Content-Type varies by requested format and stored MIME type. content: application/octet-stream: schema: $ref: "#/components/schemas/BinaryFileResponse" "400": description: Invalid or missing fileId. content: application/json: schema: $ref: "#/components/schemas/DocumentDownloadError" "401": description: No valid session is present. content: application/json: schema: $ref: "#/components/schemas/DocumentDownloadError" "404": description: Document or file was not found, has no associated file, or has no exportable content. content: application/json: schema: $ref: "#/components/schemas/DocumentDownloadError" "500": description: Export, generated-PDF download, storage, or unexpected internal failure. content: application/json: schema: $ref: "#/components/schemas/DocumentDownloadError" /api/documents/{documentId}/download: get: summary: Download document attachment description: Downloads the original stored file for a document as an attachment. The documentId path value is resolved against documents.document_id first, then documents.file_id. The route supports Auth.js session-cookie authentication and x-api-key fallback for machine clients, derives the tenant from the authenticated principal, requires document:read permission, and runs document authorization rules before reading the file from storage. tags: - Documents security: - SessionCookieAuth: [] - ApiKeyAuth: [] extensions: x-auth-modes: - session-cookie - api-key x-id-resolution: document_id_then_file_id x-rbac-required: document:read x-alga-products: - psa parameters: - schema: type: string format: uuid description: Document UUID from documents.document_id, or file UUID from documents.file_id. The handler resolves document_id first and falls back to file_id. required: true description: Document UUID from documents.document_id, or file UUID from documents.file_id. The handler resolves document_id first and falls back to file_id. name: documentId in: path - schema: type: string description: Optional API key for machine-to-machine download requests. Used only when no valid Auth.js session cookie is present. required: false description: Optional API key for machine-to-machine download requests. Used only when no valid Auth.js session cookie is present. name: x-api-key in: header responses: "200": description: Binary file stream with attachment Content-Disposition headers. Content-Type varies by stored MIME type. content: application/octet-stream: schema: $ref: "#/components/schemas/BinaryFileResponse" "400": description: Missing documentId path parameter. content: application/json: schema: $ref: "#/components/schemas/DocumentDownloadError" "401": description: No valid session or API key was supplied. content: application/json: schema: $ref: "#/components/schemas/DocumentDownloadError" "403": description: Authenticated user lacks document:read permission. content: application/json: schema: $ref: "#/components/schemas/DocumentDownloadError" "404": description: Document not found, document has no file_id, or file metadata/storage record was not found. content: application/json: schema: $ref: "#/components/schemas/DocumentDownloadError" "500": description: Unexpected internal failure while downloading the document. content: application/json: schema: $ref: "#/components/schemas/DocumentDownloadError" /api/documents/view/{fileId}: get: summary: View document file inline description: Streams a stored file for inline browser viewing, such as images, videos, PDFs, and SVGs. Tenant logo files are public. Other files require either a valid Auth.js session cookie or an x-api-key header, then document-level authorization is checked using RBAC, relationship rules, bundle narrowing, and client visibility rules. Video files support HTTP Range requests and may return 206 Partial Content. tags: - Documents security: - SessionCookieAuth: [] - ApiKeyAuth: [] - {} extensions: x-supports-range-requests: true x-public-when-tenant-logo: true x-api-key-auth-skipped: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: File UUID from external_files.file_id identifying the stored file to serve. required: true description: File UUID from external_files.file_id identifying the stored file to serve. name: fileId in: path - schema: type: string description: HTTP Range header for partial video responses, for example bytes=0-1048575. Only honored for video/* files. required: false description: HTTP Range header for partial video responses, for example bytes=0-1048575. Only honored for video/* files. name: range in: header - schema: type: string description: Optional API key fallback for non-browser clients. Used only when no valid session cookie is present. required: false description: Optional API key fallback for non-browser clients. Used only when no valid session cookie is present. name: x-api-key in: header responses: "200": description: Full file stream for inline viewing. content: application/octet-stream: schema: $ref: "#/components/schemas/BinaryFileResponse" "206": description: Partial file stream for a valid video Range request. content: application/octet-stream: schema: $ref: "#/components/schemas/BinaryFileResponse" "400": description: Missing fileId or unsupported file type for inline viewing. content: text/plain: schema: $ref: "#/components/schemas/DocumentPlainTextError" "401": description: No valid session or API key was supplied. content: text/plain: schema: $ref: "#/components/schemas/DocumentPlainTextError" "403": description: Authenticated user is not authorized to view the file. content: text/plain: schema: $ref: "#/components/schemas/DocumentPlainTextError" "404": description: File was not found in metadata or storage. content: text/plain: schema: $ref: "#/components/schemas/DocumentPlainTextError" "416": description: Range header is invalid or outside the file size. content: text/plain: schema: $ref: "#/components/schemas/DocumentPlainTextError" "500": description: Unexpected internal error while authorizing or streaming the file. content: text/plain: schema: $ref: "#/components/schemas/DocumentPlainTextError" /api/email/oauth/initiate: post: summary: Initiate email OAuth flow description: Starts the OAuth 2.0 authorization flow for a Google or Microsoft email provider. Requires a valid Auth.js session cookie. The handler builds secure OAuth state containing tenant, user, providerId, redirect URI, timestamp, and nonce, resolves the provider client ID from configured secrets, and returns the authorization URL for the browser to visit. tags: - Email security: - SessionCookieAuth: [] extensions: x-api-key-auth-skipped: true x-alga-products: - psa - algadesk requestBody: description: Email OAuth initiation payload. required: true content: application/json: schema: $ref: "#/components/schemas/EmailOAuthInitiateRequest" description: Email OAuth initiation payload. responses: "200": description: OAuth authorization URL generated successfully. content: application/json: schema: $ref: "#/components/schemas/EmailOAuthInitiateResponse" "400": description: Provider is missing or not supported. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" "401": description: No authenticated user session was found. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" "500": description: OAuth client ID was not configured or initiation failed unexpectedly. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" /api/email/refresh-watch: post: summary: Refresh Gmail watch registration description: Forces Pub/Sub setup and Gmail watch registration refresh for an active Google email provider. Requires a valid Auth.js session. The providerId must reference email_providers.id for a provider_type=google record with a google_email_provider_config row and project_id. Internally this calls configureGmailProvider with force=true. tags: - Email security: - SessionCookieAuth: [] x-alga-products: - psa requestBody: description: Gmail provider refresh request. required: true content: application/json: schema: $ref: "#/components/schemas/EmailRefreshWatchRequest" description: Gmail provider refresh request. responses: "200": description: Gmail provider Pub/Sub and watch registration refreshed successfully. content: application/json: schema: $ref: "#/components/schemas/EmailRefreshWatchResponse" "400": description: providerId is missing, or the Gmail provider has no project_id configured. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" "401": description: No authenticated user session was found. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" "404": description: Gmail provider or Gmail configuration row was not found. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" "500": description: Refresh failed unexpectedly. Response includes success=false and an error message. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" /api/email/webhooks/google: options: summary: CORS preflight for Google email webhook description: CORS preflight response for the Gmail Pub/Sub webhook endpoint. This is handled by global middleware before route authentication or business logic. It does not require a session, API key, tenant, JWT, request body, or query parameter, and always returns 204 No Content with CORS headers. tags: - Email security: [] extensions: x-cors-preflight: true x-handled-by: middleware x-alga-products: - psa responses: "204": description: CORS preflight accepted; response body is empty. post: summary: Receive Google Gmail Pub/Sub webhook description: "Receives Google Pub/Sub push notifications for Gmail watches. Standard session and API-key middleware are bypassed; the handler requires an Authorization: Bearer Google-signed JWT, decodes the Pub/Sub message data into a Gmail notification with emailAddress and historyId, resolves the tenant and email provider by subscription name or mailbox, validates Google configuration, and enqueues a pointer-only job into the unified inbound email queue. It does not fetch or return email content." tags: - Email security: - GooglePubSubJWT: [] extensions: x-api-key-auth-skipped: true x-session-auth-skipped: true x-webhook-provider: google-pubsub x-alga-products: - psa requestBody: description: Google Pub/Sub push message containing a base64-encoded Gmail notification. required: true content: application/json: schema: $ref: "#/components/schemas/GooglePubSubPushBody" description: Google Pub/Sub push message containing a base64-encoded Gmail notification. responses: "200": description: Webhook accepted. Either a queue job was enqueued, or the notification was safely skipped. content: application/json: schema: anyOf: - $ref: "#/components/schemas/GoogleWebhookEnqueueResponse" - $ref: "#/components/schemas/GoogleWebhookSkippedResponse" "400": description: Permanent parse or validation error; Pub/Sub should not retry. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" "401": description: Bearer JWT is missing or invalid. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" "503": description: Transient enqueue or processing failure; Pub/Sub may retry. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" /api/email/webhooks/microsoft: get: summary: Validate Microsoft email webhook subscription description: Microsoft Graph subscription validation endpoint. During subscription creation or renewal, Microsoft calls this endpoint with validationtoken or validationToken. The handler echoes the token verbatim as text/plain. If no token is provided, it returns OK. No session, API key, tenant header, or request body is required. tags: - Email security: [] extensions: x-api-key-auth-skipped: true x-webhook-provider: microsoft-graph x-alga-products: - psa parameters: - schema: type: string description: Microsoft Graph subscription validation token. The handler also accepts validationToken with camel-case spelling. required: false description: Microsoft Graph subscription validation token. The handler also accepts validationToken with camel-case spelling. name: validationtoken in: query - schema: type: string description: Camel-case variant of the Microsoft Graph validation token. required: false description: Camel-case variant of the Microsoft Graph validation token. name: validationToken in: query responses: "200": description: Plain text validation token echo, or OK when no validation token is present. content: text/plain: schema: $ref: "#/components/schemas/MicrosoftWebhookTextResponse" "500": description: Unexpected error while handling validation request. content: text/plain: schema: $ref: "#/components/schemas/MicrosoftWebhookTextResponse" options: summary: CORS preflight for Microsoft email webhook description: CORS preflight response for the Microsoft Graph email webhook endpoint. Global middleware intercepts OPTIONS before route logic and returns 204 No Content with CORS headers. No authentication, tenant, request body, query parameter, or database access is required. tags: - Email security: [] extensions: x-cors-preflight: true x-handled-by: middleware x-alga-products: - psa responses: "204": description: CORS preflight accepted; response body is empty. post: summary: Receive Microsoft Graph email webhook description: Receives Microsoft Graph change notifications for monitored mailboxes. Standard session and API-key middleware are bypassed. The handler supports validation token echo, parses Microsoft notification batches, resolves provider and tenant by matching notification subscriptionId to microsoft_email_provider_config.webhook_subscription_id, validates clientState against the stored webhook_verification_token when configured, extracts message IDs, and enqueues pointer-only jobs into the unified inbound email queue. The tenantId in the Microsoft payload is informational and is not trusted for tenant resolution. tags: - Email security: [] extensions: x-api-key-auth-skipped: true x-session-auth-skipped: true x-webhook-provider: microsoft-graph x-alga-products: - psa parameters: - schema: type: string description: Microsoft Graph subscription validation token. The handler also accepts validationToken with camel-case spelling. required: false description: Microsoft Graph subscription validation token. The handler also accepts validationToken with camel-case spelling. name: validationtoken in: query - schema: type: string description: Camel-case variant of the Microsoft Graph validation token. required: false description: Camel-case variant of the Microsoft Graph validation token. name: validationToken in: query requestBody: description: Microsoft Graph webhook notification batch. required: true content: application/json: schema: $ref: "#/components/schemas/MicrosoftGraphWebhookBody" description: Microsoft Graph webhook notification batch. responses: "200": description: Validation token echoed as text/plain, or JSON success response after notifications are processed or skipped. content: application/json: schema: anyOf: - $ref: "#/components/schemas/MicrosoftWebhookSuccessResponse" - $ref: "#/components/schemas/MicrosoftWebhookEmptyResponse" - $ref: "#/components/schemas/MicrosoftWebhookTextResponse" "500": description: Unexpected internal server error. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" "503": description: One or more notification pointers could not be enqueued. content: application/json: schema: $ref: "#/components/schemas/MicrosoftWebhookEnqueueErrorResponse" /api/email/webhooks/test: post: summary: Publish test inbound email event description: Publishes a synthetic INBOUND_EMAIL_RECEIVED event to the workflow event stream so operators can test webhook and workflow delivery without a real provider notification. Requires a valid Auth.js session; tenant is taken from the authenticated user session. The route performs no RBAC check and does not require an API key. tags: - Email security: - SessionCookieAuth: [] x-alga-products: - psa requestBody: description: Optional synthetic email provider metadata for the test event. required: true content: application/json: schema: $ref: "#/components/schemas/EmailWebhookTestRequest" description: Optional synthetic email provider metadata for the test event. responses: "200": description: Test event was published successfully. content: application/json: schema: $ref: "#/components/schemas/EmailWebhookTestResponse" "401": description: No authenticated user session was found. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" "500": description: Failed to publish the test event. content: application/json: schema: $ref: "#/components/schemas/EmailErrorResponse" /api/ext/{extensionId}/{path}: get: summary: Forward GET request to extension runner description: Tenant-scoped extension gateway endpoint that forwards GET requests to an installed extension runner. The gateway resolves the tenant from x-alga-tenant, x-tenant-id, session cookie, or DEV_TENANT_ID in development; verifies the extension is installed and enabled for that tenant; forwards selected headers and all query parameters to RUNNER_BASE_URL /v1/execute; and relays the runner response. GET requests do not read a body and do not generate an idempotency key. The gateway currently has a placeholder access check and does not enforce per-extension RBAC beyond tenant install resolution. tags: - Extension Gateway security: - SessionCookieAuth: [] extensions: x-api-key-auth-skipped: true x-proxy-target: extension-runner x-request-body-read: false x-idempotency-generated: false x-alga-products: - psa parameters: - schema: type: string minLength: 1 description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. required: true description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. name: extensionId in: path - schema: type: string description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. required: false description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. name: path in: path - schema: type: string format: uuid description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. required: false description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. name: x-request-id in: header - schema: type: string description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. required: false description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. name: x-idempotency-key in: header - schema: type: string description: Internal tenant header used for tenant resolution before session fallback. required: false description: Internal tenant header used for tenant resolution before session fallback. name: x-alga-tenant in: header - schema: type: string description: Legacy tenant header accepted for tenant resolution before session fallback. required: false description: Legacy tenant header accepted for tenant resolution before session fallback. name: x-tenant-id in: header responses: "200": description: Runner response relayed by the gateway. The actual status can vary by extension contract. content: application/json: schema: $ref: "#/components/schemas/ExtensionOpaqueResponse" "204": description: Runner returned no content, or CORS preflight for OPTIONS requests on this gateway path. "404": description: Extension is not installed or not enabled for the resolved tenant. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "500": description: Tenant could not be resolved or another internal gateway error occurred. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "502": description: Runner call failed, runner response was empty/invalid, or install context was incomplete. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" post: summary: Forward POST request to extension runner description: Tenant-scoped extension gateway endpoint that forwards POST requests to an installed extension runner. The gateway resolves the tenant from x-alga-tenant, x-tenant-id, session cookie, or DEV_TENANT_ID in development; verifies the extension is installed and enabled for that tenant; forwards selected headers, query parameters, and an optional opaque body to RUNNER_BASE_URL /v1/execute; and relays the runner response. For POST requests the body is limited to 10 MB, base64-encoded, and forwarded as http.body_b64. An x-idempotency-key header is forwarded when supplied, otherwise the generated x-request-id is used as the non-GET idempotency fallback. The gateway currently has a placeholder access check and does not enforce per-extension RBAC beyond tenant install resolution. tags: - Extension Gateway security: - SessionCookieAuth: [] extensions: x-api-key-auth-skipped: true x-proxy-target: extension-runner x-max-body-bytes: 10485760 x-idempotency-supported: true x-idempotency-key-header: x-idempotency-key x-idempotency-fallback: x-request-id x-alga-products: - psa parameters: - schema: type: string minLength: 1 description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. required: true description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. name: extensionId in: path - schema: type: string description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. required: false description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. name: path in: path - schema: type: string format: uuid description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. required: false description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. name: x-request-id in: header - schema: type: string description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. required: false description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. name: x-idempotency-key in: header - schema: type: string description: Internal tenant header used for tenant resolution before session fallback. required: false description: Internal tenant header used for tenant resolution before session fallback. name: x-alga-tenant in: header - schema: type: string description: Legacy tenant header accepted for tenant resolution before session fallback. required: false description: Legacy tenant header accepted for tenant resolution before session fallback. name: x-tenant-id in: header requestBody: description: Optional extension-specific POST body. The gateway accepts any content type up to 10 MB and forwards it as base64. required: false content: application/json: schema: $ref: "#/components/schemas/ExtensionOpaqueRequest" description: Optional extension-specific POST body. The gateway accepts any content type up to 10 MB and forwards it as base64. responses: "200": description: Runner response relayed by the gateway. The actual status can vary by extension contract. content: application/json: schema: $ref: "#/components/schemas/ExtensionOpaqueResponse" "204": description: Runner returned no content, or CORS preflight for OPTIONS requests on this gateway path. "404": description: Extension is not installed or not enabled for the resolved tenant. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "413": description: Request body exceeds the 10 MB gateway limit. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "500": description: Tenant could not be resolved or another internal gateway error occurred. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "502": description: Runner call failed, runner response was empty/invalid, or install context was incomplete. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" put: summary: Forward PUT request to extension runner description: Tenant-scoped extension gateway endpoint that forwards PUT requests to an installed extension runner. The gateway resolves the tenant from x-alga-tenant, x-tenant-id, session cookie, or DEV_TENANT_ID in development; verifies the extension is installed and enabled for that tenant; forwards selected headers, query parameters, and an optional opaque body to RUNNER_BASE_URL /v1/execute; and relays the runner response. For PUT requests the body is limited to 10 MB, base64-encoded, and forwarded as http.body_b64. Clients should provide x-idempotency-key for safe retries; otherwise the gateway falls back to a generated request ID. The gateway currently has a placeholder access check and does not enforce per-extension RBAC beyond tenant install resolution. tags: - Extension Gateway security: - SessionCookieAuth: [] extensions: x-api-key-auth-skipped: true x-proxy-target: extension-runner x-max-body-bytes: 10485760 x-idempotency-supported: true x-idempotency-key-header: x-idempotency-key x-idempotency-fallback: x-request-id x-alga-products: - psa parameters: - schema: type: string minLength: 1 description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. required: true description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. name: extensionId in: path - schema: type: string description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. required: false description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. name: path in: path - schema: type: string format: uuid description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. required: false description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. name: x-request-id in: header - schema: type: string description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. required: false description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. name: x-idempotency-key in: header - schema: type: string description: Internal tenant header used for tenant resolution before session fallback. required: false description: Internal tenant header used for tenant resolution before session fallback. name: x-alga-tenant in: header - schema: type: string description: Legacy tenant header accepted for tenant resolution before session fallback. required: false description: Legacy tenant header accepted for tenant resolution before session fallback. name: x-tenant-id in: header requestBody: description: Optional extension-specific PUT body. The gateway accepts any content type up to 10 MB and forwards it as base64. required: false content: application/json: schema: $ref: "#/components/schemas/ExtensionOpaqueRequest" description: Optional extension-specific PUT body. The gateway accepts any content type up to 10 MB and forwards it as base64. responses: "200": description: Runner response relayed by the gateway. The actual status can vary by extension contract. content: application/json: schema: $ref: "#/components/schemas/ExtensionOpaqueResponse" "204": description: Runner returned no content, or CORS preflight for OPTIONS requests on this gateway path. "404": description: Extension is not installed or not enabled for the resolved tenant. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "413": description: Request body exceeds the 10 MB gateway limit. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "500": description: Tenant could not be resolved or another internal gateway error occurred. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "502": description: Runner call failed, runner response was empty/invalid, or install context was incomplete. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" patch: summary: Forward PATCH request to extension runner description: Tenant-scoped extension gateway endpoint that forwards PATCH requests to an installed extension runner. The gateway resolves the tenant from x-alga-tenant, x-tenant-id, session cookie, or DEV_TENANT_ID in development; verifies the extension is installed and enabled for that tenant; forwards selected headers, query parameters, and an optional opaque body to RUNNER_BASE_URL /v1/execute; and relays the runner response. For PATCH requests the body is limited to 10 MB, base64-encoded, and forwarded as http.body_b64. Clients should provide x-idempotency-key for safe retries; otherwise the gateway falls back to a generated request ID. The gateway does not interpret PATCH semantics; partial-update behavior is extension-defined. tags: - Extension Gateway security: - SessionCookieAuth: [] extensions: x-api-key-auth-skipped: true x-proxy-target: extension-runner x-max-body-bytes: 10485760 x-idempotency-supported: true x-idempotency-key-header: x-idempotency-key x-idempotency-fallback: x-request-id x-alga-products: - psa parameters: - schema: type: string minLength: 1 description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. required: true description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. name: extensionId in: path - schema: type: string description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. required: false description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. name: path in: path - schema: type: string format: uuid description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. required: false description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. name: x-request-id in: header - schema: type: string description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. required: false description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. name: x-idempotency-key in: header - schema: type: string description: Internal tenant header used for tenant resolution before session fallback. required: false description: Internal tenant header used for tenant resolution before session fallback. name: x-alga-tenant in: header - schema: type: string description: Legacy tenant header accepted for tenant resolution before session fallback. required: false description: Legacy tenant header accepted for tenant resolution before session fallback. name: x-tenant-id in: header requestBody: description: Optional extension-specific PATCH body. The gateway accepts any content type up to 10 MB and forwards it as base64. required: false content: application/json: schema: $ref: "#/components/schemas/ExtensionOpaqueRequest" description: Optional extension-specific PATCH body. The gateway accepts any content type up to 10 MB and forwards it as base64. responses: "200": description: Runner response relayed by the gateway. The actual status can vary by extension contract. content: application/json: schema: $ref: "#/components/schemas/ExtensionOpaqueResponse" "204": description: Runner returned no content, or CORS preflight for OPTIONS requests on this gateway path. "404": description: Extension is not installed or not enabled for the resolved tenant. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "413": description: Request body exceeds the 10 MB gateway limit. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "500": description: Tenant could not be resolved or another internal gateway error occurred. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "502": description: Runner call failed, runner response was empty/invalid, or install context was incomplete. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" delete: summary: Forward DELETE request to extension runner description: Tenant-scoped extension gateway endpoint that forwards DELETE requests to an installed extension runner. The gateway resolves the tenant from x-alga-tenant, x-tenant-id, session cookie, or DEV_TENANT_ID in development; verifies the extension is installed and enabled for that tenant; forwards selected headers, query parameters, and an optional opaque body to RUNNER_BASE_URL /v1/execute; and relays the runner response. For DELETE requests the body, if present, is limited to 10 MB, base64-encoded, and forwarded as http.body_b64. The gateway currently has a placeholder access check and does not enforce per-extension RBAC beyond tenant install resolution. tags: - Extension Gateway security: - SessionCookieAuth: [] extensions: x-api-key-auth-skipped: true x-proxy-target: extension-runner x-max-body-bytes: 10485760 x-idempotency-supported: true x-idempotency-key-header: x-idempotency-key x-idempotency-fallback: x-request-id x-alga-products: - psa parameters: - schema: type: string minLength: 1 description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. required: true description: Extension identifier from the URL. This may be a registry/install UUID or a publisher.name slug, resolved case-insensitively. name: extensionId in: path - schema: type: string description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. required: false description: Remaining extension endpoint path after extensionId. The gateway forwards this path to the runner unchanged. name: path in: path - schema: type: string format: uuid description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. required: false description: Optional request ID. The gateway generates a UUID when absent and forwards it to the runner. name: x-request-id in: header - schema: type: string description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. required: false description: Optional idempotency key for non-GET methods. The gateway falls back to x-request-id when absent and forwards the key to the runner. name: x-idempotency-key in: header - schema: type: string description: Internal tenant header used for tenant resolution before session fallback. required: false description: Internal tenant header used for tenant resolution before session fallback. name: x-alga-tenant in: header - schema: type: string description: Legacy tenant header accepted for tenant resolution before session fallback. required: false description: Legacy tenant header accepted for tenant resolution before session fallback. name: x-tenant-id in: header requestBody: description: Optional extension-specific DELETE body. The gateway accepts any content type up to 10 MB and forwards it as base64. required: false content: application/json: schema: $ref: "#/components/schemas/ExtensionOpaqueRequest" description: Optional extension-specific DELETE body. The gateway accepts any content type up to 10 MB and forwards it as base64. responses: "200": description: Runner response relayed by the gateway. The actual status can vary by extension contract. content: application/json: schema: $ref: "#/components/schemas/ExtensionOpaqueResponse" "204": description: Runner returned no content, or CORS preflight for OPTIONS requests on this gateway path. "404": description: Extension is not installed or not enabled for the resolved tenant. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "413": description: Request body exceeds the 10 MB gateway limit. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "500": description: Tenant could not be resolved or another internal gateway error occurred. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" "502": description: Runner call failed, runner response was empty/invalid, or install context was incomplete. content: application/json: schema: $ref: "#/components/schemas/ExtensionGatewayErrorResponse" options: summary: OPTIONS ext description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/billing-analytics/overview: get: summary: Get billing overview analytics description: Maps to ApiContractLineController.getBillingOverviewAnalytics() and returns tenant billing overview analytics. Authenticated and tenant-scoped via withApiKeyRouteAuth (req.context is populated before the handler runs). tags: - Billing Analytics security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-source: middleware API-key presence check only x-request-context-required: true x-request-context-wiring-gap: true x-alga-products: - psa responses: "200": description: Billing analytics payload returned. content: application/json: schema: $ref: "#/components/schemas/BillingOverviewResponse" "500": description: Request context missing or other server failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/billing/calculate: post: summary: Calculate client billing charges description: Calculates billing for one client and billing window using FinancialService.calculateBilling(). Requires financial:read permission. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialCalculateBillingBody" responses: "200": description: Billing calculation returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid billing calculation payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected billing calculation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/billing/payment-terms: get: summary: List billing payment terms description: Returns payment terms from FinancialService.getPaymentTerms(). tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa responses: "200": description: Payment terms returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected payment terms failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/bulk/invoices: post: summary: Run bulk invoice operation description: FinancialService.bulkInvoiceOperation() supports send/finalize/cancel/mark_paid operations. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: update x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialBulkInvoiceOperationBody" responses: "200": description: Bulk operation processed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid bulk operation payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected bulk operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/bulk/transactions: post: summary: Run bulk transaction operation description: FinancialService.bulkTransactionOperation() applies approve/reject/reverse to existing transactions (1–100 ids). reverse posts a compensating transaction linked to the original via related_transaction_id, recomputes the running balance, and syncs the client credit balance for credit-type transactions. Returns per-id results { total_requested, successful, failed, results[] }. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: update x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialBulkTransactionOperationBody" responses: "200": description: Bulk operation processed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid bulk operation payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected bulk operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/bulk/credits: post: summary: Run bulk credit operation description: FinancialService.bulkCreditOperation() applies expire/extend_expiration/transfer to existing credits (1–100 ids). expire forfeits the remaining amount via a credit_expiration transaction and reduces the client balance; extend_expiration sets a new expiration_date; transfer moves the remaining amount to parameters.target_client_id. Returns per-id results { total_requested, successful, failed, results[] }. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: update x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialBulkCreditOperationBody" responses: "200": description: Bulk operation processed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid bulk operation payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected bulk operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/credits: get: summary: List credit balances and records description: Lists credits with filters using FinancialService.listClientCredits(). tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a80 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: created_from in: query - schema: type: string required: false name: created_to in: query - schema: type: string required: false name: updated_from in: query - schema: type: string required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: invoice_id in: query - schema: type: string required: false name: type in: query - schema: type: string required: false name: status in: query - schema: type: string required: false name: amount_min in: query - schema: type: string required: false name: amount_max in: query - schema: type: string enum: *a81 required: false name: include_expired in: query - schema: type: string enum: *a82 required: false name: expiring_soon in: query - schema: type: string enum: *a83 required: false name: has_remaining in: query - schema: type: string enum: *a84 required: false name: has_expiration in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query - schema: type: string enum: *a85 required: false name: group_by in: query - schema: type: string enum: *a86 required: false name: include_projections in: query - schema: type: string required: false name: as_of_date in: query responses: "200": description: Paginated credit records returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiPaginated" "400": description: Invalid credit query parameters. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected credit listing failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/credits/apply: post: summary: Apply credit to invoice description: Applies client credit to an invoice via FinancialService.applyCreditToInvoice(). tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: update x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialApplyCreditToInvoiceBody" responses: "200": description: Credit operation completed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Credit operation created a new record. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected credit operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/credits/prepayment: post: summary: Create prepayment invoice description: Creates a prepayment invoice and corresponding credit allocation. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: create x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialPrepaymentInvoiceBody" responses: "200": description: Credit operation completed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Credit operation created a new record. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:create permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected credit operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/credits/transfer: post: summary: Transfer credit between clients description: Transfers credit between clients via FinancialService.transferCredit(). tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: transfer x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialTransferCreditBody" responses: "200": description: Credit operation completed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Credit operation created a new record. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:transfer permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected credit operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/credits/validate: post: summary: Validate client credit balance description: Validates whether a client has sufficient usable credit. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialValidateCreditBody" responses: "200": description: Credit operation completed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Credit operation created a new record. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected credit operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/invoices: get: summary: List financial invoices (transaction list wiring) description: Route file maps to ApiFinancialController.list(), which is transaction-oriented (resource financial/transactions) rather than invoice-specific list logic. Current response is the generic transaction list envelope with financial report links. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-route-to-controller-mismatch: true x-controller-method: ApiFinancialController.list() x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a80 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: created_from in: query - schema: type: string required: false name: created_to in: query - schema: type: string required: false name: updated_from in: query - schema: type: string required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: invoice_id in: query - schema: type: string required: false name: type in: query - schema: type: string required: false name: status in: query - schema: type: string required: false name: amount_min in: query - schema: type: string required: false name: amount_max in: query - schema: type: string enum: *a81 required: false name: include_expired in: query - schema: type: string enum: *a82 required: false name: expiring_soon in: query - schema: type: string enum: *a83 required: false name: has_remaining in: query - schema: type: string enum: *a84 required: false name: has_expiration in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query - schema: type: string enum: *a85 required: false name: group_by in: query - schema: type: string enum: *a86 required: false name: include_projections in: query - schema: type: string required: false name: as_of_date in: query responses: "200": description: Paginated financial list returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiPaginated" "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected listing failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/invoices/{id}/finalize: post: summary: Finalize financial invoice (maps to generic update) description: Despite route naming, the handler calls ApiFinancialController.update() which performs generic financial update validation and update semantics. Path id is extracted as financial resource id and processed by FinancialService.update(). tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: update x-route-to-controller-mismatch: true x-controller-method: ApiFinancialController.update() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialUpdateTransactionBody" responses: "200": description: Financial resource updated. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid id or payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Financial resource not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected update failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/invoices/{id}/items: post: summary: Add financial invoice item (maps to generic create) description: Route maps to ApiFinancialController.create(), which validates createTransactionSchema and creates a financial transaction. The path {id} is not consumed by create(). tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: create x-route-to-controller-mismatch: true x-controller-method: ApiFinancialController.create() x-path-param-currently-unused: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialCreateTransactionBody" responses: "201": description: Financial transaction created. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:create permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected create failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/payment-methods: get: summary: List payment methods (transaction list wiring) description: Current route wiring calls ApiFinancialController.list(), which lists transaction records and not payment methods. This discrepancy is documented as implementation behavior. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-route-to-controller-mismatch: true x-controller-method: ApiFinancialController.list() x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a80 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: created_from in: query - schema: type: string required: false name: created_to in: query - schema: type: string required: false name: updated_from in: query - schema: type: string required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: invoice_id in: query - schema: type: string required: false name: type in: query - schema: type: string required: false name: status in: query - schema: type: string required: false name: amount_min in: query - schema: type: string required: false name: amount_max in: query - schema: type: string enum: *a81 required: false name: include_expired in: query - schema: type: string enum: *a82 required: false name: expiring_soon in: query - schema: type: string enum: *a83 required: false name: has_remaining in: query - schema: type: string enum: *a84 required: false name: has_expiration in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query - schema: type: string enum: *a85 required: false name: group_by in: query - schema: type: string enum: *a86 required: false name: include_projections in: query - schema: type: string required: false name: as_of_date in: query responses: "200": description: Paginated list returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiPaginated" "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected list failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" post: summary: Create payment method description: Creates a payment method using FinancialService.createPaymentMethod(). tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: create x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialCreatePaymentMethodBody" responses: "201": description: Payment method created. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:create permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected payment method creation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/payment-methods/{id}: get: summary: Get payment method by id (transaction get wiring) description: Route maps to ApiFinancialController.getById(), which fetches a financial transaction by id. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-route-to-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "204": description: Resource deleted. "400": description: Invalid id or request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Resource not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" put: summary: Update payment method by id (transaction update wiring) description: Route maps to ApiFinancialController.update(), which updates generic financial resource fields. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: update x-route-to-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialUpdateTransactionBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "204": description: Resource deleted. "400": description: Invalid id or request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Resource not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" delete: summary: Delete payment method by id (transaction delete wiring) description: Route maps to ApiFinancialController.delete(), deleting a generic financial resource by id. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: delete x-route-to-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "204": description: Resource deleted. "400": description: Invalid id or request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:delete permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Resource not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/reconciliation/run: post: summary: Run financial reconciliation description: Triggers FinancialService.runCreditReconciliation(). Optional client_id query narrows reconciliation target. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: update x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a80 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: created_from in: query - schema: type: string required: false name: created_to in: query - schema: type: string required: false name: updated_from in: query - schema: type: string required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: invoice_id in: query - schema: type: string required: false name: type in: query - schema: type: string required: false name: status in: query - schema: type: string required: false name: amount_min in: query - schema: type: string required: false name: amount_max in: query - schema: type: string enum: *a81 required: false name: include_expired in: query - schema: type: string enum: *a82 required: false name: expiring_soon in: query - schema: type: string enum: *a83 required: false name: has_remaining in: query - schema: type: string enum: *a84 required: false name: has_expiration in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query - schema: type: string enum: *a85 required: false name: group_by in: query - schema: type: string enum: *a86 required: false name: include_projections in: query - schema: type: string required: false name: as_of_date in: query responses: "200": description: Reconciliation run completed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected reconciliation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/reconciliation/{id}/resolve: post: summary: Resolve reconciliation report description: Resolves one reconciliation report by id with optional operator notes. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: update x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialReconciliationResolveBody" responses: "200": description: Reconciliation report resolved. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid id or payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Reconciliation report not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected resolution failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/reports/aging: get: summary: Get aging report description: Returns aging buckets and summary for tenant-wide receivables or one client. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a80 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: created_from in: query - schema: type: string required: false name: created_to in: query - schema: type: string required: false name: updated_from in: query - schema: type: string required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: invoice_id in: query - schema: type: string required: false name: type in: query - schema: type: string required: false name: status in: query - schema: type: string required: false name: amount_min in: query - schema: type: string required: false name: amount_max in: query - schema: type: string enum: *a81 required: false name: include_expired in: query - schema: type: string enum: *a82 required: false name: expiring_soon in: query - schema: type: string enum: *a83 required: false name: has_remaining in: query - schema: type: string enum: *a84 required: false name: has_expiration in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query - schema: type: string enum: *a85 required: false name: group_by in: query - schema: type: string enum: *a86 required: false name: include_projections in: query - schema: type: string required: false name: as_of_date in: query responses: "200": description: Report returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid report query parameters. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected report failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/reports/analytics: get: summary: Get financial analytics description: Returns aggregate financial analytics for a date range. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a80 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: created_from in: query - schema: type: string required: false name: created_to in: query - schema: type: string required: false name: updated_from in: query - schema: type: string required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: invoice_id in: query - schema: type: string required: false name: type in: query - schema: type: string required: false name: status in: query - schema: type: string required: false name: amount_min in: query - schema: type: string required: false name: amount_max in: query - schema: type: string enum: *a81 required: false name: include_expired in: query - schema: type: string enum: *a82 required: false name: expiring_soon in: query - schema: type: string enum: *a83 required: false name: has_remaining in: query - schema: type: string enum: *a84 required: false name: has_expiration in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query - schema: type: string enum: *a85 required: false name: group_by in: query - schema: type: string enum: *a86 required: false name: include_projections in: query - schema: type: string required: false name: as_of_date in: query responses: "200": description: Report returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid report query parameters. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected report failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/reports/balance: get: summary: Get account balance report description: Returns balance summary for one client_id (required by controller). tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a80 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: created_from in: query - schema: type: string required: false name: created_to in: query - schema: type: string required: false name: updated_from in: query - schema: type: string required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: invoice_id in: query - schema: type: string required: false name: type in: query - schema: type: string required: false name: status in: query - schema: type: string required: false name: amount_min in: query - schema: type: string required: false name: amount_max in: query - schema: type: string enum: *a81 required: false name: include_expired in: query - schema: type: string enum: *a82 required: false name: expiring_soon in: query - schema: type: string enum: *a83 required: false name: has_remaining in: query - schema: type: string enum: *a84 required: false name: has_expiration in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query - schema: type: string enum: *a85 required: false name: group_by in: query - schema: type: string enum: *a86 required: false name: include_projections in: query - schema: type: string required: false name: as_of_date in: query responses: "200": description: Report returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid report query parameters. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected report failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/tax/calculate: post: summary: Calculate financial tax description: Calculates tax for a client/amount/tax_region tuple. Requires financial:read permission in current controller implementation. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialCalculateTaxBody" responses: "200": description: Tax calculation returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid tax request payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected tax calculation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/tax/rates: get: summary: List financial tax rates (transaction list wiring) description: Route file currently maps to ApiFinancialController.list(), so the response is the generic financial transaction list rather than a tax-rate list. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-route-to-controller-mismatch: true x-controller-method: ApiFinancialController.list() x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a80 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: created_from in: query - schema: type: string required: false name: created_to in: query - schema: type: string required: false name: updated_from in: query - schema: type: string required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: invoice_id in: query - schema: type: string required: false name: type in: query - schema: type: string required: false name: status in: query - schema: type: string required: false name: amount_min in: query - schema: type: string required: false name: amount_max in: query - schema: type: string enum: *a81 required: false name: include_expired in: query - schema: type: string enum: *a82 required: false name: expiring_soon in: query - schema: type: string enum: *a83 required: false name: has_remaining in: query - schema: type: string enum: *a84 required: false name: has_expiration in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query - schema: type: string enum: *a85 required: false name: group_by in: query - schema: type: string enum: *a86 required: false name: include_projections in: query - schema: type: string required: false name: as_of_date in: query responses: "200": description: Paginated list returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiPaginated" "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected list failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/transactions: get: summary: List financial transactions description: Lists transactions with advanced filtering. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a80 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: created_from in: query - schema: type: string required: false name: created_to in: query - schema: type: string required: false name: updated_from in: query - schema: type: string required: false name: updated_to in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: invoice_id in: query - schema: type: string required: false name: type in: query - schema: type: string required: false name: status in: query - schema: type: string required: false name: amount_min in: query - schema: type: string required: false name: amount_max in: query - schema: type: string enum: *a81 required: false name: include_expired in: query - schema: type: string enum: *a82 required: false name: expiring_soon in: query - schema: type: string enum: *a83 required: false name: has_remaining in: query - schema: type: string enum: *a84 required: false name: has_expiration in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query - schema: type: string enum: *a85 required: false name: group_by in: query - schema: type: string enum: *a86 required: false name: include_projections in: query - schema: type: string required: false name: as_of_date in: query responses: "200": description: Paginated transactions returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiPaginated" "400": description: Invalid transaction query parameters. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected transaction listing failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" post: summary: Create financial transaction description: Creates one financial transaction. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: create x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialCreateTransactionBody" responses: "201": description: Transaction created. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid transaction payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:create permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected transaction creation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial/transactions/{id}: get: summary: Get financial transaction by id description: Loads one financial transaction by id. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "200": description: Transaction returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid transaction id format. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Transaction not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected transaction retrieval failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" put: summary: Update financial transaction description: Updates one transaction id with partial payload. tags: - Financial security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: financial x-rbac-action: update x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FinancialUpdateTransactionBody" responses: "200": description: Transaction updated. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid transaction id or payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: financial:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Transaction not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected transaction update failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices: get: summary: List invoices description: Lists invoices with pagination, filter query keys, and include flags. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a87 required: false name: order in: query - schema: type: string enum: *a88 required: false name: include_items in: query - schema: type: string enum: *a89 required: false name: include_client in: query - schema: type: string enum: *a90 required: false name: include_billing_cycle in: query - schema: type: string enum: *a91 required: false name: include_transactions in: query - schema: type: string required: false name: q in: query - schema: type: string required: false name: from in: query - schema: type: string required: false name: to in: query - schema: type: string enum: *a92 required: false name: format in: query responses: "200": description: Paginated invoices returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiPaginated" "400": description: Invalid list query parameters. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice list failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" post: summary: Create invoice description: Creates an invoice record via ApiBaseController.create() and invoice create schema. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: create x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceCreateBody" responses: "201": description: Invoice created. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid invoice payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:create permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice creation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/analytics: get: summary: Get invoice analytics description: Returns aggregate analytics for invoice states and amounts over optional from/to range. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: analytics x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a87 required: false name: order in: query - schema: type: string enum: *a88 required: false name: include_items in: query - schema: type: string enum: *a89 required: false name: include_client in: query - schema: type: string enum: *a90 required: false name: include_billing_cycle in: query - schema: type: string enum: *a91 required: false name: include_transactions in: query - schema: type: string required: false name: q in: query - schema: type: string required: false name: from in: query - schema: type: string required: false name: to in: query - schema: type: string enum: *a92 required: false name: format in: query responses: "200": description: Invoice analytics returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:analytics permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected analytics failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/bulk: post: summary: Bulk update invoice status description: Bulk status transition route using bulkInvoiceStatusUpdateSchema. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: bulk_update x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceBulkStatusBody" responses: "200": description: Bulk status update completed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid bulk status payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:bulk_update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected bulk status failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/bulk/credit: post: summary: Bulk apply invoice credits description: Applies the same credit amount to each listed invoice; response includes successes and per-invoice errors. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: bulk_credit x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceBulkCreditBody" responses: "200": description: Bulk credit operation completed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid bulk credit payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:bulk_credit permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected bulk credit failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/bulk/delete: post: summary: Bulk delete invoices description: Deletes multiple invoice records in one request. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: bulk_delete x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceBulkDeleteBody" responses: "200": description: Bulk delete completed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid bulk delete payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:bulk_delete permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected bulk delete failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/bulk/send: post: summary: Bulk send invoices description: Enqueues or executes invoice send for multiple invoice IDs. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: bulk_send x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceBulkSendBody" responses: "200": description: Bulk send completed. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid bulk send payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:bulk_send permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected bulk send failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/export: get: summary: Export invoices description: Exports invoice data. format=csv returns text/csv attachment; default is JSON success envelope. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: read x-alt-response-content-type: text/csv x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a87 required: false name: order in: query - schema: type: string enum: *a88 required: false name: include_items in: query - schema: type: string enum: *a89 required: false name: include_client in: query - schema: type: string enum: *a90 required: false name: include_billing_cycle in: query - schema: type: string enum: *a91 required: false name: include_transactions in: query - schema: type: string required: false name: q in: query - schema: type: string required: false name: from in: query - schema: type: string required: false name: to in: query - schema: type: string enum: *a92 required: false name: format in: query responses: "200": description: Invoice export returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected export failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/generate: post: summary: Generate recurring invoice description: Generates one recurring invoice using canonical selector_input payload. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: create x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceSelectorBody" responses: "201": description: Invoice generated. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid selector payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:create permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected generation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/manual: post: summary: Create manual invoice description: Creates a manual invoice using clientId + items payload. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: create x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceManualBody" responses: "201": description: Manual invoice created. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid manual invoice payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:create permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected manual invoice failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/preview: post: summary: Preview recurring invoice description: Previews invoice output for selector_input payload without committing final invoice state. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: read x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceSelectorBody" responses: "200": description: Invoice preview returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid selector payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected preview failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/recurring: get: summary: List recurring invoice templates description: Current implementation returns an empty list placeholder (TODO in ApiInvoiceController.listRecurringTemplates). tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: recurring x-implementation-gap: Returns [] placeholder. x-alga-products: - psa responses: "200": description: Recurring template list returned (currently empty). content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:recurring permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected recurring template list failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" post: summary: Create recurring invoice template description: Creates a recurring template used for scheduled invoice generation. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: recurring x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceRecurringCreateBody" responses: "201": description: Recurring template created. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid recurring template payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:recurring permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected recurring template creation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/recurring/{id}: put: summary: Update recurring invoice template description: Current implementation echoes payload and id without persistence (TODO in ApiInvoiceController.updateRecurringTemplate). tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: recurring x-implementation-gap: Update is TODO; response is synthetic. x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceRecurringCreateBody" responses: "200": description: Recurring template update response returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid id or payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:recurring permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected recurring template update failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" delete: summary: Delete recurring invoice template description: Current implementation is TODO and returns 204 without delete persistence. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: recurring x-implementation-gap: Delete is TODO; returns 204 directly. x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "204": description: Recurring template deleted (current TODO stub response). "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:recurring permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected recurring template delete failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/search: get: summary: Search invoices description: Searches invoices by free-text q with paginated response. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a87 required: false name: order in: query - schema: type: string enum: *a88 required: false name: include_items in: query - schema: type: string enum: *a89 required: false name: include_client in: query - schema: type: string enum: *a90 required: false name: include_billing_cycle in: query - schema: type: string enum: *a91 required: false name: include_transactions in: query - schema: type: string required: false name: q in: query - schema: type: string required: false name: from in: query - schema: type: string required: false name: to in: query - schema: type: string enum: *a92 required: false name: format in: query responses: "200": description: Search results returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiPaginated" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected search failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}: get: summary: Get invoice by id description: Returns one invoice with optional include flags. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a87 required: false name: order in: query - schema: type: string enum: *a88 required: false name: include_items in: query - schema: type: string enum: *a89 required: false name: include_client in: query - schema: type: string enum: *a90 required: false name: include_billing_cycle in: query - schema: type: string enum: *a91 required: false name: include_transactions in: query - schema: type: string required: false name: q in: query - schema: type: string required: false name: from in: query - schema: type: string required: false name: to in: query - schema: type: string enum: *a92 required: false name: format in: query responses: "200": description: Invoice operation succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid id or payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" put: summary: Update invoice description: Updates an invoice using ApiBaseController.update(). tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: update x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceUpdateBody" responses: "200": description: Invoice operation succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid id or payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:update permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" delete: summary: Delete invoice description: Deletes one invoice using ApiBaseController.delete(). tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: delete x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "204": description: Invoice deleted. "400": description: Invalid id or payload. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:delete permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice operation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/approve: post: summary: Approve invoice description: Approves one invoice; optional execution_id query is forwarded to workflow context. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: approve x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path - schema: type: string required: false name: execution_id in: query - schema: type: string required: false name: reason in: query responses: "200": description: Invoice action succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Invoice action created a new invoice resource. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload or query. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:approve permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice action failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/credit: post: summary: Apply credit to invoice description: Applies credit amount to one invoice. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: credit x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceCreditBody" responses: "200": description: Invoice action succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Invoice action created a new invoice resource. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload or query. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:credit permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice action failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/duplicate: post: summary: Duplicate invoice description: Clones an invoice into a new draft/manual invoice. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: create x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "200": description: Invoice action succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Invoice action created a new invoice resource. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload or query. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:create permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice action failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/finalize: post: summary: Finalize invoice description: Finalizes one invoice. invoice_id is path-derived and merged into finalize schema. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: finalize x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceFinalizeBody" responses: "200": description: Invoice action succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Invoice action created a new invoice resource. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload or query. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:finalize permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice action failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/payment: post: summary: Record invoice payment description: Records payment for one invoice. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: payment x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoicePaymentBody" responses: "200": description: Invoice action succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Invoice action created a new invoice resource. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload or query. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:payment permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice action failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/reject: post: summary: Reject invoice description: Rejects one invoice. Optional reason/execution_id come from query string. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: reject x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path - schema: type: string required: false name: execution_id in: query - schema: type: string required: false name: reason in: query responses: "200": description: Invoice action succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Invoice action created a new invoice resource. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload or query. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:reject permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice action failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/send: post: summary: Send invoice description: Sends one invoice to provided recipient addresses. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: send x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceSendBody" responses: "200": description: Invoice action succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Invoice action created a new invoice resource. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload or query. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:send permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice action failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/tax: post: summary: Calculate invoice tax description: Calculates tax for invoice context; uses billing permission gate. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InvoiceTaxBody" responses: "200": description: Invoice action succeeded. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "201": description: Invoice action created a new invoice resource. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid request payload or query. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:billing permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected invoice action failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/items: get: summary: List invoice items description: Returns invoice_charges array for one invoice id. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "200": description: Invoice item list returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid invoice id. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected list-items failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/transactions: get: summary: List invoice transactions description: Returns transactions array for one invoice id. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "200": description: Invoice transactions returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid invoice id. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:read permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected list-transactions failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/invoices/{id}/pdf: post: summary: Generate invoice PDF asset description: Generates/refreshes invoice PDF metadata and returns file_id plus optional download_url. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: pdf x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "200": description: PDF generation metadata returned. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiSuccess" "400": description: Invalid invoice id. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:pdf permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected PDF generation failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" get: summary: Redirect to invoice PDF download description: Attempts to generate/load PDF metadata and redirects to download_url when present. tags: - Invoices security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key header validated in ApiBaseController.authenticate() x-tenant-header: x-tenant-id (optional; otherwise tenant inferred from key) x-rbac-resource: invoice x-rbac-action: pdf x-redirect-response: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). required: true description: Path UUID parameter resolved by ApiBaseController.extractIdFromPath(). name: id in: path responses: "307": description: Redirect to generated PDF URL. "400": description: Invalid invoice id. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "403": description: invoice:pdf permission denied. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: PDF URL unavailable or invoice not found. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "500": description: Unexpected PDF download failure. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/financial: get: summary: Financial API namespace root description: "Namespace root with no resource of its own — it returns 404. Use the financial sub-resources instead: /api/v1/financial/invoices, /api/v1/financial/transactions, /api/v1/financial/credits, /api/v1/financial/bulk/{invoices,transactions,credits}, and /api/v1/billing-analytics/overview." tags: - Financial security: - ApiKeyAuth: [] extensions: x-namespace-root: true x-alga-products: - psa responses: "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" "404": description: Always — this root has no resource; call a sub-resource path. content: application/json: schema: $ref: "#/components/schemas/FinancialInvoiceApiError" /api/v1/kb-articles: get: summary: List knowledge base articles description: Returns a paginated list of KB articles for the tenant, with optional status, audience, article_type, category_id, and free-text search filters. Each row includes the joined document name. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: integer minimum: 1 required: false name: page in: query - schema: type: integer minimum: 1 maximum: 100 required: false name: limit in: query - schema: type: string enum: *a17 required: false name: status in: query - schema: type: string enum: *a16 required: false name: audience in: query - schema: type: string enum: *a15 required: false name: article_type in: query - schema: type: string format: uuid required: false name: category_id in: query - schema: type: string required: false name: search in: query responses: "200": description: Paginated KB articles. content: application/json: schema: $ref: "#/components/schemas/PaginatedKbArticleResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: Create a knowledge base article description: "Creates a KB article: generates a unique slug, creates the backing document record, and optionally stores initial block content. Returns the created article." tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: create x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/KbArticleCreateRequest" responses: "201": description: Article created. content: application/json: schema: $ref: "#/components/schemas/KbArticleResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/kb-articles/categories: get: summary: List KB article categories description: Returns the standard categories available for KB articles, ordered by display order then name. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: read x-alga-products: - psa - algadesk responses: "200": description: Available categories. content: application/json: schema: $ref: "#/components/schemas/KbCategoryListResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/kb-articles/templates: get: summary: List KB article templates description: Returns KB article templates for the tenant, optionally filtered by the article_type query parameter, ordered by name. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string enum: *a15 required: false name: article_type in: query responses: "200": description: Available templates. content: application/json: schema: $ref: "#/components/schemas/KbTemplateListResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/kb-articles/from-ticket/{ticketId}: post: summary: Create a KB article from a ticket description: Creates a troubleshooting KB article (audience internal) from an existing ticket, seeding the body with the ticket title/description as a "Problem" section and the resolution as a "Resolution" section. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: create x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Source ticket UUID. required: true description: Source ticket UUID. name: ticketId in: path responses: "201": description: Article created from the ticket. content: application/json: schema: $ref: "#/components/schemas/KbArticleResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Ticket not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/kb-articles/{id}: get: summary: Get a knowledge base article description: Returns a single KB article by id with its metadata, joined document name, and block content. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: KB article UUID. required: true description: KB article UUID. name: id in: path responses: "200": description: The KB article. content: application/json: schema: $ref: "#/components/schemas/KbArticleResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Article not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Update a knowledge base article description: Updates article metadata (title, slug, type, audience, category, status, review cycle). Validates slug uniqueness, syncs the linked document name when the title changes, and recomputes the next review date when the review cycle changes. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: update x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: KB article UUID. required: true description: KB article UUID. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/KbArticleUpdateRequest" responses: "200": description: Updated article. content: application/json: schema: $ref: "#/components/schemas/KbArticleResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Article not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: summary: Delete a knowledge base article description: Deletes the KB article and cascades to remove the linked document and its block content. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: delete x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: KB article UUID. required: true description: KB article UUID. name: id in: path responses: "204": description: Article deleted. "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Article not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/kb-articles/{id}/archive: post: summary: Archive a knowledge base article description: Sets the article status to archived and clears client visibility on the linked document. Returns the updated article. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: update x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: KB article UUID. required: true description: KB article UUID. name: id in: path responses: "200": description: Article archived. content: application/json: schema: $ref: "#/components/schemas/KbArticleResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Article not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/kb-articles/{id}/content: get: summary: Get KB article content as text description: Returns the article body converted from its stored block (BlockNote) content into readable markdown-like text (headings, lists, code blocks, paragraphs). tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: KB article UUID. required: true description: KB article UUID. name: id in: path responses: "200": description: Rendered article content. content: application/json: schema: $ref: "#/components/schemas/KbArticleContentResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Article not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Update KB article content description: Replaces the article body. Accepts markdown or BlockNote JSON (format field), parses it into block content, and creates or updates the document block-content record. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: update x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: KB article UUID. required: true description: KB article UUID. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/KbArticleContentUpdateRequest" responses: "200": description: Content updated. content: application/json: schema: $ref: "#/components/schemas/KbArticleResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Article not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/kb-articles/{id}/publish: post: summary: Publish a knowledge base article description: Sets the article status to published, records the publish timestamp and user, and sets is_client_visible on the linked document when the audience is client or public. Returns the updated article. tags: - Knowledge Base security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: document x-rbac-action: update x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: KB article UUID. required: true description: KB article UUID. name: id in: path responses: "200": description: Article published. content: application/json: schema: $ref: "#/components/schemas/KbArticleResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required document permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Article not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/billing: get: summary: Billing API namespace root description: Namespace root with no resource of its own — it returns 404. Use /api/v1/financial/invoices, /api/v1/financial/transactions, /api/v1/financial/credits, and /api/v1/billing-analytics/overview. tags: - Billing security: - ApiKeyAuth: [] extensions: x-namespace-root: true x-alga-products: - psa responses: "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Always — this root has no resource; call a sub-resource path. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/comments: get: summary: Comments API namespace root description: "Namespace root with no resource of its own — it returns 404. Comments are accessed per ticket: /api/v1/tickets/{id}/comments and its sub-paths." tags: - Comments security: - ApiKeyAuth: [] extensions: x-namespace-root: true x-alga-products: - psa - algadesk responses: "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Always — this root has no resource; call a sub-resource path. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/documents: get: summary: Documents API namespace root description: Namespace root with no resource of its own — it returns 404. Documents are accessed per parent entity, e.g. /api/v1/tickets/{id}/documents. tags: - Documents security: - ApiKeyAuth: [] extensions: x-namespace-root: true x-alga-products: - psa responses: "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Always — this root has no resource; call a sub-resource path. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/email: get: summary: Email API namespace root description: Namespace root with no resource of its own — it returns 404. Use the email provider and webhook endpoints rather than this root. tags: - Email security: - ApiKeyAuth: [] extensions: x-namespace-root: true x-alga-products: - psa - algadesk responses: "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Always — this root has no resource; call a sub-resource path. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/ai/document-assist: post: summary: AI document assistance (streaming, EE) description: Streams AI-generated document edits using the tenant's configured LLM provider. Enterprise Edition feature gated by the AI add-on tier and a feature flag; authenticated with the AI_DOCUMENT_API_KEY via the x-api-key header. Returns a streamed text response (501 on Community Edition). tags: - AI security: - ApiKeyAuth: [] extensions: x-edition-feature: ee-ai x-streaming: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AiDocumentAssistBody" responses: "200": description: Streamed AI edit suggestions (text/event-stream). content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "401": description: AI_DOCUMENT_API_KEY missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: AI add-on/feature flag not enabled. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "501": description: Not available on Community Edition. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/software/search: get: summary: Search software across the fleet description: Searches installed software across all assets in the tenant, with filters for name/publisher search, category, software_type, is_managed, is_security_relevant, and client_id. Paginated. Authenticated by the global x-api-key middleware and tenant-scoped by the underlying withAuth action (it calls the searchSoftwareFleetWide server action directly rather than using a route-level controller wrapper). tags: - Software security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-via: middleware-apikey+withAuth-action x-alga-products: - psa parameters: - schema: type: string required: false name: search in: query - schema: type: string required: false name: category in: query - schema: type: string required: false name: software_type in: query - schema: type: string enum: *a93 required: false name: is_managed in: query - schema: type: string enum: *a94 required: false name: is_security_relevant in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: integer minimum: 1 required: false name: page in: query - schema: type: integer minimum: 1 maximum: 200 required: false name: limit in: query responses: "200": description: Matching software, paginated. content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/priorities: get: summary: List priorities description: Lists ticket priorities for the tenant with pagination and sorting. tags: - Priorities security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: integer minimum: 1 required: false name: page in: query - schema: type: integer minimum: 1 maximum: 100 required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a95 required: false name: order in: query responses: "200": description: Priorities. content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/priorities/{id}: get: summary: Get a priority description: Returns a single priority by id. tags: - Priorities security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid required: true name: id in: path responses: "200": description: The priority. content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Priority not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/extensions/install: post: summary: Install an extension (EE) description: Installs a tenant extension. Enterprise Edition feature requiring the extensions capability and the psa product; returns 501 on Community Edition. tags: - Extensions security: - ApiKeyAuth: [] extensions: x-edition-feature: ee-extensions x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ExtensionActionBody" responses: "200": description: Extension install accepted. content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Extensions capability/product not available. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "501": description: Not available on Community Edition. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/extensions/uninstall: post: summary: Uninstall an extension (EE) description: Uninstalls a tenant extension. Enterprise Edition feature requiring the extensions capability and the psa product; returns 501 on Community Edition. tags: - Extensions security: - ApiKeyAuth: [] extensions: x-edition-feature: ee-extensions x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ExtensionActionBody" responses: "200": description: Extension uninstall accepted. content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Extensions capability/product not available. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "501": description: Not available on Community Edition. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/company-contract-lines: get: summary: List company contract lines (deprecated) description: "Lists client contract lines (contract_lines joined to client contracts), with filters and pagination. Deprecated: use /api/v1/client-contract-lines. This path is an alias kept for backwards compatibility." tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-deprecated: true x-replaced-by: /api/v1/client-contract-lines x-alga-products: - psa parameters: - schema: type: integer minimum: 1 required: false name: page in: query - schema: type: integer minimum: 1 maximum: 100 required: false name: limit in: query - schema: type: string format: uuid required: false name: client_id in: query - schema: type: string format: uuid required: false name: contract_line_id in: query responses: "200": description: Client contract lines. content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: Assign contract line to client (deprecated) description: "Assigns a contract line to a client by cloning a template line into the client contract. Deprecated: use /api/v1/client-contract-lines. This path is an alias kept for backwards compatibility." tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-deprecated: true x-replaced-by: /api/v1/client-contract-lines x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CompanyContractLineBody" responses: "201": description: Assignment created. content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/company-contract-lines/{id}: delete: summary: Unassign contract line (deprecated) description: "Deactivates a client-owned contract line by id. Deprecated: use /api/v1/client-contract-lines. This path is an alias kept for backwards compatibility." tags: - Contract Lines security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-deprecated: true x-replaced-by: /api/v1/client-contract-lines x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: id in: path responses: "204": description: Unassigned. "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/accounting-exports/xero-csv/client-export: get: summary: Export clients as Xero Contacts CSV description: Generates a Xero Contacts import CSV from the tenant clients (optionally limited to clientIds). Returns a CSV file. Requires billing:manage. tags: - Accounting Exports security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: billing x-rbac-action: manage x-response-content-type: text/csv x-alga-products: - psa parameters: - schema: type: string description: Comma-separated client UUIDs to limit the export. required: false description: Comma-separated client UUIDs to limit the export. name: clientIds in: query responses: "200": description: CSV file (text/csv attachment). content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/accounting-exports/xero-csv/client-import: post: summary: Import Xero Contacts CSV description: Ingests a Xero Contacts CSV and matches/creates/updates clients. Accepts multipart file, JSON csvContent, or raw CSV. Supports preview mode and createNew/updateExisting/matchBy options. Requires billing:manage. tags: - Accounting Exports security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: billing x-rbac-action: manage x-request-content-type: multipart/form-data or application/json or text/csv x-alga-products: - psa parameters: - schema: type: string enum: *a96 required: false name: preview in: query - schema: type: string enum: *a97 required: false name: createNew in: query - schema: type: string enum: *a98 required: false name: updateExisting in: query - schema: type: string required: false name: matchBy in: query responses: "200": description: Import preview or result. content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/accounting-exports/xero-csv/tax-import: post: summary: Import Xero invoice tax CSV description: Ingests a Xero Invoice Details Report CSV, extracts per-invoice tax amounts, and updates the matching Alga invoices. Accepts multipart file, JSON csvContent, or raw CSV; supports preview mode. Requires billing:manage. tags: - Accounting Exports security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: billing x-rbac-action: manage x-request-content-type: multipart/form-data or application/json or text/csv x-alga-products: - psa parameters: - schema: type: string enum: *a99 required: false name: preview in: query responses: "200": description: Import preview or result. content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/accounting-exports/{batchId}/download: get: summary: Download an accounting export batch description: Regenerates and returns the export file (CSV/IIF) for a stored export batch using its registered adapter (xero_csv, quickbooks_desktop). Requires billing_settings:update. tags: - Accounting Exports security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: billing_settings x-rbac-action: update x-alga-products: - psa parameters: - schema: type: string description: Export batch identifier. required: true description: Export batch identifier. name: batchId in: path responses: "200": description: Regenerated export file (attachment). content: application/json: schema: $ref: "#/components/schemas/PublicV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Batch not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/projects/templates: post: summary: Create project template description: Creates a project template from an existing project. tags: - Project Templates security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: project x-rbac-action: create x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ProjectTemplateCreateBody" responses: "201": description: Template created. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: List project templates description: Lists the tenant project templates. tags: - Project Templates security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: project x-rbac-action: read x-alga-products: - psa responses: "200": description: List project templates. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/projects/templates/{templateId}: patch: summary: Update project template description: Updates the template name, description, or category. tags: - Project Templates security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: project x-rbac-action: update x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: templateId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ProjectTemplateUpdateBody" responses: "200": description: Template updated. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Template not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: Get a project template description: Returns a single project template by id. tags: - Project Templates security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: project x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: templateId in: path responses: "200": description: Get a project template. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Template not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: summary: Delete a project template description: Deletes a project template by id. tags: - Project Templates security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: project x-rbac-action: delete x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: templateId in: path responses: "204": description: Template deleted. "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Template not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/projects/templates/{templateId}/apply: post: summary: Create project from template description: Creates a new project from the template, copying the selected parts (phases, statuses, tasks, etc.). tags: - Project Templates security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: project x-rbac-action: create x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: templateId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ProjectTemplateApplyBody" responses: "201": description: Project created from template. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Template not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/projects/templates/{templateId}/duplicate: post: summary: Duplicate project template description: Creates a complete copy of the template and returns the new template id. No request body. tags: - Project Templates security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: project x-rbac-action: create x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: templateId in: path responses: "201": description: Template duplicated. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Template not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-definitions: post: summary: Create workflow definition description: Creates a new workflow with a draft definition. tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: manage x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowDefinitionCreateBody" responses: "201": description: Workflow definition created. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: List workflow definitions description: Lists workflow definitions for the tenant. tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: List workflow definitions. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-definitions/import: post: summary: Import a v1 workflow bundle description: Imports a legacy v1 workflow bundle. Pass force=true (query) to overwrite an existing definition. tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: admin x-alga-products: - psa parameters: - schema: type: string enum: *a100 required: false name: force in: query requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowImportBody" responses: "201": description: Bundle imported. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-definitions/{workflowId}/metadata: put: summary: Update workflow metadata description: "Updates workflow metadata: key, visibility, pause state, concurrency limit, failure thresholds, and retention policy." tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: publish x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: workflowId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowMetadataBody" responses: "200": description: Metadata updated. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Workflow not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-definitions/{workflowId}/{version}: put: summary: Update workflow draft definition description: Replaces the draft definition for a specific version. tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: manage x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: workflowId in: path - schema: type: string description: Draft version number (coerced to a positive integer). required: true description: Draft version number (coerced to a positive integer). name: version in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowDefinitionUpdateBody" responses: "200": description: Draft updated. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Workflow/version not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: Get a workflow version description: Returns the definition document for a specific workflow version. tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: workflowId in: path - schema: type: string description: Draft version number (coerced to a positive integer). required: true description: Draft version number (coerced to a positive integer). name: version in: path responses: "200": description: Get a workflow version. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Workflow/version not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-definitions/{workflowId}/{version}/publish: post: summary: Publish a workflow version description: Publishes the draft as an active version (auto-increments when the requested version is below the next expected). An optional definition in the body overrides the stored draft. tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: publish x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: workflowId in: path - schema: type: string description: Draft version number (coerced to a positive integer). required: true description: Draft version number (coerced to a positive integer). name: version in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowPublishBody" responses: "200": description: Version published. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Workflow/version not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs: post: summary: Start a workflow run description: Starts a workflow execution with an optional version override and input payload (payload capped ~2MB; rate-limited per tenant). tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: manage x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowRunCreateBody" responses: "201": description: Run started. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: List workflow runs description: Lists workflow runs for the tenant. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: List workflow runs. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/cancel: post: summary: Cancel a workflow run description: Stops the run and marks its waits as canceled. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: admin x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowRunActionBody" responses: "200": description: Cancel a workflow run succeeded. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/replay: post: summary: Replay a workflow run description: Re-executes the workflow from the start with a new input payload. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: admin x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowRunReplayBody" responses: "200": description: Replay a workflow run succeeded. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/requeue: post: summary: Requeue a workflow run description: Re-initializes the run's event wait (for runs stuck awaiting an external event). tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: admin x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowRunActionBody" responses: "200": description: Requeue a workflow run succeeded. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/resume: post: summary: Resume a workflow run description: Resolves waiting steps and resumes a paused/waiting run. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: admin x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowRunActionBody" responses: "200": description: Resume a workflow run succeeded. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/retry: post: summary: Retry a failed workflow run description: Restarts a FAILED run from its last failed node. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: admin x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowRunActionBody" responses: "200": description: Retry a failed workflow run succeeded. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow/events: post: summary: Submit a workflow event description: Injects an event into the workflow runtime, correlating it to waiting runs by event name and correlation key. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: manage x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowEventBody" responses: "200": description: Event accepted. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: List workflow events description: Lists submitted workflow events for the tenant. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: List workflow events. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/projects/templates/categories: get: summary: List project template categories description: Lists the available project-template categories. tags: - Project Templates security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: project x-rbac-action: read x-alga-products: - psa responses: "200": description: List project template categories. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-definitions/{workflowId}/versions: get: summary: List workflow versions description: Lists the versions (draft and published) of a workflow definition. tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: workflowId in: path responses: "200": description: List workflow versions. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Workflow not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-definitions/{workflowId}/export: get: summary: Export a workflow definition description: Exports the workflow definition document (JSON). tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: workflowId in: path responses: "200": description: Export a workflow definition. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Workflow not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-definitions/{workflowId}/audit: get: summary: Get workflow audit log description: Returns the audit-log entries for a workflow definition. tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: workflowId in: path responses: "200": description: Get workflow audit log. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Workflow not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-definitions/{workflowId}/audit/export: get: summary: Export workflow audit log description: Exports the workflow definition audit log. tags: - Workflow Definitions security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid required: true name: workflowId in: path responses: "200": description: Export workflow audit log. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Workflow not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/dead-letter: get: summary: List dead-lettered runs description: Lists runs that failed terminally and were moved to the dead-letter set. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: List dead-lettered runs. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/export: get: summary: Export workflow runs description: Exports workflow runs (JSON/CSV). tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: Export workflow runs. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/latest: get: summary: Get latest workflow runs description: Returns the most recent workflow runs. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: Get latest workflow runs. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/summary: get: summary: Get workflow runs summary description: Returns aggregate run metrics across the tenant. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: Get workflow runs summary. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}: get: summary: Get a workflow run description: Returns a single workflow run by id. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path responses: "200": description: Get a workflow run. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/steps: get: summary: Get workflow run steps description: Returns the step/node states for a run. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path responses: "200": description: Get workflow run steps. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/timeline: get: summary: Get workflow run timeline description: Returns the chronological event timeline for a run. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path responses: "200": description: Get workflow run timeline. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/summary: get: summary: Get workflow run summary description: Returns a summary of a single run. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path responses: "200": description: Get workflow run summary. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/audit: get: summary: Get workflow run audit log description: Returns the audit-log entries for a run. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path responses: "200": description: Get workflow run audit log. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/audit/export: get: summary: Export workflow run audit log description: Exports the audit log for a run. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path responses: "200": description: Export workflow run audit log. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow-runs/{runId}/export: get: summary: Export a workflow run description: Exports a single workflow run (JSON). tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: true name: runId in: path responses: "200": description: Export a workflow run. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow/events/export: get: summary: Export workflow events description: Exports workflow events (JSON/CSV). tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: Export workflow events. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow/events/summary: get: summary: Get workflow events summary description: Returns aggregate workflow-event metrics. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: Get workflow events summary. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow/events/{eventId}: get: summary: Get a workflow event description: Returns a single workflow event by id. tags: - Workflow Runs security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: true name: eventId in: path responses: "200": description: Get a workflow event. content: application/json: schema: $ref: "#/components/schemas/UnversionedV1Success" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Event not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow/registry/actions: get: summary: List workflow registry actions description: Lists every action registered in the workflow runtime — the building blocks workflow definitions can invoke — including JSON Schemas for each action's input and output. Returns a bare array (no envelope). tags: - Workflow Registry security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: Registered actions. content: application/json: schema: type: array items: $ref: "#/components/schemas/WorkflowRegistryAction" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow/registry/nodes: get: summary: List workflow registry node types description: Lists the node types available to workflow definitions (triggers, control flow, action nodes, etc.) with each node's configuration JSON Schema and default retry policy. Returns a bare array (no envelope). tags: - Workflow Registry security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: Registered node types. content: application/json: schema: type: array items: $ref: "#/components/schemas/WorkflowRegistryNode" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow/registry/designer-catalog: get: summary: Get the workflow designer action catalog description: "Returns the action catalog the workflow designer renders: registry actions and integration modules grouped into tiles, filtered to the integrations actually available to the tenant. Returns a bare array of catalog records (no envelope)." tags: - Workflow Registry security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa responses: "200": description: Designer catalog tiles. content: application/json: schema: type: array items: type: object additionalProperties: {} description: Catalog tile (groupKey, tileKind, actions, UI metadata). "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/workflow/registry/schemas/{schemaRef}: get: summary: Get a workflow schema by ref description: Resolves a registered workflow schema reference (URL-encoded) to its JSON Schema document. tags: - Workflow Registry security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: workflow x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string description: Registered schema reference; URL-encode it in the path. required: true description: Registered schema reference; URL-encode it in the path. name: schemaRef in: path responses: "200": description: Resolved schema. content: application/json: schema: $ref: "#/components/schemas/WorkflowSchemaResponse" "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Unknown schema ref. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/projects: get: summary: List projects description: Lists all projects for the tenant. Returns a bare array of project records (no envelope); responds 403 with an error message when the caller lacks project read permission. tags: - Projects security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: project x-rbac-action: read x-alga-products: - psa responses: "200": description: Projects for the tenant. content: application/json: schema: type: array items: type: object additionalProperties: {} description: Project record. "400": description: Invalid request. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Caller lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/files/{fileId}/download: get: summary: Download file by ID description: Downloads a stored external file as an attachment by external_files.file_id. The route is skipped by API-key middleware and relies on session/tenant resolution through createTenantKnex and StorageService. Storage lookup is tenant-scoped to external_files.tenant and is_deleted=false, but the handler performs no explicit per-document authorization; any user resolved into the tenant can download a file by fileId. The response body is binary and Content-Type is taken from stored file metadata. tags: - Files security: - SessionCookieAuth: [] extensions: x-api-key-auth-skipped: true x-tenant-scoped-storage: true x-explicit-document-authorization: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: File UUID from external_files.file_id to download. The handler does not validate UUID syntax before querying storage metadata. required: true description: File UUID from external_files.file_id to download. The handler does not validate UUID syntax before querying storage metadata. name: fileId in: path responses: "200": description: Binary file download with attachment Content-Disposition. Content-Type varies by stored MIME type. content: application/octet-stream: schema: $ref: "#/components/schemas/FileBinaryDownloadResponse" "404": description: Tenant could not be resolved by createTenantKnex. content: text/plain: schema: $ref: "#/components/schemas/FileDownloadPlainTextError" "500": description: File metadata/storage lookup failed or another download error occurred. content: text/plain: schema: $ref: "#/components/schemas/FileDownloadPlainTextError" /api/v1/inbound-webhooks: get: summary: List inbound webhooks description: Lists tenant inbound webhook configurations. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: read x-handler: server/src/app/api/v1/inbound-webhooks/route.ts x-alga-products: - psa responses: "200": description: Inbound webhook list returned. content: application/json: schema: type: object properties: data: type: array items: $ref: "#/components/schemas/InboundWebhookConfig" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error post: summary: Create inbound webhook description: Creates an inbound webhook configuration and returns any one-time generated secret. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: create x-handler: server/src/app/api/v1/inbound-webhooks/route.ts x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InboundWebhookCreateInput" responses: "201": description: Inbound webhook created. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/InboundWebhookConfig" secret: type: - string - "null" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "409": description: Inbound webhook slug already exists. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error /api/v1/inbound-webhooks/actions: get: summary: List inbound webhook actions description: Returns registered direct-action definitions with target field schemas. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: read x-handler: server/src/app/api/v1/inbound-webhooks/actions/route.ts x-alga-products: - psa responses: "200": description: Inbound action definitions returned. content: application/json: schema: type: object properties: data: type: array items: $ref: "#/components/schemas/InboundActionDefinition" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error /api/v1/inbound-webhooks/{id}: get: summary: Get inbound webhook description: Returns a single inbound webhook configuration. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: read x-handler: server/src/app/api/v1/inbound-webhooks/{id}/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path responses: "200": description: Inbound webhook returned. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/InboundWebhookConfig" secret: type: - string - "null" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound webhook not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error put: summary: Update inbound webhook description: Updates an inbound webhook configuration by id. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: update x-handler: server/src/app/api/v1/inbound-webhooks/{id}/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InboundWebhookUpdateInput" responses: "200": description: Inbound webhook updated. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/InboundWebhookConfig" secret: type: - string - "null" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound webhook not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error delete: summary: Delete inbound webhook description: Deletes an inbound webhook configuration by id. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: delete x-handler: server/src/app/api/v1/inbound-webhooks/{id}/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path responses: "204": description: Inbound webhook deleted. "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound webhook not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error /api/v1/inbound-webhooks/{id}/rotate-secret: post: summary: Rotate inbound webhook secret description: Rotates the inbound webhook authentication secret and returns the replacement once. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: update x-handler: server/src/app/api/v1/inbound-webhooks/{id}/rotate-secret/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path responses: "200": description: Inbound webhook secret rotated. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/InboundWebhookConfig" secret: type: - string - "null" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound webhook not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error /api/v1/inbound-webhooks/{id}/test: post: summary: Send inbound webhook test request description: Dispatches a synthetic inbound request through the current webhook configuration. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: update x-handler: server/src/app/api/v1/inbound-webhooks/{id}/test/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path requestBody: required: true content: application/json: schema: type: object properties: body: {} headers: type: object additionalProperties: anyOf: - type: string - type: array items: type: string responses: "200": description: Synthetic inbound delivery accepted. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/InboundWebhookDelivery" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound webhook not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error /api/v1/inbound-webhooks/{id}/capture-sample: post: summary: Enable inbound webhook sample capture description: Enables capture mode so the next verified request stores its body as the sample payload. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: update x-handler: server/src/app/api/v1/inbound-webhooks/{id}/capture-sample/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path responses: "200": description: Sample capture enabled. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/InboundWebhookConfig" secret: type: - string - "null" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound webhook not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error delete: summary: Clear inbound webhook sample payload description: Clears the saved sample payload and disables sample capture. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: update x-handler: server/src/app/api/v1/inbound-webhooks/{id}/capture-sample/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path responses: "200": description: Sample payload cleared. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/InboundWebhookConfig" secret: type: - string - "null" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound webhook not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error /api/v1/inbound-webhooks/{id}/deliveries: get: summary: List inbound webhook deliveries description: Returns paginated delivery history for one inbound webhook. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: read x-handler: server/src/app/api/v1/inbound-webhooks/{id}/deliveries/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: - pending - dispatched - duplicate - failed required: false name: status in: query - schema: type: string format: date-time required: false name: date_from in: query - schema: type: string format: date-time required: false name: date_to in: query responses: "200": description: Inbound delivery list returned. content: application/json: schema: type: object properties: data: type: array items: $ref: "#/components/schemas/InboundWebhookDelivery" meta: type: object properties: page: type: integer limit: type: integer total: type: integer required: - page - limit - total required: - data - meta "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound webhook not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error /api/v1/inbound-webhooks/{id}/deliveries/{deliveryId}: get: summary: Get inbound webhook delivery description: Returns a single inbound webhook delivery row including request and response details. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: read x-handler: server/src/app/api/v1/inbound-webhooks/{id}/deliveries/{deliveryId}/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path - schema: type: string format: uuid description: Inbound delivery UUID. required: true description: Inbound delivery UUID. name: deliveryId in: path responses: "200": description: Inbound delivery returned. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/InboundWebhookDelivery" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound delivery not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error /api/v1/inbound-webhooks/{id}/deliveries/{deliveryId}/replay: post: summary: Replay inbound webhook delivery description: Re-dispatches a stored inbound delivery against the current webhook configuration. tags: - Inbound Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: withAuth server action session context x-rbac-resource: inbound_webhook x-rbac-action: replay x-handler: server/src/app/api/v1/inbound-webhooks/{id}/deliveries/{deliveryId}/replay/route.ts x-alga-products: - psa parameters: - schema: type: string format: uuid description: Inbound webhook UUID. required: true description: Inbound webhook UUID. name: id in: path - schema: type: string format: uuid description: Inbound delivery UUID. required: true description: Inbound delivery UUID. name: deliveryId in: path responses: "200": description: Inbound delivery replay accepted. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/InboundWebhookDelivery" required: - data "400": description: Invalid inbound webhook request. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Missing or invalid authenticated user context. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "403": description: Inbound webhook permission denied. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "404": description: Inbound delivery not found. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected inbound webhook operation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error /api/inbound/{tenantSlug}/{webhookSlug}: post: summary: Receive inbound webhook payload description: Receives a JSON payload for a tenant inbound webhook. Authentication, idempotency, rate limit, and handler behavior are controlled by the webhook configuration. tags: - Inbound Webhooks extensions: x-tenant-scoped: true x-auth-mechanism: per-webhook auth configuration x-rbac-resource: inbound_webhook x-handler: server/src/app/api/inbound/[tenantSlug]/[webhookSlug]/route.ts x-alga-products: - psa parameters: - schema: type: string description: URL-safe tenant slug used for inbound webhook routing. required: true description: URL-safe tenant slug used for inbound webhook routing. name: tenantSlug in: path - schema: type: string description: URL-safe inbound webhook slug unique within the tenant. required: true description: URL-safe inbound webhook slug unique within the tenant. name: webhookSlug in: path - schema: type: string description: Expected to be application/json for JSON payloads. required: false description: Expected to be application/json for JSON payloads. name: content-type in: header - schema: type: string description: Example HMAC-SHA256 signature header. Actual header name is webhook-configurable. required: false description: Example HMAC-SHA256 signature header. Actual header name is webhook-configurable. name: x-signature in: header - schema: type: string description: Optional idempotency key header when the webhook uses a header idempotency source. required: false description: Optional idempotency key header when the webhook uses a header idempotency source. name: x-idempotency-key in: header requestBody: description: Source-specific JSON payload. Shape varies per inbound webhook configuration. required: true content: application/json: schema: {} description: Source-specific JSON payload. Shape varies per inbound webhook configuration. responses: "200": description: Request accepted or treated as duplicate no-op. content: application/json: schema: type: object properties: delivery_id: type: string format: uuid required: - delivery_id "400": description: Invalid request payload or handler validation failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "401": description: Authentication failed or receiver is unknown/inactive. Response body is intentionally empty to avoid leaking which webhooks exist. "429": description: Per-webhook rate limit exceeded. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error "500": description: Unexpected dispatch failure. content: application/json: schema: type: object properties: error: type: object properties: code: type: string message: type: string details: {} required: - code - message required: - error patch: summary: PATCH inbound description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - inbound extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: PUT inbound description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - inbound extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/health: get: summary: Health check description: Simple unauthenticated liveness check for the Next.js API process. It performs no database, Redis, or downstream dependency checks and returns a fixed status/version payload when the process can serve HTTP requests. tags: - System security: [] extensions: x-api-key-auth-skipped: true x-dependency-checks: false x-alga-products: - psa responses: "200": description: API process is alive and responding. content: application/json: schema: $ref: "#/components/schemas/HealthResponse" /api/healthz: get: summary: Liveness probe description: Kubernetes liveness endpoint. It returns a fixed healthy status with timestamp, uptime, version, and environment when the process can serve HTTP. It does not check database, Redis, or downstream dependencies; use /api/readyz for dependency-aware readiness. tags: - System security: [] extensions: x-api-key-auth-skipped: true x-dependency-checks: false x-kubernetes-probe: liveness x-alga-products: - psa responses: "200": description: Process is alive and serving HTTP. content: application/json: schema: $ref: "#/components/schemas/HealthzResponse" /api/readyz: get: summary: Readiness probe description: Kubernetes readiness endpoint for the Next.js API route. It checks database connectivity with SELECT 1 and returns 200 only when critical dependencies are available. The Redis check is currently a placeholder that mirrors the database result. This endpoint is unauthenticated and is explicitly skipped by API-key middleware. tags: - System security: [] extensions: x-api-key-auth-skipped: true x-dependency-checks: true x-kubernetes-probe: readiness x-redis-check-stubbed: true x-alga-products: - psa responses: "200": description: All critical dependencies checked by this handler are available. content: application/json: schema: $ref: "#/components/schemas/ReadyzReadyResponse" "503": description: One or more critical dependencies are unavailable, or a readiness check threw an exception. content: application/json: schema: $ref: "#/components/schemas/ReadyzNotReadyResponse" /api/installs/lookup-by-host: get: summary: Lookup extension install by runner host description: Internal endpoint for extension runners. Given a runner domain, resolves the tenant, extension registry ID, and current bundle content hash needed to serve extension content. The EE implementation queries tenant_extension_install.runner_domain with an admin connection and then selects the latest extension_bundle row for the installed version. In non-EE builds the product-extension action is a stub. Requires x-api-key; the Express middleware allows the ALGA_AUTH_KEY runner secret or a valid database API key. tags: - Extension Installs security: - ApiKeyAuth: [] extensions: x-runner-internal: true x-admin-db-connection: true x-cache-control: no-store x-vary: x-api-key, x-canary x-alga-products: - psa parameters: - schema: type: string minLength: 1 description: Runner domain hostname to resolve. The implementation lowercases the value and strips any port before matching tenant_extension_install.runner_domain. required: true description: Runner domain hostname to resolve. The implementation lowercases the value and strips any port before matching tenant_extension_install.runner_domain. name: host in: query - schema: type: string description: Optional runner canary identifier used only for logging and cache variance. required: false description: Optional runner canary identifier used only for logging and cache variance. name: x-canary in: header responses: "200": description: Install mapping found for the runner host. content: application/json: schema: $ref: "#/components/schemas/InstallLookupByHostResponse" "400": description: The required host query parameter is missing. content: application/json: schema: $ref: "#/components/schemas/InstallLookupErrorResponse" "401": description: x-api-key is missing or invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/InstallLookupErrorResponse" "404": description: No install or bundle was found for the runner host. content: application/json: schema: $ref: "#/components/schemas/InstallLookupErrorResponse" "500": description: Unexpected lookup failure. content: application/json: schema: $ref: "#/components/schemas/InstallLookupErrorResponse" /api/installs/validate: get: summary: Validate extension bundle content hash description: Internal endpoint for extension runners and deployment validation. It checks whether a supplied content hash belongs to the currently installed extension version for the supplied tenant and extension registry ID. The EE action uses an admin database connection, reads tenant_extension_install by tenant_id and registry_id, and checks extension_bundle for a matching version_id and content_hash. A negative validation result is returned as 200 with valid=false, not as 404. Requires x-api-key; the Express middleware allows the ALGA_AUTH_KEY runner secret or a valid database API key. tags: - Extension Installs security: - ApiKeyAuth: [] extensions: x-runner-internal: true x-admin-db-connection: true x-cache-control: no-store x-vary: x-api-key, x-canary x-alga-products: - psa parameters: - schema: type: string format: uuid description: Tenant UUID from tenant_extension_install.tenant_id. required: true description: Tenant UUID from tenant_extension_install.tenant_id. name: tenant in: query - schema: type: string format: uuid description: Extension registry UUID from tenant_extension_install.registry_id. required: true description: Extension registry UUID from tenant_extension_install.registry_id. name: extension in: query - schema: type: string minLength: 1 description: "Bundle content hash to validate. The EE action accepts sha256:<64 hex chars> or a raw 64-character hex string and normalizes raw hex to sha256: form." required: true description: "Bundle content hash to validate. The EE action accepts sha256:<64 hex chars> or a raw 64-character hex string and normalizes raw hex to sha256: form." name: hash in: query - schema: type: string description: Optional runner canary identifier used only for logging and cache variance. required: false description: Optional runner canary identifier used only for logging and cache variance. name: x-canary in: header responses: "200": description: Validation completed. valid=false means the hash did not match, the install was not found, or the hash format was invalid at the action layer. content: application/json: schema: $ref: "#/components/schemas/InstallValidateResponse" "400": description: Required tenant, extension, or hash query parameter is missing. content: application/json: schema: $ref: "#/components/schemas/InstallValidateParameterErrorResponse" "401": description: x-api-key is missing or invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/InstallLookupErrorResponse" "500": description: Unexpected validation failure. The EE handler returns valid=false for internal exceptions. content: application/json: schema: $ref: "#/components/schemas/InstallValidateResponse" /api/integrations/qbo/status: get: summary: QuickBooks Online status route unavailable description: This path appears in the generated route inventory, but server/src/app/api/integrations/qbo/status/route.ts is not present in the current worktree. Without an x-api-key, API middleware returns 401 before routing. With the middleware requirement satisfied, Next.js has no handler for this path and returns the framework not-found response. QuickBooks connection status is currently exposed through server actions such as getQboConnectionStatus and through versioned QuickBooks API routes, not this inventory-only path. deprecated: true tags: - Integrations - QuickBooks security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/integrations/qbo/status/route.ts x-oauth-provider: quickbooks-online x-alga-products: - psa responses: "401": description: x-api-key is missing at middleware before routing. content: application/json: schema: $ref: "#/components/schemas/QboErrorResponse" "404": description: No route handler exists for this inventory-only path in the current worktree. content: text/html: schema: $ref: "#/components/schemas/QboRouteMissingResponse" /api/integrations/qbo/connect: get: summary: Start QuickBooks Online OAuth flow description: Browser-navigated endpoint that initiates the QuickBooks Online OAuth 2.0 authorization flow. The handler resolves tenant context with createTenantKnex, reads qbo_client_id from app secrets, generates a random CSRF value, embeds {tenantId, csrf} as base64url JSON in the state parameter, and redirects to Intuit at appcenter.intuit.com/connect/oauth2. The CSRF value is currently logged but not persisted, and the callback currently treats CSRF as valid. The route is not currently listed in apiKeySkipPaths, so middleware may require x-api-key before the browser can reach the handler. tags: - Integrations - QuickBooks security: - ApiKeyAuth: [] extensions: x-oauth-provider: quickbooks-online x-redirect-endpoint: true x-middleware-api-key-required-currently: true x-csrf-validation-implemented: false x-alga-products: - psa responses: "302": description: Redirect to Intuit OAuth authorization URL. Location includes client_id, response_type=code, QuickBooks accounting scope, redirect_uri, and encoded state. The handler returns no JSON body. "401": description: Tenant context is missing in the handler, or x-api-key is missing at middleware before the handler runs. content: application/json: schema: $ref: "#/components/schemas/QboErrorResponse" "500": description: QBO client ID is not configured, or an unexpected error occurred while constructing the authorization redirect. content: application/json: schema: $ref: "#/components/schemas/QboErrorResponse" /api/integrations/qbo/callback: get: summary: Handle QuickBooks Online OAuth callback description: OAuth 2.0 redirect endpoint for QuickBooks Online. Intuit redirects the browser here with code, state, and realmId after authorization. The handler decodes tenantId and csrf from the base64url state parameter, exchanges the code for access and refresh tokens, stores credentials in the tenant secret qbo_credentials keyed by realmId, and redirects back to /msp/settings with qbo_status=success or qbo_status=failure and an error code. The route returns redirects rather than JSON from the handler. Like the connect route, it is not currently listed in apiKeySkipPaths, so middleware may reject real Intuit callbacks that do not include x-api-key. tags: - Integrations - QuickBooks security: [] extensions: x-oauth-provider: quickbooks-online x-redirect-endpoint: true x-token-secret-name: qbo_credentials x-middleware-api-key-required-currently: true x-csrf-validation-implemented: false x-alga-products: - psa parameters: - schema: type: string description: OAuth 2.0 authorization code returned by Intuit. Required unless Intuit sends an error parameter. required: false description: OAuth 2.0 authorization code returned by Intuit. Required unless Intuit sends an error parameter. name: code in: query - schema: type: string description: Base64url-encoded JSON containing tenantId and csrf generated by the connect endpoint. required: false description: Base64url-encoded JSON containing tenantId and csrf generated by the connect endpoint. name: state in: query - schema: type: string description: QuickBooks company/realm ID returned by Intuit. required: false description: QuickBooks company/realm ID returned by Intuit. name: realmId in: query - schema: type: string description: OAuth error returned by Intuit when authorization fails or is denied. required: false description: OAuth error returned by Intuit when authorization fails or is denied. name: error in: query responses: "307": description: Redirect to the MSP settings integrations page. Success redirects with qbo_status=success; failures redirect with qbo_status=failure and an error such as qbo_error, missing_params, invalid_state, csrf_mismatch, config_error, token_exchange_failed, or callback_processing_error. The handler returns no JSON body. "401": description: Middleware-level API-key rejection can occur before the OAuth callback handler runs. content: application/json: schema: $ref: "#/components/schemas/QboErrorResponse" /api/v1/integrations/quickbooks/accounts: get: summary: Get QuickBooks chart of accounts description: Returns QuickBooks accounts list; current implementation is a stub empty array. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getAccounts). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getAccounts() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /accounts x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/accounts/mappings: get: summary: List account mappings description: Returns paginated account mapping configuration; current implementation is stubbed. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getAccountMappings). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getAccountMappings() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /accounts/mappings x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" put: summary: Configure account mappings description: Stores/updates account mapping configuration for integration export/import. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (configureAccountMappings). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.configureAccountMappings() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /accounts/mappings x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1AccountMappingsBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/connection/refresh: post: summary: Refresh QuickBooks connection tokens description: Refresh endpoint currently returns synthetic success payload (service TODO). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (refreshConnection). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.refreshConnection() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /connection/refresh x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/connection/status: get: summary: Get QuickBooks connection status description: Returns tenant connection status and quick links for integration actions. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getConnectionStatus). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getConnectionStatus() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /connection/status x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/connection/test: post: summary: Run QuickBooks connection test description: Runs connection diagnostics against configured QuickBooks tenant. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (testConnection). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.testConnection() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /connection/test x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ConnectionTestBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/customers/mappings: get: summary: List customer mappings description: Returns paginated customer mapping records. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getCustomerMappings). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getCustomerMappings() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /customers/mappings x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/customers/mappings/{mapping_id}: delete: summary: Delete customer mapping description: Delete handler currently returns 204 stub response (service TODO). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (deleteCustomerMapping). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.deleteCustomerMapping() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /customers/mappings/{mapping_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Mapping identifier extracted from path segment mapping_id. required: true description: Mapping identifier extracted from path segment mapping_id. name: mapping_id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/customers/sync: post: summary: Sync customers description: Synchronizes customer entities between Alga and QuickBooks. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (syncCustomers). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.syncCustomers() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /customers/sync x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1CustomerSyncBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/diagnostics: post: summary: Run QuickBooks diagnostics description: Runs diagnostic checks; current implementation returns synthetic health data. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (runDiagnostics). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: admin x-controller-method: ApiQuickBooksController.runDiagnostics() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /diagnostics x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/health: get: summary: Get integration health description: Returns integration health summary from QuickBooksService. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getHealth). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getHealth() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /health x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/health/config: get: summary: Get health monitoring config description: Returns health monitoring configuration; current implementation is stubbed. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getHealthConfig). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getHealthConfig() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /health/config x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" put: summary: Update health monitoring config description: Updates health monitoring configuration (controller-side synthetic response). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (updateHealthConfig). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: admin x-controller-method: ApiQuickBooksController.updateHealthConfig() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /health/config x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1HealthConfigBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/invoices/export: post: summary: Export invoices to QuickBooks description: Exports selected invoices to QuickBooks and returns job/result metadata. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (exportInvoices). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.exportInvoices() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /invoices/export x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1InvoiceExportBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/invoices/import: post: summary: Import invoices from QuickBooks description: Imports QuickBooks invoices into Alga with optional upsert behavior. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (importInvoices). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.importInvoices() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /invoices/import x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1InvoiceImportBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/items: get: summary: List QuickBooks items description: Returns items/services catalog; current implementation returns sample stub rows. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getItems). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getItems() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /items x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/mappings: get: summary: List data mappings description: Returns paginated list of generic QuickBooks data mapping configurations. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getDataMappings). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getDataMappings() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /mappings x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" post: summary: Create data mapping description: Creates one data mapping configuration; current implementation returns synthetic mapping id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (createDataMapping). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.createDataMapping() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /mappings x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1DataMappingBody" responses: "201": description: Mapping created. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/mappings/{mapping_id}: get: summary: Get data mapping by id description: Returns one data mapping record by mapping_id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getDataMappingById). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getDataMappingById() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /mappings/{mapping_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Mapping identifier extracted from path segment mapping_id. required: true description: Mapping identifier extracted from path segment mapping_id. name: mapping_id in: path responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "404": description: Requested mapping/sync record not found. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" put: summary: Update data mapping description: Updates one data mapping configuration by mapping_id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (updateDataMapping). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.updateDataMapping() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /mappings/{mapping_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Mapping identifier extracted from path segment mapping_id. required: true description: Mapping identifier extracted from path segment mapping_id. name: mapping_id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1DataMappingBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" delete: summary: Delete data mapping description: Deletes one data mapping configuration (current controller returns 204 stub). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (deleteDataMapping). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.deleteDataMapping() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /mappings/{mapping_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Mapping identifier extracted from path segment mapping_id. required: true description: Mapping identifier extracted from path segment mapping_id. name: mapping_id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/oauth/callback: post: summary: Handle QuickBooks OAuth callback payload description: Consumes OAuth callback payload with code/state/realm and persists connection tokens. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (handleOAuthCallback). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.handleOAuthCallback() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /oauth/callback x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1OAuthCallbackBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/oauth/disconnect: delete: summary: Disconnect QuickBooks OAuth description: Revokes/disconnects QuickBooks tenant credentials and returns 204. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (disconnectOAuth). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: admin x-controller-method: ApiQuickBooksController.disconnectOAuth() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /oauth/disconnect x-quickbooks-family-alias: true x-alga-products: - psa responses: "204": description: Operation completed with no response body. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/oauth/initiate: post: summary: Initiate QuickBooks OAuth flow description: Generates authorization URL for QuickBooks OAuth with tenant-scoped state. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (initiateOAuth). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.initiateOAuth() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /oauth/initiate x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1OAuthInitiateBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/payment-methods: get: summary: List QuickBooks payment methods description: Returns payment methods; current implementation returns sample stub rows. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getPaymentMethods). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getPaymentMethods() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /payment-methods x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/payments/sync: post: summary: Sync payments description: Synchronizes payment records between Alga and QuickBooks. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (syncPayments). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.syncPayments() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /payments/sync x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1PaymentSyncBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/sync/bulk: post: summary: Run bulk QuickBooks sync description: Starts multi-operation bulk sync and returns accepted job payload. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (bulkSync). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.bulkSync() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /sync/bulk x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1BulkSyncBody" responses: "202": description: Async sync job accepted. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/sync/full: post: summary: Run full QuickBooks sync description: Starts full synchronization workflow and returns accepted job payload. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (fullSync). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: admin x-controller-method: ApiQuickBooksController.fullSync() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /sync/full x-quickbooks-family-alias: true x-alga-products: - psa responses: "202": description: Async sync job accepted. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/sync/history: get: summary: List sync history description: Returns paginated synchronization history with status/type/date filters. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getSyncHistory). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getSyncHistory() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /sync/history x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a103 required: false name: status in: query - schema: type: string enum: *a104 required: false name: operation_type in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/sync/status: get: summary: Get current sync status description: Returns current sync status summary (currently stub status payload). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getSyncStatus). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getSyncStatus() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /sync/status x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/sync/status/{sync_id}: get: summary: Get sync status by id description: Returns detailed status for one sync operation id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getSyncStatusById). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getSyncStatusById() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /sync/status/{sync_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Sync operation identifier extracted from path segment sync_id. required: true description: Sync operation identifier extracted from path segment sync_id. name: sync_id in: path responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "404": description: Requested mapping/sync record not found. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/sync/{sync_id}/cancel: post: summary: Cancel sync operation description: Cancel endpoint currently returns 204 stub response (service TODO). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (cancelSync). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.cancelSync() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /sync/{sync_id}/cancel x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Sync operation identifier extracted from path segment sync_id. required: true description: Sync operation identifier extracted from path segment sync_id. name: sync_id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/sync/{sync_id}/retry: post: summary: Retry sync operation description: Retries a failed sync and returns synthetic new retry sync id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (retrySync). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.retrySync() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /sync/{sync_id}/retry x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Sync operation identifier extracted from path segment sync_id. required: true description: Sync operation identifier extracted from path segment sync_id. name: sync_id in: path responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/tax-codes: get: summary: List QuickBooks tax codes description: Returns tax code list; current implementation is a stub empty array. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getTaxCodes). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getTaxCodes() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /tax-codes x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/tax-codes/mappings: get: summary: List tax mappings description: Returns paginated tax mapping configuration; current implementation is stubbed. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getTaxMappings). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getTaxMappings() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /tax-codes/mappings x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" put: summary: Configure tax mappings description: Stores/updates mapping from Alga tax regions to QuickBooks tax codes. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (configureTaxMappings). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.configureTaxMappings() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /tax-codes/mappings x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1TaxMappingsBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/integrations/quickbooks/terms: get: summary: List QuickBooks terms description: Returns payment terms catalog; current implementation returns sample stub rows. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getTerms). This family uses route handlers that instantiate ApiQuickBooksController and usually wrap calls in explicit try/catch handleApiError blocks. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getTerms() x-quickbooks-route-family: integrations x-quickbooks-alias-path: /terms x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/accounts: get: summary: Get QuickBooks chart of accounts description: Returns QuickBooks accounts list; current implementation is a stub empty array. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getAccounts). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getAccounts() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /accounts x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/accounts/mappings: get: summary: List account mappings description: Returns paginated account mapping configuration; current implementation is stubbed. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getAccountMappings). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getAccountMappings() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /accounts/mappings x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" put: summary: Configure account mappings description: Stores/updates account mapping configuration for integration export/import. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (configureAccountMappings). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.configureAccountMappings() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /accounts/mappings x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1AccountMappingsBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/connection/refresh: post: summary: Refresh QuickBooks connection tokens description: Refresh endpoint currently returns synthetic success payload (service TODO). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (refreshConnection). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.refreshConnection() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /connection/refresh x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/connection/status: get: summary: Get QuickBooks connection status description: Returns tenant connection status and quick links for integration actions. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getConnectionStatus). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getConnectionStatus() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /connection/status x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/connection/test: post: summary: Run QuickBooks connection test description: Runs connection diagnostics against configured QuickBooks tenant. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (testConnection). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.testConnection() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /connection/test x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ConnectionTestBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/customers/mappings: get: summary: List customer mappings description: Returns paginated customer mapping records. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getCustomerMappings). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getCustomerMappings() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /customers/mappings x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/customers/mappings/{mapping_id}: delete: summary: Delete customer mapping description: Delete handler currently returns 204 stub response (service TODO). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (deleteCustomerMapping). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.deleteCustomerMapping() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /customers/mappings/{mapping_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Mapping identifier extracted from path segment mapping_id. required: true description: Mapping identifier extracted from path segment mapping_id. name: mapping_id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/customers/sync: post: summary: Sync customers description: Synchronizes customer entities between Alga and QuickBooks. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (syncCustomers). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.syncCustomers() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /customers/sync x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1CustomerSyncBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/diagnostics: post: summary: Run QuickBooks diagnostics description: Runs diagnostic checks; current implementation returns synthetic health data. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (runDiagnostics). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: admin x-controller-method: ApiQuickBooksController.runDiagnostics() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /diagnostics x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/health: get: summary: Get integration health description: Returns integration health summary from QuickBooksService. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getHealth). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getHealth() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /health x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/health/config: get: summary: Get health monitoring config description: Returns health monitoring configuration; current implementation is stubbed. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getHealthConfig). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getHealthConfig() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /health/config x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" put: summary: Update health monitoring config description: Updates health monitoring configuration (controller-side synthetic response). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (updateHealthConfig). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: admin x-controller-method: ApiQuickBooksController.updateHealthConfig() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /health/config x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1HealthConfigBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/invoices/export: post: summary: Export invoices to QuickBooks description: Exports selected invoices to QuickBooks and returns job/result metadata. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (exportInvoices). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.exportInvoices() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /invoices/export x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1InvoiceExportBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/invoices/import: post: summary: Import invoices from QuickBooks description: Imports QuickBooks invoices into Alga with optional upsert behavior. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (importInvoices). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.importInvoices() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /invoices/import x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1InvoiceImportBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/items: get: summary: List QuickBooks items description: Returns items/services catalog; current implementation returns sample stub rows. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getItems). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getItems() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /items x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/mappings: get: summary: List data mappings description: Returns paginated list of generic QuickBooks data mapping configurations. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getDataMappings). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getDataMappings() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /mappings x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" post: summary: Create data mapping description: Creates one data mapping configuration; current implementation returns synthetic mapping id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (createDataMapping). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.createDataMapping() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /mappings x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1DataMappingBody" responses: "201": description: Mapping created. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/mappings/{mapping_id}: get: summary: Get data mapping by id description: Returns one data mapping record by mapping_id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getDataMappingById). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getDataMappingById() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /mappings/{mapping_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Mapping identifier extracted from path segment mapping_id. required: true description: Mapping identifier extracted from path segment mapping_id. name: mapping_id in: path responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "404": description: Requested mapping/sync record not found. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" put: summary: Update data mapping description: Updates one data mapping configuration by mapping_id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (updateDataMapping). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.updateDataMapping() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /mappings/{mapping_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Mapping identifier extracted from path segment mapping_id. required: true description: Mapping identifier extracted from path segment mapping_id. name: mapping_id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1DataMappingBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" delete: summary: Delete data mapping description: Deletes one data mapping configuration (current controller returns 204 stub). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (deleteDataMapping). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.deleteDataMapping() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /mappings/{mapping_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Mapping identifier extracted from path segment mapping_id. required: true description: Mapping identifier extracted from path segment mapping_id. name: mapping_id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/oauth/callback: post: summary: Handle QuickBooks OAuth callback payload description: Consumes OAuth callback payload with code/state/realm and persists connection tokens. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (handleOAuthCallback). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.handleOAuthCallback() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /oauth/callback x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1OAuthCallbackBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/oauth/disconnect: delete: summary: Disconnect QuickBooks OAuth description: Revokes/disconnects QuickBooks tenant credentials and returns 204. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (disconnectOAuth). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: admin x-controller-method: ApiQuickBooksController.disconnectOAuth() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /oauth/disconnect x-quickbooks-family-alias: true x-alga-products: - psa responses: "204": description: Operation completed with no response body. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/oauth/initiate: post: summary: Initiate QuickBooks OAuth flow description: Generates authorization URL for QuickBooks OAuth with tenant-scoped state. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (initiateOAuth). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.initiateOAuth() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /oauth/initiate x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1OAuthInitiateBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/payment-methods: get: summary: List QuickBooks payment methods description: Returns payment methods; current implementation returns sample stub rows. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getPaymentMethods). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getPaymentMethods() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /payment-methods x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/payments/sync: post: summary: Sync payments description: Synchronizes payment records between Alga and QuickBooks. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (syncPayments). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.syncPayments() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /payments/sync x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1PaymentSyncBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/sync/bulk: post: summary: Run bulk QuickBooks sync description: Starts multi-operation bulk sync and returns accepted job payload. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (bulkSync). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.bulkSync() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /sync/bulk x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1BulkSyncBody" responses: "202": description: Async sync job accepted. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/sync/full: post: summary: Run full QuickBooks sync description: Starts full synchronization workflow and returns accepted job payload. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (fullSync). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: admin x-controller-method: ApiQuickBooksController.fullSync() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /sync/full x-quickbooks-family-alias: true x-alga-products: - psa responses: "202": description: Async sync job accepted. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/sync/history: get: summary: List sync history description: Returns paginated synchronization history with status/type/date filters. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getSyncHistory). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getSyncHistory() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /sync/history x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a103 required: false name: status in: query - schema: type: string enum: *a104 required: false name: operation_type in: query - schema: type: string required: false name: date_from in: query - schema: type: string required: false name: date_to in: query responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/sync/status: get: summary: Get current sync status description: Returns current sync status summary (currently stub status payload). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getSyncStatus). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getSyncStatus() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /sync/status x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/sync/status/{sync_id}: get: summary: Get sync status by id description: Returns detailed status for one sync operation id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getSyncStatusById). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getSyncStatusById() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /sync/status/{sync_id} x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Sync operation identifier extracted from path segment sync_id. required: true description: Sync operation identifier extracted from path segment sync_id. name: sync_id in: path responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "404": description: Requested mapping/sync record not found. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/sync/{sync_id}/cancel: post: summary: Cancel sync operation description: Cancel endpoint currently returns 204 stub response (service TODO). Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (cancelSync). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.cancelSync() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /sync/{sync_id}/cancel x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Sync operation identifier extracted from path segment sync_id. required: true description: Sync operation identifier extracted from path segment sync_id. name: sync_id in: path responses: "204": description: Operation completed with no response body. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/sync/{sync_id}/retry: post: summary: Retry sync operation description: Retries a failed sync and returns synthetic new retry sync id. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (retrySync). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.retrySync() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /sync/{sync_id}/retry x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string description: Sync operation identifier extracted from path segment sync_id. required: true description: Sync operation identifier extracted from path segment sync_id. name: sync_id in: path responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/tax-codes: get: summary: List QuickBooks tax codes description: Returns tax code list; current implementation is a stub empty array. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getTaxCodes). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getTaxCodes() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /tax-codes x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/tax-codes/mappings: get: summary: List tax mappings description: Returns paginated tax mapping configuration; current implementation is stubbed. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getTaxMappings). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getTaxMappings() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /tax-codes/mappings x-quickbooks-family-alias: true x-alga-products: - psa responses: "200": description: Paginated records returned. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" put: summary: Configure tax mappings description: Stores/updates mapping from Alga tax regions to QuickBooks tax codes. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (configureTaxMappings). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: write x-controller-method: ApiQuickBooksController.configureTaxMappings() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /tax-codes/mappings x-quickbooks-family-alias: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1TaxMappingsBody" responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/quickbooks/terms: get: summary: List QuickBooks terms description: Returns payment terms catalog; current implementation returns sample stub rows. Both /api/v1/integrations/quickbooks/* and /api/v1/quickbooks/* map to the same ApiQuickBooksController method (getTerms). This family is a path alias that binds controller methods directly (for example `export const GET = controller.getAccounts()`) and relies on controller-level error handling. tags: - QuickBooks v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated by ApiQuickBooksController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quickbooks x-rbac-action: read x-controller-method: ApiQuickBooksController.getTerms() x-quickbooks-route-family: quickbooks x-quickbooks-alias-path: /terms x-quickbooks-family-alias: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a101 required: false name: active in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: entity_type in: query - schema: type: string enum: *a102 required: false name: force_refresh in: query responses: "200": description: QuickBooks operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "403": description: QuickBooks RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" "500": description: Unexpected QuickBooks endpoint failure. content: application/json: schema: $ref: "#/components/schemas/QuickBooksV1ApiError" /api/v1/boards: get: summary: List boards description: Returns a paginated list of ticket boards for the current tenant. Use this to discover valid board_id values before creating tickets or statuses. tags: - Boards security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: List Boards x-chat-rbac-resource: ticket x-chat-approval-required: false x-alga-products: - psa - algadesk responses: "200": description: Boards returned successfully. content: application/json: schema: $ref: "#/components/schemas/BoardListEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: Create board description: Creates a new ticket board. After creating a board, create at least one status for it via POST /api/v1/statuses so tickets can be assigned to the board. tags: - Boards security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: Create Board x-chat-rbac-resource: ticket x-chat-approval-required: true x-alga-products: - psa - algadesk requestBody: description: Board creation payload. required: true content: application/json: schema: $ref: "#/components/schemas/BoardCreateRequest" description: Board creation payload. responses: "201": description: Board created successfully. content: application/json: schema: $ref: "#/components/schemas/BoardEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/boards/{id}: get: summary: Get board by ID description: Returns a single board by its UUID. tags: - Boards security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: Get Board x-chat-rbac-resource: ticket x-chat-approval-required: false x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Board UUID. required: true description: Board UUID. name: id in: path responses: "200": description: Board returned successfully. content: application/json: schema: $ref: "#/components/schemas/BoardEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Board not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Update board description: Updates an existing board. All fields are optional — only send the fields you want to change. tags: - Boards security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: Update Board x-chat-rbac-resource: ticket x-chat-approval-required: true x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Board UUID. required: true description: Board UUID. name: id in: path requestBody: description: Board update payload. required: true content: application/json: schema: $ref: "#/components/schemas/BoardUpdateRequest" description: Board update payload. responses: "200": description: Board updated successfully. content: application/json: schema: $ref: "#/components/schemas/BoardEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Board not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: summary: Delete board description: Deletes a board by its UUID. This will fail if the board has associated tickets. tags: - Boards security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: Delete Board x-chat-rbac-resource: ticket x-chat-approval-required: true x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Board UUID. required: true description: Board UUID. name: id in: path responses: "204": description: Board deleted successfully. "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Board not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/statuses: get: summary: List statuses description: Returns a paginated list of statuses. For ticket statuses, filter by type=ticket and board_id to get statuses that belong to a specific board. The status_id must belong to the same board_id when creating tickets. tags: - Statuses security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: List Statuses x-chat-rbac-resource: ticket x-chat-approval-required: false x-alga-products: - psa - algadesk responses: "200": description: Statuses returned successfully. content: application/json: schema: $ref: "#/components/schemas/StatusListEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: Create status description: "Creates a new status. For ticket statuses, board_id is required. The status_type must be one of: ticket, project, project_task, interaction." tags: - Statuses security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: Create Status x-chat-rbac-resource: ticket x-chat-approval-required: true x-alga-products: - psa - algadesk requestBody: description: Status creation payload. required: true content: application/json: schema: $ref: "#/components/schemas/StatusCreateRequest" description: Status creation payload. responses: "201": description: Status created successfully. content: application/json: schema: $ref: "#/components/schemas/StatusEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/statuses/{id}: get: summary: Get status by ID description: Returns a single status by its UUID. tags: - Statuses security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: Get Status x-chat-rbac-resource: ticket x-chat-approval-required: false x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Status UUID. required: true description: Status UUID. name: id in: path responses: "200": description: Status returned successfully. content: application/json: schema: $ref: "#/components/schemas/StatusEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Status not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Update status description: Updates an existing status. All fields are optional — only send the fields you want to change. tags: - Statuses security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: Update Status x-chat-rbac-resource: ticket x-chat-approval-required: true x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Status UUID. required: true description: Status UUID. name: id in: path requestBody: description: Status update payload. required: true content: application/json: schema: $ref: "#/components/schemas/StatusUpdateRequest" description: Status update payload. responses: "200": description: Status updated successfully. content: application/json: schema: $ref: "#/components/schemas/StatusEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Status not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: summary: Delete status description: Deletes a status by its UUID. Cannot delete the last default status for a board. tags: - Statuses security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket x-chat-callable: true x-chat-display-name: Delete Status x-chat-rbac-resource: ticket x-chat-approval-required: true x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Status UUID. required: true description: Status UUID. name: id in: path responses: "204": description: Status deleted successfully. "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Status not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/search: get: summary: Unified full-text search description: "Full-text search across all indexed business records (tickets, clients, contacts, projects, assets, invoices, contracts, documents, knowledge-base articles, and more) backed by the shared app_search_index. Results are tenant-scoped and filtered by the API key user's permissions: a coarse per-type permission gate plus a per-row access-control check, so only records the user could see in-app are returned. No dedicated search permission is required — any valid API key may call this endpoint. Client-portal API keys are automatically scoped to their own client." tags: - Search security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-acl-filtered: true x-not-paginated: false x-alga-products: - psa parameters: - schema: type: string minLength: 1 maxLength: 200 description: Full-text query. A concise expression of likely record words, identifiers, names, or quoted phrases — not a full sentence. Supports OR for alternatives (e.g. "laptop OR workstation"). required: true description: Full-text query. A concise expression of likely record words, identifiers, names, or quoted phrases — not a full sentence. Supports OR for alternatives (e.g. "laptop OR workstation"). name: query in: query - schema: type: string description: "Comma-separated list of object types to restrict the search (e.g. \"ticket,project\"). Omit to search every type the API key's user is permitted to read. Allowed values: client, contact, user, ticket, ticket_comment, project, project_phase, project_task, project_task_comment, asset, invoice, invoice_item, invoice_annotation, contract, client_contract, document, kb_article, service_catalog, service_request_submission, service_request_definition, workflow_task, interaction, schedule_entry, time_entry, board, category, tag, status." required: false description: "Comma-separated list of object types to restrict the search (e.g. \"ticket,project\"). Omit to search every type the API key's user is permitted to read. Allowed values: client, contact, user, ticket, ticket_comment, project, project_phase, project_task, project_task_comment, asset, invoice, invoice_item, invoice_annotation, contract, client_contract, document, kb_article, service_catalog, service_request_submission, service_request_definition, workflow_task, interaction, schedule_entry, time_entry, board, category, tag, status." name: types in: query - schema: type: integer minimum: 1 maximum: 100 description: Maximum number of results to return. Defaults to 30; capped at 100. required: false description: Maximum number of results to return. Defaults to 30; capped at 100. name: limit in: query - schema: type: string description: Opaque pagination cursor copied from a prior response's nextCursor. required: false description: Opaque pagination cursor copied from a prior response's nextCursor. name: cursor in: query - schema: type: string enum: *a105 description: Result ordering. "relevance" (default) ranks by full-text score; "recent" orders by last update. required: false description: Result ordering. "relevance" (default) ranks by full-text score; "recent" orders by last update. name: sort in: query responses: "200": description: Matching records returned successfully. content: application/json: schema: $ref: "#/components/schemas/SearchResponse" "400": description: Query parameter validation failed (missing/empty query, unknown type, or out-of-range limit). content: application/json: schema: $ref: "#/components/schemas/SearchApiErrorEnvelope" "401": description: API key is missing or invalid. content: application/json: schema: $ref: "#/components/schemas/SearchApiErrorEnvelope" "429": description: API rate limit exceeded for the key. content: application/json: schema: $ref: "#/components/schemas/SearchApiErrorEnvelope" "500": description: Unexpected error while executing the search. content: application/json: schema: $ref: "#/components/schemas/SearchApiErrorEnvelope" /api/v1/categories/service: get: summary: List service categories description: Returns a paginated list of service categories within the current tenant. tags: - Service Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service-category x-chat-callable: true x-chat-display-name: List Service Categories x-chat-rbac-resource: service-category x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: string required: false name: search in: query - schema: type: boolean required: false name: is_active in: query - schema: type: integer minimum: 1 required: false name: page in: query - schema: type: integer minimum: 1 maximum: 100 required: false name: limit in: query responses: "200": description: A paginated list of service categories. content: application/json: schema: $ref: "#/components/schemas/PaginatedServiceCategoryResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: Create service category description: Creates a new service category for the tenant. Requires the billing settings create permission. tags: - Service Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service-category x-chat-callable: true x-chat-display-name: Create Service Category x-chat-rbac-resource: service-category x-chat-approval-required: true x-alga-products: - psa requestBody: description: Service category payload required: true content: application/json: schema: $ref: "#/components/schemas/ServiceCategoryCreateRequest" description: Service category payload responses: "201": description: Service category created successfully. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/ServiceCategory" required: - data "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/categories/service/{id}: get: summary: Get service category description: Returns one service category by category_id for the authenticated tenant. Requires billing_settings:read permission. tags: - Service Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: billing_settings x-rbac-action: read x-id-provenance: category_id: service_categories.category_id x-alga-products: - psa parameters: - schema: type: string format: uuid description: Category UUID from service_categories.category_id or categories.category_id. required: true description: Category UUID from service_categories.category_id or categories.category_id. name: id in: path responses: "200": description: Service category returned successfully. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/ServiceCategory" required: - data "400": description: Invalid category id format. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks billing settings read permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Service category not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Update service category description: Updates one service category by category_id. Requires billing_settings:update permission. tags: - Service Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: billing_settings x-rbac-action: update x-id-provenance: category_id: service_categories.category_id x-alga-products: - psa parameters: - schema: type: string format: uuid description: Category UUID from service_categories.category_id or categories.category_id. required: true description: Category UUID from service_categories.category_id or categories.category_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ServiceCategoryCreateRequest" responses: "200": description: Service category updated successfully. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/ServiceCategory" required: - data "400": description: Invalid category id or request payload. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks billing settings update permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Service category not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: summary: Delete service category description: Deletes one service category by category_id. Requires billing_settings:delete permission. tags: - Service Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: billing_settings x-rbac-action: delete x-id-provenance: category_id: service_categories.category_id x-alga-products: - psa parameters: - schema: type: string format: uuid description: Category UUID from service_categories.category_id or categories.category_id. required: true description: Category UUID from service_categories.category_id or categories.category_id. name: id in: path responses: "204": description: Service category deleted successfully. "400": description: Invalid category id format. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks billing settings delete permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Service category not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/categories/ticket: get: summary: List ticket categories description: Returns paginated ticket categories. Requires ticket_settings:read permission. tags: - Ticket Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket_settings x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a106 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string format: date-time required: false name: created_from in: query - schema: type: string format: date-time required: false name: created_to in: query - schema: type: string format: date-time required: false name: updated_from in: query - schema: type: string format: date-time required: false name: updated_to in: query - schema: type: string required: false name: category_name in: query - schema: type: string format: uuid required: false name: board_id in: query - schema: type: string format: uuid required: false name: parent_category in: query - schema: type: string enum: *a107 required: false name: is_parent in: query - schema: type: string enum: *a108 required: false name: is_child in: query - schema: type: string required: false name: depth in: query - schema: type: string enum: *a109 required: false name: active in: query - schema: type: string required: false name: offset in: query - schema: type: string required: false name: sort_by in: query - schema: type: string enum: *a110 required: false name: sort_order in: query - schema: type: string enum: *a111 required: false name: include_hierarchy in: query - schema: type: string enum: *a112 required: false name: category_type in: query responses: "200": description: Ticket categories returned successfully. content: application/json: schema: $ref: "#/components/schemas/PaginatedTicketCategoryResponse" "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks ticket settings read permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: Create ticket category description: Creates a ticket category row for one board. Requires ticket_settings:create permission. tags: - Ticket Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket_settings x-rbac-action: create x-id-provenance: category_id: categories.category_id x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/TicketCategoryCreateRequest" responses: "201": description: Ticket category created successfully. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/TicketCategory" required: - data "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks ticket settings create permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/categories/ticket/{id}: get: summary: Get ticket category description: Returns one ticket category by category_id. Requires ticket_settings:read permission. tags: - Ticket Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket_settings x-rbac-action: read x-id-provenance: category_id: categories.category_id x-alga-products: - psa parameters: - schema: type: string format: uuid description: Category UUID from service_categories.category_id or categories.category_id. required: true description: Category UUID from service_categories.category_id or categories.category_id. name: id in: path responses: "200": description: Ticket category returned successfully. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/TicketCategory" required: - data "400": description: Invalid category id format. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks ticket settings read permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Ticket category not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Update ticket category description: Updates one ticket category by category_id. Requires ticket_settings:update permission. tags: - Ticket Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket_settings x-rbac-action: update x-id-provenance: category_id: categories.category_id x-alga-products: - psa parameters: - schema: type: string format: uuid description: Category UUID from service_categories.category_id or categories.category_id. required: true description: Category UUID from service_categories.category_id or categories.category_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/TicketCategoryUpdateRequest" responses: "200": description: Ticket category updated successfully. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/TicketCategory" required: - data "400": description: Invalid category id or request payload. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks ticket settings update permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Ticket category not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: summary: Delete ticket category description: Deletes one ticket category by category_id. Requires ticket_settings:delete permission. tags: - Ticket Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket_settings x-rbac-action: delete x-id-provenance: category_id: categories.category_id x-alga-products: - psa parameters: - schema: type: string format: uuid description: Category UUID from service_categories.category_id or categories.category_id. required: true description: Category UUID from service_categories.category_id or categories.category_id. name: id in: path responses: "204": description: Ticket category deleted successfully. "400": description: Invalid category id format. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks ticket settings delete permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Ticket category not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/categories/ticket/tree: get: summary: Get ticket category tree (implicit board id) description: Calls getCategoryTree and derives boardId from the last URL path segment. For this path without a board parameter, the current implementation passes literal `tree` as boardId to CategoryService.getCategoryTree. tags: - Ticket Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket_settings x-rbac-action: read x-board-id-derived-from-last-path-segment: true x-no-board-param-route-currently-passes-tree-literal: true x-alga-products: - psa responses: "200": description: Category tree response for derived board id value. content: application/json: schema: $ref: "#/components/schemas/CategoryTreeResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks ticket settings read permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected category tree failure for invalid derived board id. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/categories/ticket/tree/{boardId}: get: summary: Get ticket category tree by board description: Returns hierarchical ticket categories for a board route. Current controller still derives board id from the last path segment instead of reading req.params directly; this works for this route because the last segment is boardId. tags: - Ticket Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket_settings x-rbac-action: read x-board-id-derived-from-last-path-segment: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Board UUID used by ticket category tree queries. required: true description: Board UUID used by ticket category tree queries. name: boardId in: path responses: "200": description: Category tree returned successfully. content: application/json: schema: $ref: "#/components/schemas/CategoryTreeResponse" "400": description: Invalid board id format. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks ticket settings read permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Unexpected category tree failure. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/categories/ticket/move: post: summary: Move ticket category in hierarchy description: Moves a ticket category under a new parent. Requires ticket_settings:update permission. tags: - Ticket Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: ticket_settings x-rbac-action: update x-id-provenance: category_id: categories.category_id x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CategoryMoveRequest" responses: "200": description: Category moved successfully. content: application/json: schema: type: object properties: data: $ref: "#/components/schemas/TicketCategory" required: - data "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks ticket settings update permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Category not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/categories/search: get: summary: Search categories description: Searches categories across service/ticket types. Permission resource is chosen dynamically from category_type (defaults to ticket_settings when omitted). tags: - Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource-dynamic-by-category-type: service: billing_settings ticket_or_default: ticket_settings x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string minLength: 1 required: true name: search_term in: query - schema: type: string enum: *a113 required: false name: category_type in: query - schema: type: string format: uuid required: false name: board_id in: query - schema: type: string enum: *a114 required: false name: include_inactive in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: offset in: query responses: "200": description: Category search results returned. content: application/json: schema: type: object properties: data: type: array items: type: object additionalProperties: {} pagination: type: object additionalProperties: {} meta: type: object additionalProperties: {} required: - data - pagination "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the derived settings read permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/categories/analytics: get: summary: Get category analytics description: Returns category analytics with generation timestamp. Permission resource is chosen dynamically from category_type (defaults to ticket_settings when omitted). tags: - Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource-dynamic-by-category-type: service: billing_settings ticket_or_default: ticket_settings x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string enum: *a115 required: false name: category_type in: query - schema: type: string format: uuid required: false name: board_id in: query - schema: type: string format: date-time required: false name: date_from in: query - schema: type: string format: date-time required: false name: date_to in: query - schema: type: string enum: *a116 required: false name: include_usage in: query responses: "200": description: Category analytics returned successfully. content: application/json: schema: $ref: "#/components/schemas/CategoryAnalyticsResponse" "400": description: Invalid query parameters. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the derived settings read permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/categories/bulk/delete: post: summary: Bulk delete categories description: Deletes multiple category ids. Permission resource is chosen dynamically from category_type; response includes success/failed counts and per-item errors. tags: - Categories security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource-dynamic-by-category-type: service: billing_settings ticket: ticket_settings x-rbac-action: delete x-partial-failures-in-response: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BulkDeleteCategoriesRequest" responses: "200": description: Bulk deletion completed. content: application/json: schema: $ref: "#/components/schemas/BulkDeleteCategoriesResponse" "400": description: Invalid request payload. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the derived settings delete permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/services: get: summary: List services description: Returns service catalog entries where item_kind is service. Use this endpoint to inspect existing service catalog records and to gather prerequisite IDs such as custom_service_type_id and category_id before creating a new service. tags: &a117 - Services - Service Catalog security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: List Services x-chat-rbac-resource: service x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: integer minimum: 1 default: 1 required: false name: page in: query - schema: type: integer minimum: 1 maximum: 100 default: 25 required: false name: limit in: query - schema: type: string enum: - service_name - billing_method - default_rate default: service_name required: false name: sort in: query - schema: type: string enum: - asc - desc default: asc required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string enum: - service - product - any required: false name: item_kind in: query - schema: anyOf: - type: string enum: - "true" - type: string enum: - "false" required: false name: is_active in: query - schema: type: string enum: &a118 - fixed - hourly - usage required: false name: billing_method in: query - schema: anyOf: - type: string format: uuid - type: string enum: - "null" required: false name: category_id in: query - schema: type: string format: uuid required: false name: custom_service_type_id in: query responses: "200": description: Services returned successfully. content: application/json: schema: $ref: "#/components/schemas/PaginatedServiceEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: Create service description: Creates a new service catalog entry. Resolve custom_service_type_id with GET /api/v1/service-types and category_id with GET /api/v1/categories/service before calling this endpoint. Use this endpoint for fixed, hourly, or usage-based service offerings. tags: *a117 security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: Create Service x-chat-rbac-resource: service x-chat-approval-required: true x-alga-products: - psa requestBody: description: Service creation payload. required: true content: application/json: schema: type: object properties: service_name: type: string minLength: 1 maxLength: 255 custom_service_type_id: type: string format: uuid billing_method: type: string enum: *a118 default_rate: type: number minimum: 0 unit_of_measure: type: string minLength: 1 maxLength: 128 category_id: anyOf: - type: string format: uuid - type: "null" - type: "null" tax_rate_id: anyOf: - type: string format: uuid - type: "null" - type: "null" description: anyOf: - type: string maxLength: 2048 - type: "null" - type: "null" required: - service_name - custom_service_type_id - billing_method - default_rate - unit_of_measure description: Service creation payload. responses: "201": description: Service created successfully. content: application/json: schema: $ref: "#/components/schemas/ServiceEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/services/{id}: get: summary: Get service description: Returns a single service catalog entry by UUID. tags: *a117 security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: Get Service x-chat-rbac-resource: service x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: Service UUID. required: true description: Service UUID. name: id in: path responses: "200": description: Service returned successfully. content: application/json: schema: $ref: "#/components/schemas/ServiceEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Service not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Update service description: Updates a service catalog entry by UUID. tags: *a117 security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: Update Service x-chat-rbac-resource: service x-chat-approval-required: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Service UUID. required: true description: Service UUID. name: id in: path requestBody: description: Service update payload. required: true content: application/json: schema: type: object properties: service_name: type: string minLength: 1 maxLength: 255 custom_service_type_id: type: string format: uuid billing_method: type: string enum: *a118 default_rate: type: number minimum: 0 unit_of_measure: type: string minLength: 1 maxLength: 128 category_id: anyOf: - type: string format: uuid - type: "null" - type: "null" tax_rate_id: anyOf: - type: string format: uuid - type: "null" - type: "null" description: anyOf: - type: string maxLength: 2048 - type: "null" - type: "null" description: Service update payload. responses: "200": description: Service updated successfully. content: application/json: schema: $ref: "#/components/schemas/ServiceEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Service not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: summary: Delete service description: Deletes a service catalog entry by UUID. tags: *a117 security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: Delete Service x-chat-rbac-resource: service x-chat-approval-required: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Service UUID. required: true description: Service UUID. name: id in: path responses: "204": description: Service deleted successfully. "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Service not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/products: get: summary: List products description: Returns product catalog entries where item_kind is product. Use this endpoint to inspect existing product catalog records and to gather prerequisite IDs such as custom_service_type_id and category_id before creating a new product. tags: &a119 - Products - Service Catalog security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: List Products x-chat-rbac-resource: service x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: integer minimum: 1 default: 1 required: false name: page in: query - schema: type: integer minimum: 1 maximum: 100 default: 25 required: false name: limit in: query - schema: type: string enum: - service_name - default_rate default: service_name required: false name: sort in: query - schema: type: string enum: - asc - desc default: asc required: false name: order in: query - schema: type: string required: false name: search in: query - schema: anyOf: - type: string enum: - "true" - type: string enum: - "false" required: false name: is_active in: query - schema: anyOf: - type: string format: uuid - type: string enum: - "null" required: false name: category_id in: query - schema: anyOf: - type: string enum: - "true" - type: string enum: - "false" required: false name: is_license in: query responses: "200": description: Products returned successfully. content: application/json: schema: $ref: "#/components/schemas/PaginatedProductEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: Create product description: Creates a new product catalog entry. Resolve custom_service_type_id with GET /api/v1/service-types and category_id with GET /api/v1/categories/service before calling this endpoint. Products are catalog entries with item_kind product and always use billing_method usage. tags: *a119 security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: Create Product x-chat-rbac-resource: service x-chat-approval-required: true x-alga-products: - psa requestBody: description: Product creation payload. required: true content: application/json: schema: type: object properties: service_name: type: string minLength: 1 maxLength: 255 custom_service_type_id: type: string format: uuid billing_method: type: string enum: &a120 - usage default: usage default_rate: type: number minimum: 0 default: 0 currency_code: type: string minLength: 3 maxLength: 3 default: USD unit_of_measure: type: string minLength: 1 maxLength: 128 category_id: anyOf: - type: string format: uuid - type: "null" - type: "null" tax_rate_id: anyOf: - type: string format: uuid - type: "null" - type: "null" description: anyOf: - type: string maxLength: 2048 - type: "null" - type: "null" sku: anyOf: - type: string maxLength: 128 - type: "null" - type: "null" cost: anyOf: - type: number minimum: 0 - type: "null" - type: "null" cost_currency: anyOf: - type: string minLength: 3 maxLength: 3 - type: "null" - type: "null" default: USD vendor: anyOf: - type: string maxLength: 255 - type: "null" - type: "null" manufacturer: anyOf: - type: string maxLength: 255 - type: "null" - type: "null" product_category: anyOf: - type: string maxLength: 255 - type: "null" - type: "null" is_license: type: boolean default: false license_term: anyOf: - type: string maxLength: 64 - type: "null" - type: "null" license_billing_cadence: anyOf: - type: string maxLength: 64 - type: "null" - type: "null" is_active: type: boolean default: true prices: type: array items: type: object properties: currency_code: type: string minLength: 3 maxLength: 3 rate: type: number minimum: 0 required: - currency_code - rate required: - service_name - custom_service_type_id - unit_of_measure description: Product creation payload. responses: "201": description: Product created successfully. content: application/json: schema: $ref: "#/components/schemas/ProductEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/products/{id}: get: summary: Get product description: Returns a single product catalog entry by UUID. tags: *a119 security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: Get Product x-chat-rbac-resource: service x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: Product UUID. required: true description: Product UUID. name: id in: path responses: "200": description: Product returned successfully. content: application/json: schema: $ref: "#/components/schemas/ProductEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Product not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Update product description: Updates a product catalog entry by UUID. tags: *a119 security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: Update Product x-chat-rbac-resource: service x-chat-approval-required: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Product UUID. required: true description: Product UUID. name: id in: path requestBody: description: Product update payload. required: true content: application/json: schema: type: object properties: service_name: type: string minLength: 1 maxLength: 255 custom_service_type_id: type: string format: uuid billing_method: type: string enum: *a120 default: usage default_rate: type: number minimum: 0 default: 0 currency_code: type: string minLength: 3 maxLength: 3 default: USD unit_of_measure: type: string minLength: 1 maxLength: 128 category_id: anyOf: - type: string format: uuid - type: "null" - type: "null" tax_rate_id: anyOf: - type: string format: uuid - type: "null" - type: "null" description: anyOf: - type: string maxLength: 2048 - type: "null" - type: "null" sku: anyOf: - type: string maxLength: 128 - type: "null" - type: "null" cost: anyOf: - type: number minimum: 0 - type: "null" - type: "null" cost_currency: anyOf: - type: string minLength: 3 maxLength: 3 - type: "null" - type: "null" default: USD vendor: anyOf: - type: string maxLength: 255 - type: "null" - type: "null" manufacturer: anyOf: - type: string maxLength: 255 - type: "null" - type: "null" product_category: anyOf: - type: string maxLength: 255 - type: "null" - type: "null" is_license: type: boolean default: false license_term: anyOf: - type: string maxLength: 64 - type: "null" - type: "null" license_billing_cadence: anyOf: - type: string maxLength: 64 - type: "null" - type: "null" is_active: type: boolean default: true prices: type: array items: type: object properties: currency_code: type: string minLength: 3 maxLength: 3 rate: type: number minimum: 0 required: - currency_code - rate description: Product update payload. responses: "200": description: Product updated successfully. content: application/json: schema: $ref: "#/components/schemas/ProductEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Product not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: summary: Delete product description: Deletes a product catalog entry by UUID. tags: *a119 security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: Delete Product x-chat-rbac-resource: service x-chat-approval-required: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Product UUID. required: true description: Product UUID. name: id in: path responses: "204": description: Product deleted successfully. "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Product not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/service-types: get: summary: List service types description: Returns tenant service types. Use this endpoint to resolve custom_service_type_id before creating or updating services and products in the service catalog. tags: &a121 - Service Types - Service Catalog security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: List Service Types x-chat-rbac-resource: service x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: string required: false name: search in: query - schema: type: boolean required: false name: is_active in: query - schema: type: integer minimum: 1 required: false name: page in: query - schema: type: integer minimum: 1 maximum: 100 required: false name: limit in: query responses: "200": description: Service types returned successfully. content: application/json: schema: $ref: "#/components/schemas/PaginatedServiceTypeEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/service-types/{id}: get: summary: Get service type description: Returns a single tenant service type by UUID. tags: *a121 security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: service x-chat-callable: true x-chat-display-name: Get Service Type x-chat-rbac-resource: service x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: Service type UUID. required: true description: Service type UUID. name: id in: path responses: "200": description: Service type returned successfully. content: application/json: schema: $ref: "#/components/schemas/ServiceTypeEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Service type not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/webhooks: get: summary: List webhooks description: Lists tenant webhooks with pagination and filter query fields. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: read x-controller-method: ApiWebhookController.list() x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a122 required: false name: order in: query - schema: type: string required: false name: name in: query - schema: type: string required: false name: url in: query - schema: type: string required: false name: event_type in: query - schema: type: string enum: *a123 required: false name: is_active in: query - schema: type: string enum: *a124 required: false name: is_test_mode in: query - schema: type: string enum: *a125 required: false name: payload_format in: query - schema: type: string enum: *a126 required: false name: has_failures in: query - schema: type: string required: false name: last_delivery_from in: query - schema: type: string required: false name: last_delivery_to in: query - schema: type: string required: false name: delivery_rate_min in: query - schema: type: string required: false name: delivery_rate_max in: query - schema: type: string required: false name: query in: query responses: "200": description: Paginated webhook list. content: application/json: schema: $ref: "#/components/schemas/WebhookListResponseV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" post: summary: Create webhook description: Creates a webhook configuration. Supports per-entity payload_fields allowlists; an undefined or null map yields the full payload. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: create x-controller-method: ApiWebhookController.create() x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateWebhookBodyV1" responses: "201": description: Webhook created. content: application/json: schema: $ref: "#/components/schemas/WebhookEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "409": description: Webhook already exists. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/analytics: get: summary: Get system webhook analytics description: Returns aggregated webhook delivery analytics for the tenant over a date window. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: analytics x-controller-method: ApiWebhookController.getAnalytics() x-alga-products: - psa parameters: - schema: type: string format: uuid required: false name: webhook_id in: query - schema: type: string format: date-time required: false name: date_from in: query - schema: type: string format: date-time required: false name: date_to in: query responses: "200": description: Aggregated analytics returned. content: application/json: schema: $ref: "#/components/schemas/WebhookAnalyticsEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/events: get: summary: List available webhook events description: Returns the supported webhook event types from webhookEventTypeSchema (ticket.*, project.*, invoice.*, etc.). tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: read x-controller-method: ApiWebhookController.listEvents() x-alga-products: - psa responses: "200": description: Event type list. content: application/json: schema: $ref: "#/components/schemas/WebhookEventListEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/templates: get: summary: List webhook templates description: Returns webhook templates visible to the tenant (own + system templates). tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: read x-controller-method: ApiWebhookController.listTemplates() x-alga-products: - psa responses: "200": description: Template list. content: application/json: schema: $ref: "#/components/schemas/WebhookTemplateListEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" post: summary: Create webhook template description: Creates a reusable webhook template. Requires system_settings RBAC. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: system_settings x-controller-method: ApiWebhookController.createTemplate() x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WebhookTemplateBodyV1" responses: "201": description: Template created. content: application/json: schema: $ref: "#/components/schemas/WebhookTemplateEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/templates/{id}: get: summary: Get webhook template detail (webhook getById wiring) description: Template detail route delegates to ApiWebhookController.getById() and looks up rows from the webhooks table by the URL id, not webhook_templates. Calling with a true template_id will return 404. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: read x-controller-method: ApiWebhookController.getById() x-route-to-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path responses: "200": description: Webhook detail returned. content: application/json: schema: $ref: "#/components/schemas/WebhookEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" put: summary: Update webhook template (webhook update wiring) description: Template update route delegates to ApiWebhookController.update() and operates on webhooks rows, not webhook_templates. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: update x-controller-method: ApiWebhookController.update() x-route-to-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateWebhookBodyV1" responses: "200": description: Webhook updated. content: application/json: schema: $ref: "#/components/schemas/WebhookEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" delete: summary: Delete webhook template (webhook delete wiring) description: Template delete route delegates to ApiWebhookController.delete() and removes a webhooks row, not a webhook_templates row. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: delete x-controller-method: ApiWebhookController.delete() x-route-to-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path responses: "204": description: Webhook deleted. "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/templates/{id}/create: post: summary: Create webhook from template description: Instantiates a webhook configuration from a template, merging caller-supplied overrides. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: create x-controller-method: ApiWebhookController.useTemplate() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WebhookTemplateCreateBodyV1" responses: "201": description: Webhook created from template. content: application/json: schema: $ref: "#/components/schemas/WebhookEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/test: post: summary: Test webhook configuration description: Sends a one-off test delivery. Pass webhook_id to reuse stored configuration, or override_url/test_payload for ad-hoc testing. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: test x-controller-method: ApiWebhookController.test() x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WebhookTestBodyV1" responses: "200": description: Test delivery executed. content: application/json: schema: $ref: "#/components/schemas/WebhookTestResultEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/verify: post: summary: Verify webhook signature description: "Verifies an X-Alga-Signature header value against a stored signing secret. Returns { valid: true } only for sha256 with a matching v1 signature." tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: verify x-controller-method: ApiWebhookController.verifySignature() x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WebhookSignatureBodyV1" responses: "200": description: Signature verification result. content: application/json: schema: $ref: "#/components/schemas/WebhookSignatureValidationEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/{id}: get: summary: Get webhook description: Returns a single webhook by id. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: read x-controller-method: ApiWebhookController.getById() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path responses: "200": description: Webhook detail. content: application/json: schema: $ref: "#/components/schemas/WebhookEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" put: summary: Update webhook description: Updates a webhook by id. Body accepts the same fields as create, all optional. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: update x-controller-method: ApiWebhookController.update() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateWebhookBodyV1" responses: "200": description: Webhook updated. content: application/json: schema: $ref: "#/components/schemas/WebhookEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" delete: summary: Delete webhook description: Deletes a webhook by id. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: delete x-controller-method: ApiWebhookController.delete() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path responses: "204": description: Webhook deleted. "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/{id}/analytics: get: summary: Get webhook analytics description: Returns delivery analytics for a single webhook over a date window. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: analytics x-controller-method: ApiWebhookController.getWebhookAnalytics() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path - schema: type: string format: uuid required: false name: webhook_id in: query - schema: type: string format: date-time required: false name: date_from in: query - schema: type: string format: date-time required: false name: date_to in: query responses: "200": description: Per-webhook analytics returned. content: application/json: schema: $ref: "#/components/schemas/WebhookAnalyticsEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/{id}/deliveries: get: summary: List webhook deliveries description: Returns paginated delivery history for a webhook id, optionally filtered by status and date window. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: read x-controller-method: ApiWebhookController.getDeliveries() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string enum: *a127 required: false name: status in: query - schema: type: string format: date-time required: false name: from_date in: query - schema: type: string format: date-time required: false name: to_date in: query responses: "200": description: Paginated delivery list. content: application/json: schema: $ref: "#/components/schemas/WebhookDeliveryListResponseV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/{id}/deliveries/{delivery_id}: get: summary: Get delivery detail description: Returns a single delivery record (request/response payloads, status, retry pointer). tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: read x-controller-method: ApiWebhookController.getDelivery() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path - schema: type: string format: uuid description: Delivery UUID from webhook_deliveries.delivery_id (URL-derived). required: true description: Delivery UUID from webhook_deliveries.delivery_id (URL-derived). name: delivery_id in: path responses: "200": description: Delivery detail returned. content: application/json: schema: $ref: "#/components/schemas/WebhookDeliveryEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/{id}/deliveries/{delivery_id}/retry: post: summary: Retry delivery description: Re-sends a previously failed delivery and records a new attempt on the same delivery row. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: retry x-controller-method: ApiWebhookController.retryDelivery() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path - schema: type: string format: uuid description: Delivery UUID from webhook_deliveries.delivery_id (URL-derived). required: true description: Delivery UUID from webhook_deliveries.delivery_id (URL-derived). name: delivery_id in: path responses: "200": description: Retry attempted. content: application/json: schema: $ref: "#/components/schemas/WebhookDeliveryEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/{id}/health: get: summary: Get webhook health description: Derives status (healthy | failing | disabled), success_rate, and last delivery timestamps from the webhook stats counters. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: read x-controller-method: ApiWebhookController.getHealth() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path responses: "200": description: Health status returned. content: application/json: schema: $ref: "#/components/schemas/WebhookHealthEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/{id}/secret/rotate: post: summary: Rotate webhook secret description: Generates a new 32-byte base64url signing secret, persists it via webhookModel.update, and returns the secret in the response. The secret is only available at rotation time. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: manage_security x-controller-method: ApiWebhookController.rotateSecret() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path responses: "200": description: Secret rotated. content: application/json: schema: $ref: "#/components/schemas/WebhookSecretRotationEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/{id}/subscriptions: get: summary: List webhook event subscriptions description: Returns the event types the webhook is subscribed to. Subscriptions are stored on the webhooks row (event_types column), not in a separate subscription table. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: read x-controller-method: ApiWebhookController.getSubscriptions() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path responses: "200": description: Subscription list returned. content: application/json: schema: $ref: "#/components/schemas/WebhookSubscriptionsEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/webhooks/{id}/test: post: summary: Test webhook by id description: Sends a signed test delivery to the webhook URL using the stored signing secret and records the attempt in webhook_deliveries with is_test=true. tags: - Webhooks security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiWebhookController.authenticate() x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: webhook x-rbac-action: test x-controller-method: ApiWebhookController.testById() x-alga-products: - psa parameters: - schema: type: string format: uuid description: Webhook UUID from webhooks.webhook_id. required: true description: Webhook UUID from webhooks.webhook_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WebhookTestBodyV1" responses: "200": description: Test delivery executed. content: application/json: schema: $ref: "#/components/schemas/WebhookTestResultEnvelopeV1" "400": description: Invalid request payload, query, or webhook id format. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "401": description: API key missing/invalid or key user missing. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "403": description: Webhook RBAC permission denied. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "404": description: Webhook, delivery, template, or signing secret not found. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" "500": description: Unexpected webhook operation failure. content: application/json: schema: $ref: "#/components/schemas/WebhookApiErrorV1" /api/v1/workflows: get: summary: List workflows (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" post: summary: Create workflow (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/analytics: get: summary: Get workflow analytics (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/events: get: summary: List workflow events (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" post: summary: Create workflow event (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/events/{id}: get: summary: Get workflow event by id (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/executions: get: summary: List workflow executions (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" post: summary: Create workflow execution (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/executions/bulk: post: summary: Bulk create workflow executions (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/executions/bulk-action: post: summary: Bulk action workflow executions (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/executions/{id}: get: summary: Get workflow execution by id (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" put: summary: Update workflow execution (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/executions/{id}/cancel: post: summary: Cancel workflow execution (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/executions/{id}/pause: post: summary: Pause workflow execution (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/executions/{id}/restart: post: summary: Restart workflow execution (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/executions/{id}/resume: post: summary: Resume workflow execution (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/export: get: summary: Export workflows (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/import: post: summary: Import workflows (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/search: get: summary: Search workflows (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/tasks: get: summary: List workflow tasks (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" post: summary: Create workflow task (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/tasks/bulk-assign: post: summary: Bulk assign workflow tasks (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/tasks/{id}: get: summary: Get workflow task by id (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" put: summary: Update workflow task (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/tasks/{id}/claim: post: summary: Claim workflow task (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/tasks/{id}/complete: post: summary: Complete workflow task (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/templates: get: summary: List workflow templates (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" post: summary: Create workflow template (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/templates/{id}: delete: summary: Delete workflow template (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" get: summary: Get workflow template by id (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" put: summary: Update workflow template (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/workflows/{id}: delete: summary: Delete workflow by id (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" get: summary: Get workflow by id (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" put: summary: Update workflow (route inventory only) description: "This operation is currently present only in generated route inventory. No corresponding Next.js handler exists under server/src/app/api/v1/workflows in this worktree. Runtime behavior is middleware-dependent: missing/invalid x-api-key can return 401 before routing; with middleware requirements satisfied, Next.js returns not-found for the absent handler. Existing workflow APIs in this codebase are implemented under /api/workflow-definitions, /api/workflow-runs, and /api/workflow/events rather than /api/v1/workflows paths." tags: - Workflows v1 security: - ApiKeyAuth: [] extensions: x-route-inventory-only: true x-route-file-missing: server/src/app/api/v1/workflows/**/route.ts x-family-status: missing-handler x-alga-products: - psa responses: "401": description: x-api-key missing/invalid at middleware. content: application/json: schema: $ref: "#/components/schemas/WorkflowV1MissingApiError" "404": description: No route handler exists for this inventory-only /api/v1/workflows path. content: text/html: schema: $ref: "#/components/schemas/WorkflowV1MissingRouteResponse" /api/v1/projects/{id}/task-status-mappings: get: summary: List project task status mappings description: Returns the task status mappings configured for the specified project. Use this endpoint to translate a human-readable status label such as "In Progress" into a project_status_mapping_id UUID before updating a task. tags: - Projects security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: project x-chat-callable: true x-chat-display-name: List Project Task Status Mappings x-chat-rbac-resource: project x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project UUID. required: true description: Project UUID. name: id in: path responses: "200": description: Project task status mappings returned successfully. content: application/json: schema: $ref: "#/components/schemas/ProjectTaskStatusMappingListEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Project not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/projects/{id}/tasks: get: summary: List project tasks description: Returns all tasks for the specified project UUID. Use this endpoint to identify a task by task_name before fetching or updating it. tags: - Projects security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: project x-chat-callable: true x-chat-display-name: List Project Tasks x-chat-rbac-resource: project x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project UUID. required: true description: Project UUID. name: id in: path responses: "200": description: Project tasks returned successfully. content: application/json: schema: $ref: "#/components/schemas/ProjectTaskListEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Project not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/projects/{id}/phases/{phaseId}/tasks: post: summary: Create project phase task description: Creates a new task in the specified project phase. Resolve phaseId from the project phases and project_status_mapping_id from the project task status mappings before calling this endpoint. tags: - Projects security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: project x-chat-callable: true x-chat-display-name: Create Project Phase Task x-chat-rbac-resource: project x-chat-approval-required: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project UUID. required: true description: Project UUID. name: id in: path - schema: type: string format: uuid description: Project phase UUID. required: true description: Project phase UUID. name: phaseId in: path requestBody: description: Project task creation payload. required: true content: application/json: schema: $ref: "#/components/schemas/ProjectTaskCreateRequest" description: Project task creation payload. responses: "201": description: Project task created successfully. content: application/json: schema: $ref: "#/components/schemas/ProjectTaskEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Project or phase not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: List project phase tasks description: Returns all tasks for the specified project phase. Both id and phaseId must be UUID path parameters. tags: - Projects security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: project x-chat-callable: true x-chat-display-name: List Project Phase Tasks x-chat-rbac-resource: project x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project UUID. required: true description: Project UUID. name: id in: path - schema: type: string format: uuid description: Project phase UUID. required: true description: Project phase UUID. name: phaseId in: path responses: "200": description: Project phase tasks returned successfully. content: application/json: schema: $ref: "#/components/schemas/ProjectTaskListEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Project phase not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/projects/tasks/{taskId}: get: summary: Get project task description: Returns a single project task by its task UUID. tags: - Projects security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: project x-chat-callable: true x-chat-display-name: Get Project Task x-chat-rbac-resource: project x-chat-approval-required: false x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project task UUID. required: true description: Project task UUID. name: taskId in: path responses: "200": description: Project task returned successfully. content: application/json: schema: $ref: "#/components/schemas/ProjectTaskEnvelope" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Project task not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Update project task description: Updates a project task by task UUID. Use project_status_mapping_id when changing task status, and only send fields defined in the request schema. tags: - Projects security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: project x-chat-callable: true x-chat-display-name: Update Project Task x-chat-rbac-resource: project x-chat-approval-required: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project task UUID. required: true description: Project task UUID. name: taskId in: path requestBody: description: Project task update payload. required: true content: application/json: schema: $ref: "#/components/schemas/ProjectTaskUpdateRequest" description: Project task update payload. responses: "200": description: Project task updated successfully. content: application/json: schema: $ref: "#/components/schemas/ProjectTaskEnvelope" "400": description: Validation error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks the required permission. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Project task not found. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: summary: Delete project task description: Permanently deletes a project task by task UUID. The controller resolves the task's parent project through project_tasks.phase_id and project_phases.project_id, checks project:delete permission, and verifies row-level read access to that project before deleting the task. Returns 204 No Content on success. tags: - Projects security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: project x-chat-callable: true x-chat-display-name: Delete Project Task x-chat-rbac-resource: project x-chat-approval-required: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project task UUID. required: true description: Project task UUID. name: taskId in: path responses: "204": description: Project task deleted successfully. "401": description: Authentication failed. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Authenticated user lacks project delete permission or row-level access to the parent project. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Project task not found, or its parent project could not be resolved. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/projects: get: summary: List projects description: Lists projects using ApiProjectController.list() with authorization-aware pagination. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create project description: Creates a project via ApiProjectController.create(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1CreateProjectBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/bulk-assign: put: summary: Bulk assign projects description: Bulk assignment operation via ApiProjectController.bulkAssign(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/bulk-status: put: summary: Bulk update project status description: Bulk status update operation via ApiProjectController.bulkStatusUpdate(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/bulk-update: put: summary: Bulk update projects description: Bulk update operation via ApiProjectController.bulkUpdate(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/export: get: summary: Export projects description: Exports projects via ApiProjectController.export(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/search: get: summary: Search projects description: Searches projects via ApiProjectController.search(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/stats: get: summary: Get project stats description: Returns project aggregate statistics for authorized projects. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/tasks/{taskId}/checklist: get: summary: List task checklist items description: Reads checklist items for project task UUID through ApiProjectController.getTaskChecklist(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project task UUID from project_tasks.task_id. required: true description: Project task UUID from project_tasks.task_id. name: taskId in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create task checklist item description: Creates checklist item for project task UUID via ApiProjectController.createChecklistItem(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project task UUID from project_tasks.task_id. required: true description: Project task UUID from project_tasks.task_id. name: taskId in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/{id}: delete: summary: Delete project description: Deletes project by project UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" get: summary: Get project description: Returns one project by project UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" put: summary: Update project description: Updates project by project UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/{id}/phases: get: summary: List project phases description: Lists phases for project UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create project phase description: Creates a project phase under project UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/{id}/phases/{phaseId}: delete: summary: Delete project phase description: Deletes phase UUID under project UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project UUID from projects.project_id. required: true description: Project UUID from projects.project_id. name: id in: path - schema: type: string format: uuid description: Project phase UUID from project_phases.phase_id. required: true description: Project phase UUID from project_phases.phase_id. name: phaseId in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" put: summary: Update project phase description: Updates phase UUID under project UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: Project UUID from projects.project_id. required: true description: Project UUID from projects.project_id. name: id in: path - schema: type: string format: uuid description: Project phase UUID from project_phases.phase_id. required: true description: Project phase UUID from project_phases.phase_id. name: phaseId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/projects/{id}/tickets: get: summary: List project tickets description: Lists tickets linked to project UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: project x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for project resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/schedules: get: summary: List schedule entries description: Lists schedule entries via ApiTimeSheetController.listScheduleEntries(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create schedule entry description: Creates schedule entry via ApiTimeSheetController.createScheduleEntry(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/schedules/search: get: summary: Search schedules description: Current route delegates to ApiTimeSheetController.list() (time sheet list path), not schedule-specific search. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/schedules/{id}: delete: summary: Delete schedule entry description: Deletes schedule entry via ApiTimeSheetController.deleteScheduleEntry(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" get: summary: Get schedule entry description: Current route delegates to ApiTimeSheetController.getById() (time sheet read path), not schedule-specific getter. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" put: summary: Update schedule entry description: Updates schedule entry via ApiTimeSheetController.updateScheduleEntry(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/schedules/{id}/conflicts: get: summary: Get schedule conflicts description: Current route delegates to ApiTimeSheetController.list() rather than conflict-specific schedule logic. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags: get: summary: List tags description: Lists tags via ApiTagController.list(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create tag description: Creates a tag via ApiTagController.create(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1CreateTagBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/analytics: get: summary: Get tag analytics description: Returns tag analytics aggregation payload. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/bulk: delete: summary: Bulk delete tags description: Bulk delete tag operation. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Bulk create tags description: Bulk create tag operation. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/bulk/merge: post: summary: Bulk merge tags description: Bulk merge tags into target tag. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/bulk/tag: post: summary: Bulk tag entities description: Bulk add tags to entities. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/bulk/untag: delete: summary: Bulk untag entities description: Bulk remove tags from entities. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/by-text: delete: summary: Delete tags by text description: Deletes tags matching text criteria. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/cloud: get: summary: Get tag cloud description: Returns weighted tag cloud data. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/entity/{entityType}/{entityId}: delete: summary: Remove tags from entity description: Removes tag set from entity route params/body. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string description: Tagged entity type from route segment. required: true description: Tagged entity type from route segment. name: entityType in: path - schema: type: string description: Tagged entity id from route segment. required: true description: Tagged entity id from route segment. name: entityId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" get: summary: List tags for entity description: Lists tags attached to entity route params. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string description: Tagged entity type from route segment. required: true description: Tagged entity type from route segment. name: entityType in: path - schema: type: string description: Tagged entity id from route segment. required: true description: Tagged entity id from route segment. name: entityId in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Attach tags to entity description: Adds tags to entity route params/body. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string description: Tagged entity type from route segment. required: true description: Tagged entity type from route segment. name: entityType in: path - schema: type: string description: Tagged entity id from route segment. required: true description: Tagged entity id from route segment. name: entityId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/search: get: summary: Search tags description: Searches tags via ApiTagController.search(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/{id}: delete: summary: Delete tag description: Deletes tag UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" get: summary: Get tag description: Gets tag UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" put: summary: Update tag description: Updates tag UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/{id}/colors: put: summary: Update tag colors description: Updates tag color attributes. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tags/{id}/text: put: summary: Update tag text description: Updates tag display text. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: tag x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for tag resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets: get: summary: List tickets description: Lists tickets via ApiTicketController.list() with authorization-aware pagination. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create ticket description: Creates ticket via ApiTicketController.create(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1CreateTicketBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/from-asset: post: summary: Create ticket from asset description: Creates ticket from asset context via ApiTicketController.createFromAsset(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" get: summary: Create ticket from asset (POST only) description: This path creates a ticket from an asset via POST. GET is not supported and returns 405 Method Not Allowed. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: read x-method-not-allowed: true x-alga-products: - psa responses: "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "405": description: Method not allowed; use POST to create a ticket from an asset. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/search: get: summary: Search tickets description: Searches tickets via ApiTicketController.search(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/stats: get: summary: Get ticket stats description: Returns ticket aggregate stats for authorized tickets. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}: delete: summary: Delete ticket description: Deletes ticket UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "409": description: "Deletion blocked: the resource has dependent records that must be removed or reassigned first. The error details list the blocking dependencies." content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" get: summary: Get ticket description: Gets ticket UUID with authorization check. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" put: summary: Update ticket description: Updates ticket UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/assignment: put: summary: Update ticket assignment description: Updates ticket assignment target. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/comments: get: summary: List ticket comments description: Lists comments for ticket UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Add ticket comment description: Adds comment to ticket UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/status: put: summary: Update ticket status description: Updates status for ticket UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/time-entries: get: summary: List ticket time entries description: Returns the caller's time entries on the ticket plus, when permitted, other team members' entries (or an anonymized aggregate when the caller lacks timesheet:read_all). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/bundle: get: summary: Get ticket bundle description: "Returns bundle membership for the ticket: role (master, child, or standalone), the master ticket, child tickets, and bundle settings." tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create ticket bundle description: Bundles the given child tickets under ticket {id} as the master, with a sync mode of link_only or sync_updates. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" delete: summary: Unbundle ticket description: Unbundles master {id}, detaching all child tickets and removing bundle settings. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/bundle/children: post: summary: Add bundle children description: Adds child tickets to the existing bundle mastered by {id}. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/bundle/children/{childId}: delete: summary: Remove bundle child description: Removes child {childId} from its bundle; removes bundle settings when no children remain. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/bundle/promote: post: summary: Promote bundle master description: Promotes a child ticket to be the new bundle master, re-pointing the remaining children. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/bundle/settings: put: summary: Update ticket bundle settings description: Updates the bundle mode and/or reopen-on-child-reply policy for master {id}. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: ticket x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries: get: summary: List time entries description: Lists time entries via ApiBaseController list flow. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create time entry description: Creates time entry. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1CreateTimeEntryBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/active-session: get: summary: Get active tracking session description: Returns active tracking session for current user context. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/approve: post: summary: Approve time entries description: Approves time entries payload. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/bulk: delete: summary: Bulk delete time entries description: Bulk delete time entry operation. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Bulk create time entries description: Bulk create time entry operation. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" put: summary: Bulk update time entries description: Bulk update time entry operation. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/export: get: summary: Export time entries description: Exports time entries with optional filter/format query. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/request-changes: post: summary: Request time entry changes description: Requests changes for submitted time entries. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/search: get: summary: Search time entries description: Searches time entries with controller-specific filters. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/start-tracking: post: summary: Start time tracking description: Starts active tracking session. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/stats: get: summary: Get time entry stats description: Returns time entry statistics. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/stop-tracking/{sessionId}: post: summary: Stop time tracking description: Stops active tracking session by session id. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string description: Active time-tracking session identifier. required: true description: Active time-tracking session identifier. name: sessionId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/templates: get: summary: List time entry templates description: Lists available time entry templates. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-entries/{id}: delete: summary: Delete time entry description: Deletes time entry UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" get: summary: Get time entry description: Gets time entry UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" put: summary: Update time entry description: Updates time entry UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_entry x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_entry resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-periods: get: summary: List time periods description: Lists time periods via ApiTimeSheetController.listTimePeriods(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create time period description: Creates time period via ApiTimeSheetController.createTimePeriod(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-periods/current: get: summary: Get current time period description: Current route delegates to ApiTimeSheetController.list() and does not call a dedicated current-period method. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-periods/{id}: delete: summary: Delete time period description: Deletes time period UUID via deleteTimePeriod(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" get: summary: Get time period description: Gets time period UUID via getTimePeriod(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" put: summary: Update time period description: Updates time period UUID via updateTimePeriod(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-periods/{id}/close: post: summary: Close time period description: Current route delegates to ApiTimeSheetController.update() (time sheet update flow), not dedicated time-period close logic. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-periods/{id}/reopen: post: summary: Reopen time period description: Current route delegates to ApiTimeSheetController.update() (time sheet update flow), not dedicated time-period reopen logic. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets: get: summary: List time sheets description: Lists time sheets via ApiTimeSheetController.list(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Create time sheet description: Creates time sheet via create() path. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1CreateTimeSheetBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/bulk: post: summary: Bulk time sheet operation description: Current route delegates to ApiTimeSheetController.list() (read path) instead of bulk approval/update logic. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/export: get: summary: Export time sheets description: Exports time sheets using ApiTimeSheetController.export(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/search: get: summary: Search time sheets description: Current route delegates to ApiTimeSheetController.list() rather than search(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}: delete: summary: Delete time sheet description: Deletes time sheet UUID via ApiBase delete path. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" get: summary: Get time sheet description: Gets time sheet UUID with details via getWithDetails(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" put: summary: Update time sheet description: Updates time sheet UUID. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}/add-entry: post: summary: Add time sheet entry description: Current route delegates to ApiTimeSheetController.create() (time sheet create path), not entry-add-specific logic. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}/approve: post: summary: Approve time sheet description: Approves time sheet UUID via approve(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}/entries: get: summary: List time sheet entries description: Current route delegates to ApiTimeSheetController.list() rather than a per-sheet entries reader. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}/reject: post: summary: Reject time sheet description: Current route delegates to ApiTimeSheetController.update() instead of reject-specific flow. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}/remove-entry: delete: summary: Remove time sheet entry description: Current route delegates to ApiTimeSheetController.delete() instead of entry-remove-specific flow. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "204": description: Delete-like operation can return no content when implemented that way. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}/request-changes: post: summary: Request time sheet changes description: Requests changes via requestChanges(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}/reverse-approval: post: summary: Reverse time sheet approval description: Reverses approval via reverseApproval(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}/submit: post: summary: Submit time sheet description: Submits time sheet for approval via submit(). tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1GenericBody" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/time-sheets/{id}/summary: get: summary: Get time sheet summary description: Current route delegates to ApiTimeSheetController.list() instead of summary-specific computation. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or controller-specific equivalent x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: time_sheet x-route-controller-mismatch: true x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a128 required: false name: order in: query - schema: type: string required: false name: fields in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: query in: query responses: "200": description: Collection response returned. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiPaginated" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for time_sheet resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Target resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/priorities: get: summary: List ticket priorities description: Returns the tenant ticket priorities (item_type=ticket), ordered by name. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: read x-alga-products: - psa - algadesk responses: "200": description: Ticket priorities. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/statuses: get: summary: List ticket statuses description: Returns board-owned ticket statuses for the tenant, optionally filtered by board_id, sorted by board then order_number. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Filter statuses to this board. required: false description: Filter statuses to this board. name: board_id in: query responses: "200": description: Ticket statuses. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/comments/{commentId}: put: summary: Update a ticket comment description: Updates the text of a comment on a ticket. Comment text must be 1–5000 visible characters. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: update x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Ticket UUID. required: true description: Ticket UUID. name: id in: path - schema: type: string format: uuid description: Comment UUID. required: true description: Comment UUID. name: commentId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1TicketCommentUpdateBody" responses: "200": description: Updated comment. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Ticket or sub-resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/comments/{commentId}/reactions: post: summary: Toggle a comment reaction description: "Adds or removes the given emoji reaction on a comment for the authenticated user. Returns { added: boolean } indicating whether the reaction was added (true) or removed (false)." tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Ticket UUID. required: true description: Ticket UUID. name: id in: path - schema: type: string format: uuid description: Comment UUID. required: true description: Comment UUID. name: commentId in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1TicketReactionBody" responses: "200": description: Reaction toggled. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Ticket or sub-resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/documents: get: summary: List ticket documents description: Returns the documents (file attachments) associated with a ticket. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Ticket documents. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Ticket or sub-resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Upload a ticket document description: Uploads a file as a document attachment to a ticket. Send multipart/form-data with a `file` field. Returns the created document. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: update x-request-content-type: multipart/form-data x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "201": description: Document uploaded. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Ticket or sub-resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/documents/{documentId}: get: summary: Download a ticket document description: Downloads a specific document attached to a ticket as binary data with Content-Type and Content-Disposition headers. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: read x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Ticket UUID. required: true description: Ticket UUID. name: id in: path - schema: type: string format: uuid description: Document UUID. required: true description: Document UUID. name: documentId in: path responses: "200": description: Binary document stream (Content-Disposition attachment). content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Document not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" delete: summary: Delete a ticket document description: Removes a document from a ticket. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: update x-alga-products: - psa - algadesk parameters: - schema: type: string format: uuid description: Ticket UUID. required: true description: Ticket UUID. name: id in: path - schema: type: string format: uuid description: Document UUID. required: true description: Document UUID. name: documentId in: path responses: "200": description: Document removed. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Ticket or sub-resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/tickets/{id}/materials: get: summary: List ticket materials description: Returns the materials (service items/supplies) recorded against a ticket. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: read x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path responses: "200": description: Ticket materials. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Ticket or sub-resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" post: summary: Add a ticket material description: Associates a service item (material/supply) with a ticket, specifying quantity, rate, and currency. Returns the created material. tags: - Work Management v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: ticket x-rbac-action: update x-alga-products: - psa parameters: - schema: type: string format: uuid description: UUID path identifier from underlying resource tables. required: true description: UUID path identifier from underlying resource tables. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkV1TicketMaterialBody" responses: "201": description: Material added. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiSuccess" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "401": description: API key missing/invalid. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "403": description: RBAC denied for ticket resource action. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "404": description: Ticket or sub-resource not found. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/WorkV1ApiError" /api/v1/quotes: get: summary: List quotes description: Lists quotes via ApiQuoteController.list() with authorization-aware filtering. tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a129 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: status in: query - schema: type: string enum: *a130 required: false name: include_items in: query - schema: type: string enum: *a131 required: false name: include_client in: query responses: "200": description: Paginated quotes returned. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiPaginatedV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" post: summary: Create quote description: Creates quote via ApiQuoteController.create(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a129 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: status in: query - schema: type: string enum: *a130 required: false name: include_items in: query - schema: type: string enum: *a131 required: false name: include_client in: query requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateQuoteBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}: get: summary: Get quote description: Gets quote UUID via ApiQuoteController.getById(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" put: summary: Update quote description: Updates quote UUID via ApiQuoteController.update(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" delete: summary: Delete quote description: Deletes quote UUID via ApiQuoteController.delete(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "204": description: Delete-like operation can return no content. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/activities: get: summary: List quote activities description: Lists quote activity history via listActivities(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/approve: post: summary: Approve quote description: Approves quote pending-approval state via approve(); includes self-approval guard. tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/convert: post: summary: Convert quote description: Converts quote to downstream entities via convert(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/convert/preview: get: summary: Preview quote conversion description: Returns conversion preview via conversionPreview(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/items: get: summary: List quote items description: Lists quote items via listItems(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" post: summary: Add quote item description: Adds quote item via addItem(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/items/{itemId}: put: summary: Update quote item description: Updates quote item via updateItem(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" delete: summary: Delete quote item description: Deletes quote item via deleteItem(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "204": description: Delete-like operation can return no content. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/items/reorder: post: summary: Reorder quote items description: Reorders quote item sequence via reorderItems(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/remind: post: summary: Send quote reminder description: Sends reminder for quote via remind(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/request-changes: post: summary: Request quote changes description: Requests changes on pending-approval quote via requestChanges(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/resend: post: summary: Resend quote description: Resends quote via resend(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/revisions: get: summary: List quote revisions description: Lists quote versions via listVersions(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" post: summary: Create quote revision description: Creates quote revision via createRevision(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/send: post: summary: Send quote description: Sends quote to recipient workflow via send(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/quotes/{id}/submit-for-approval: post: summary: Submit quote for approval description: Moves quote to pending-approval state via submitForApproval(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: quote x-read-authorization-resource: billing x-alga-products: - psa parameters: - schema: type: string format: uuid description: Quote UUID from quotes.quote_id. required: true description: Quote UUID from quotes.quote_id. name: id in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/QuotesContractsGenericBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for quote resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/contracts: get: summary: List contracts description: Lists contracts via ApiContractLineController.listContracts() (v2 controller mounted under v1 route). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: contract_line x-controller-origin: ApiContractLineController (v2) mounted under v1 routes x-request-context-wiring-gap: Controller requires req.context via requireRequestContext(req); v1 route lacks explicit withApiKeyAuth wrapper. x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a129 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: status in: query - schema: type: string enum: *a130 required: false name: include_items in: query - schema: type: string enum: *a131 required: false name: include_client in: query responses: "200": description: Paginated contracts returned. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiPaginatedV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for contract resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" post: summary: Create contract description: Creates contract via ApiContractLineController.createContract() (v2 controller mounted under v1 route). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: contract_line x-controller-origin: ApiContractLineController (v2) mounted under v1 routes x-request-context-wiring-gap: Controller requires req.context via requireRequestContext(req); v1 route lacks explicit withApiKeyAuth wrapper. x-alga-products: - psa parameters: - schema: type: string required: false name: page in: query - schema: type: string required: false name: limit in: query - schema: type: string required: false name: sort in: query - schema: type: string enum: *a129 required: false name: order in: query - schema: type: string required: false name: search in: query - schema: type: string required: false name: status in: query - schema: type: string enum: *a130 required: false name: include_items in: query - schema: type: string enum: *a131 required: false name: include_client in: query requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateContractBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for contract resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/contracts/{contractId}/contract-lines: post: summary: Attach contract line description: Attaches contract line to contract via addContractLine() using body contract_line_id/custom_rate. tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: contract_line x-controller-origin: ApiContractLineController (v2) mounted under v1 routes x-request-context-wiring-gap: Controller requires req.context via requireRequestContext(req); v1 route lacks explicit withApiKeyAuth wrapper. x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract UUID from contracts.contract_id. required: true description: Contract UUID from contracts.contract_id. name: contractId in: path requestBody: required: true content: application/json: schema: type: object properties: contract_line_id: type: string format: uuid custom_rate: type: number required: - contract_line_id responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "201": description: Create-like operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for contract resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/contracts/{contractId}/contract-lines/{contractLineId}: delete: summary: Detach contract line description: Detaches contract line from contract via removeContractLine(). tags: - Quotes & Contracts v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: x-api-key validated in ApiBaseController.authenticate() or route middleware before handler x-tenant-header: x-tenant-id (optional; inferred from API key when omitted) x-rbac-resource: contract_line x-controller-origin: ApiContractLineController (v2) mounted under v1 routes x-request-context-wiring-gap: Controller requires req.context via requireRequestContext(req); v1 route lacks explicit withApiKeyAuth wrapper. x-alga-products: - psa parameters: - schema: type: string format: uuid description: Contract UUID from contracts.contract_id. required: true description: Contract UUID from contracts.contract_id. name: contractId in: path responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiSuccessV1" "204": description: Delete-like operation can return no content. "400": description: Validation or request parsing failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "401": description: API key missing/invalid or associated user missing. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "403": description: RBAC denied for contract resource action. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "404": description: Target record not found. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" "500": description: Unexpected controller/service failure. content: application/json: schema: $ref: "#/components/schemas/QuotesContractsApiErrorV1" /api/v1/feature-access: post: summary: Check feature access description: Checks feature access via ApiPermissionController.checkFeatureAccess() using API key auth and permission read checks. tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: permission x-auth-mechanism: x-api-key validated by ApiPermissionController.authenticate() x-tenant-header: x-tenant-id (optional) x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FeatureAccessBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/feature-flags: get: summary: Get feature flags description: Returns feature flags for current session user; route uses getSession() and featureFlags service. tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: Session user required in handler; global /api middleware may still require x-api-key presence x-tenant-header: x-tenant-id (optional) x-session-auth-required: true x-alga-products: - psa parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" post: summary: Evaluate feature flags with custom context description: Evaluates requested/all flags with optional custom context payload; requires session user. tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: Session user required in handler; global /api middleware may still require x-api-key presence x-tenant-header: x-tenant-id (optional) x-session-auth-required: true x-alga-products: - psa requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FeatureFlagsPostBodyV1" responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/meta/docs: get: summary: Get API docs description: Returns Swagger UI HTML or redirects to OpenAPI endpoint depending on format query. tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: metadata x-auth-mechanism: ApiMetadataController.authenticate() + metadata read permission x-tenant-header: x-tenant-id (optional) x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Swagger UI HTML or JSON redirect payload. content: text/html: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "302": description: Redirect to /api/v1/meta/openapi for non-html format. "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/meta/endpoints: get: summary: List API endpoints metadata description: Returns endpoint inventory metadata via ApiMetadataController.getEndpoints(). tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: metadata x-auth-mechanism: ApiMetadataController.authenticate() + metadata read permission x-tenant-header: x-tenant-id (optional) x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/meta/health: get: summary: Get API health metadata description: Returns API health metadata via ApiMetadataController.getHealth(). tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: metadata x-auth-mechanism: ApiMetadataController.authenticate() + metadata read permission x-tenant-header: x-tenant-id (optional) x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/meta/openapi: get: summary: Get generated OpenAPI metadata description: Returns generated OpenAPI document JSON/YAML based on query format. tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: metadata x-auth-mechanism: ApiMetadataController.authenticate() + metadata read permission x-tenant-header: x-tenant-id (optional) x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/meta/permissions: get: summary: List API permissions metadata description: Returns permission metadata via ApiMetadataController.getPermissions(). tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: metadata x-auth-mechanism: ApiMetadataController.authenticate() + metadata read permission x-tenant-header: x-tenant-id (optional) x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/meta/schemas: get: summary: List API schemas metadata description: Returns schema metadata via ApiMetadataController.getSchemas(). tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: metadata x-auth-mechanism: ApiMetadataController.authenticate() + metadata read permission x-tenant-header: x-tenant-id (optional) x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/meta/sdk: get: summary: Generate SDK metadata payload description: Generates SDK structure payload for selected language/format via generateSdk(). tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: metadata x-auth-mechanism: ApiMetadataController.authenticate() + metadata read permission x-tenant-header: x-tenant-id (optional) x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/meta/stats: get: summary: Get API stats metadata description: Returns API usage stats for requested period via getStats(). tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: metadata x-auth-mechanism: ApiMetadataController.authenticate() + metadata read permission x-tenant-header: x-tenant-id (optional) x-alga-products: - psa - algadesk parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/test-auth: get: summary: Test API key auth description: Debug endpoint wrapping withApiKeyAuth middleware; returns only non-sensitive authenticated context identifiers. tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-rbac-resource: auth x-auth-mechanism: withApiKeyAuth from apiAuthMiddleware x-tenant-header: x-tenant-id (optional) x-alga-products: - psa parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/user/telemetry-decision: get: summary: Get telemetry decision description: Returns telemetry enabled/disabled decision from environment for current session user. tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: Session user required in handler; global /api middleware may still require x-api-key presence x-tenant-header: x-tenant-id (optional) x-session-auth-required: true x-alga-products: - psa parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/v1/user/telemetry-preferences: get: summary: Get telemetry preferences description: Read-only. Returns the usage-stats telemetry state, which is controlled by the ALGA_USAGE_STATS environment variable (not per-user); requires session user. There are no write verbs because the preference cannot be changed through the API. tags: - Meta & Utility v1 security: - ApiKeyAuth: [] extensions: x-tenant-scoped: true x-auth-mechanism: Session user required in handler; global /api middleware may still require x-api-key presence x-tenant-header: x-tenant-id (optional) x-session-auth-required: true x-alga-products: - psa parameters: - schema: type: string required: false name: format in: query - schema: type: string required: false name: flags in: query - schema: type: string required: false name: period in: query - schema: type: string required: false name: language in: query - schema: type: string required: false name: package_name in: query - schema: type: string required: false name: version in: query responses: "200": description: Operation succeeded. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiSuccessV1" "400": description: Invalid request payload/query. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "401": description: Unauthorized (API key/session auth failure depending on route). content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "403": description: Permission denied. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" "500": description: Unexpected route/controller failure. content: application/json: schema: $ref: "#/components/schemas/MetaUtilityApiErrorV1" /api/extensions/softwareone/agreements: get: summary: List SoftwareOne agreements description: Returns SoftwareOne agreement records available to the SoftwareOne extension. The current handler is an MVP placeholder backed by hardcoded dummy data; comments in the route indicate that a full implementation will validate permissions, derive tenant context, fetch from the SoftwareOne API, and apply filtering, sorting, and pagination. This route is not in the middleware API-key skip list, so callers must provide x-api-key at the API layer. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension: softwareone x-alga-products: - psa responses: "200": description: Agreement list returned successfully. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneAgreementsListResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while fetching agreements. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" post: summary: Sync SoftwareOne agreements description: Triggers the SoftwareOne agreements sync placeholder. The current handler parses the JSON body but ignores all fields, then returns a dummy count. A full implementation is expected to validate permissions, derive tenant context, call the SoftwareOne API, persist agreements, and return actual sync counts. This route is not in the middleware API-key skip list, so callers must provide x-api-key at the API layer. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension: softwareone x-alga-products: - psa requestBody: description: Optional sync options. Currently ignored by the MVP handler. required: true content: application/json: schema: $ref: "#/components/schemas/SoftwareOneSyncRequest" description: Optional sync options. Currently ignored by the MVP handler. responses: "200": description: Agreements sync placeholder completed successfully. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneSyncResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while syncing agreements. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/softwareone/agreements/{id}: get: summary: Get SoftwareOne agreement description: Returns one SoftwareOne agreement by external agreement ID, including additional detail fields such as dates, payment terms, contact, and license count. The current handler is an MVP placeholder backed by hardcoded dummy data. The id path parameter is a SoftwareOne-style string such as agr-001, not an Alga UUID. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension: softwareone x-alga-products: - psa parameters: - schema: type: string description: SoftwareOne external identifier, such as agr-001 or stmt-001. This is not an Alga UUID. required: true description: SoftwareOne external identifier, such as agr-001 or stmt-001. This is not an Alga UUID. name: id in: path responses: "200": description: Agreement detail returned successfully. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneAgreementDetailResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "404": description: Agreement not found. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" "500": description: Unexpected failure while fetching agreement detail. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/softwareone/statements: get: summary: List SoftwareOne statements description: Returns SoftwareOne billing statement records available to the SoftwareOne extension. The current handler is an MVP placeholder backed by hardcoded dummy data; comments in the route indicate that a full implementation will validate permissions, derive tenant context, fetch from the SoftwareOne API, and apply filtering, sorting, and pagination. This route is not in the middleware API-key skip list, so callers must provide x-api-key at the API layer. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension: softwareone x-alga-products: - psa responses: "200": description: Statement list returned successfully. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneStatementsListResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while fetching statements. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" post: summary: Sync SoftwareOne statements description: Triggers the SoftwareOne statements sync placeholder. The current handler parses the JSON body but ignores all fields, then returns a dummy count. A full implementation is expected to validate permissions, derive tenant context, call the SoftwareOne API, persist statements, and return actual sync counts. This route is not in the middleware API-key skip list, so callers must provide x-api-key at the API layer. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension: softwareone x-alga-products: - psa requestBody: description: Optional sync options. Currently ignored by the MVP handler. required: true content: application/json: schema: $ref: "#/components/schemas/SoftwareOneSyncRequest" description: Optional sync options. Currently ignored by the MVP handler. responses: "200": description: Statements sync placeholder completed successfully. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneSyncResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while syncing statements. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/softwareone/statements/{id}: get: summary: Get SoftwareOne statement description: Returns one SoftwareOne billing statement by external statement ID, including additional detail fields such as subtotal, tax amount, description, and billing address. The current handler is an MVP placeholder backed by hardcoded dummy data. The id path parameter is a SoftwareOne-style string such as stmt-001, not an Alga UUID. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension: softwareone x-alga-products: - psa parameters: - schema: type: string description: SoftwareOne external identifier, such as agr-001 or stmt-001. This is not an Alga UUID. required: true description: SoftwareOne external identifier, such as agr-001 or stmt-001. This is not an Alga UUID. name: id in: path responses: "200": description: Statement detail returned successfully. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneStatementDetailResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "404": description: Statement not found. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" "500": description: Unexpected failure while fetching statement detail. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/softwareone/statements/{id}/charges: get: summary: List SoftwareOne statement charges description: Returns line-item charges for a SoftwareOne billing statement. The current handler is an MVP placeholder backed by hardcoded dummy data keyed by SoftwareOne statement IDs such as stmt-001. Unknown statement IDs return 200 with an empty data array rather than 404. The id path parameter is not an Alga UUID. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension: softwareone x-alga-products: - psa parameters: - schema: type: string description: SoftwareOne external identifier, such as agr-001 or stmt-001. This is not an Alga UUID. required: true description: SoftwareOne external identifier, such as agr-001 or stmt-001. This is not an Alga UUID. name: id in: path responses: "200": description: Charge list returned successfully. Data may be empty when the statement ID is unknown. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneChargesListResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while fetching statement charges. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/softwareone/sync: post: summary: Sync SoftwareOne data description: Triggers the SoftwareOne aggregate sync placeholder. The current handler accepts optional syncAgreements and syncStatements booleans, waits briefly to simulate work, and returns dummy counts and a syncedAt timestamp. A full implementation will validate permissions, derive tenant context, connect to the SoftwareOne API, and persist agreement and statement data. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension: softwareone x-alga-products: - psa requestBody: description: Sync options. The current sync endpoint consumes syncAgreements and syncStatements; unknown fields are ignored. required: false content: application/json: schema: $ref: "#/components/schemas/SoftwareOneSyncRequest" description: Sync options. The current sync endpoint consumes syncAgreements and syncStatements; unknown fields are ignored. responses: "200": description: Sync placeholder completed successfully with dummy counts. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneFullSyncResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while syncing SoftwareOne data. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/{extensionId}/agreements: get: summary: List agreements for extension description: Generic extension agreements placeholder. The current handler accepts any extensionId, performs no handler-level extension validation, and returns hardcoded SoftwareOne-style agreement data with meta.extensionId echoed from the path. A full implementation will validate the extension ID, check permissions, derive tenant context, and fetch extension-specific data. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension-scoped: true x-alga-products: - psa parameters: - schema: type: string description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. required: true description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. name: extensionId in: path responses: "200": description: Agreement list returned successfully for the requested extension placeholder. content: application/json: schema: $ref: "#/components/schemas/GenericExtensionAgreementsListResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while fetching extension agreements. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/{extensionId}/agreements/{id}: get: summary: Get agreement for extension description: Generic extension agreement detail placeholder. The current handler accepts any extensionId, looks up an agreement by SoftwareOne-style external ID such as agr-001, and returns hardcoded detail data with meta.extensionId echoed from the path. The id path parameter is not an Alga UUID. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension-scoped: true x-alga-products: - psa parameters: - schema: type: string description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. required: true description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. name: extensionId in: path - schema: type: string description: SoftwareOne-style external record identifier, such as agr-001 or stmt-001. This is not an Alga UUID. required: true description: SoftwareOne-style external record identifier, such as agr-001 or stmt-001. This is not an Alga UUID. name: id in: path responses: "200": description: Agreement detail returned successfully for the requested extension placeholder. content: application/json: schema: $ref: "#/components/schemas/GenericExtensionAgreementDetailResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "404": description: Agreement not found. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" "500": description: Unexpected failure while fetching extension agreement detail. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/{extensionId}/statements: get: summary: List statements for extension description: Generic extension statements placeholder. The current handler accepts any extensionId, performs no handler-level extension validation, and returns hardcoded SoftwareOne-style statement data with meta.extensionId echoed from the path. A full implementation will validate the extension ID, check permissions, derive tenant context, and fetch extension-specific data. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension-scoped: true x-alga-products: - psa parameters: - schema: type: string description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. required: true description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. name: extensionId in: path responses: "200": description: Statement list returned successfully for the requested extension placeholder. content: application/json: schema: $ref: "#/components/schemas/GenericExtensionStatementsListResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while fetching extension statements. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/{extensionId}/statements/{id}: get: summary: Get statement for extension description: Generic extension statement detail placeholder. The current handler accepts any extensionId, looks up a statement by SoftwareOne-style external ID such as stmt-001, and returns hardcoded detail data with meta.extensionId echoed from the path. The id path parameter is not an Alga UUID. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension-scoped: true x-alga-products: - psa parameters: - schema: type: string description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. required: true description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. name: extensionId in: path - schema: type: string description: SoftwareOne-style external record identifier, such as agr-001 or stmt-001. This is not an Alga UUID. required: true description: SoftwareOne-style external record identifier, such as agr-001 or stmt-001. This is not an Alga UUID. name: id in: path responses: "200": description: Statement detail returned successfully for the requested extension placeholder. content: application/json: schema: $ref: "#/components/schemas/GenericExtensionStatementDetailResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "404": description: Statement not found. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" "500": description: Unexpected failure while fetching extension statement detail. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/{extensionId}/statements/{id}/charges: get: summary: List charges for extension statement description: Generic extension statement charges placeholder. The current handler accepts any extensionId, returns hardcoded charge data keyed by SoftwareOne-style statement IDs such as stmt-001, and echoes extensionId in response metadata. Unknown statement IDs return 200 with an empty data array rather than 404. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension-scoped: true x-alga-products: - psa parameters: - schema: type: string description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. required: true description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. name: extensionId in: path - schema: type: string description: SoftwareOne-style external record identifier, such as agr-001 or stmt-001. This is not an Alga UUID. required: true description: SoftwareOne-style external record identifier, such as agr-001 or stmt-001. This is not an Alga UUID. name: id in: path responses: "200": description: Charge list returned successfully. Data may be empty when the statement ID is unknown. content: application/json: schema: $ref: "#/components/schemas/GenericExtensionChargesListResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while fetching extension statement charges. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/extensions/{extensionId}/sync: post: summary: Sync extension data description: Generic extension sync placeholder. The current handler accepts any extensionId and optional syncAgreements and syncStatements booleans, simulates work, and returns dummy agreement and statement counts with meta extensionId in the response data. A full implementation will validate extension identity, check permissions, derive tenant context, call the extension-specific backend, and persist data. tags: - SoftwareOne Extensions security: - ApiKeyAuth: [] extensions: x-placeholder-implementation: true x-extension-scoped: true x-alga-products: - psa parameters: - schema: type: string description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. required: true description: Extension identifier from the URL. The MVP generic routes accept any value and echo it in response metadata. name: extensionId in: path requestBody: description: "Optional sync flags consumed by the MVP handler: syncAgreements and syncStatements." required: false content: application/json: schema: $ref: "#/components/schemas/SoftwareOneSyncRequest" description: "Optional sync flags consumed by the MVP handler: syncAgreements and syncStatements." responses: "200": description: Generic extension sync placeholder completed successfully with dummy counts. content: application/json: schema: $ref: "#/components/schemas/GenericExtensionSyncResponse" "401": description: API key missing at middleware before the handler executes. content: application/json: schema: $ref: "#/components/schemas/MiddlewareUnauthorizedResponse" "500": description: Unexpected failure while syncing extension data. content: application/json: schema: $ref: "#/components/schemas/SoftwareOneErrorResponse" /api/accounting/csv/export: post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/csv/import/tax: post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/csv/import/tax/history: get: summary: GET accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/csv/import/tax/rollback/{importId}: post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/csv/import/tax/template: get: summary: GET accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/exports: get: summary: GET accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/exports/locks/invoice/reset: post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/exports/preview: post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/exports/{batchId}: get: summary: GET accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" patch: summary: PATCH accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/exports/{batchId}/download: post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/exports/{batchId}/errors: post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/exports/{batchId}/execute: post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/accounting/exports/{batchId}/lines: post: summary: POST accounting description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - accounting extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/e2e/google/authorize: get: summary: GET auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/e2e/google/complete: get: summary: GET auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/e2e/google/token: post: summary: POST auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/e2e/google/userinfo: get: summary: GET auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/google/calendar/callback: get: summary: GET auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/microsoft/calendar/callback: get: summary: GET auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/microsoft/entra/callback: get: summary: GET auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/msp/remember-email: post: summary: POST auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/msp/sso/discover: post: summary: POST auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/msp/sso/resolve: post: summary: POST auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/sessions: delete: summary: DELETE auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: GET auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/sessions/all: get: summary: GET auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/auth/sessions/{sessionId}: delete: summary: DELETE auth description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - auth extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/billing/check-tenant: get: summary: GET billing description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - billing extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/calendar/appointment/{id}: get: summary: GET calendar description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - calendar extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/calendar/webhooks/google: get: summary: GET calendar description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - calendar extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS calendar description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - calendar extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST calendar description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - calendar extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/calendar/webhooks/microsoft: get: summary: GET calendar description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - calendar extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS calendar description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - calendar extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST calendar description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - calendar extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/chat/v1/completions: post: summary: POST chat description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - chat extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/chat/v1/completions/stream: post: summary: POST chat description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - chat extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/chat/v1/execute: post: summary: POST chat description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - chat extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/client-portal/domain-session: options: summary: OPTIONS client-portal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - client-portal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST client-portal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - client-portal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/clients: get: summary: GET clients description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - clients extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/documents/{documentId}/content: get: summary: GET documents description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - documents extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/documents/{documentId}/preview: get: summary: GET documents description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - documents extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/documents/{documentId}/thumbnail: get: summary: GET documents description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - documents extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/email/imap/reconnect: post: summary: POST email description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - email extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa - algadesk requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/email/imap/resync: post: summary: POST email description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - email extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa - algadesk requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/email/oauth/imap/callback: get: summary: GET email description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - email extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa - algadesk responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/email/oauth/imap/initiate: post: summary: POST email description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - email extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa - algadesk requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/email/webhooks/imap: post: summary: POST email description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - email extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/email/webhooks/resend: post: summary: POST email description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - email extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/ext-bundles/abort: post: summary: POST ext-bundles description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-bundles extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/ext-bundles/finalize: post: summary: POST ext-bundles description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-bundles extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/ext-bundles/upload-proxy: post: summary: POST ext-bundles description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-bundles extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/ext-debug/stream: get: summary: GET ext-debug description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-debug extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST ext-debug description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-debug extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/ext-proxy/{extensionId}/{path}: delete: summary: DELETE ext-proxy description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-proxy extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: GET ext-proxy description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-proxy extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" patch: summary: PATCH ext-proxy description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-proxy extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST ext-proxy description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-proxy extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: PUT ext-proxy description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - ext-proxy extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/import/approve: post: summary: POST import description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - import extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/import/details: get: summary: GET import description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - import extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/import/history: get: summary: GET import description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - import extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/import/mapping: get: summary: GET import description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - import extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/import/preview: post: summary: POST import description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - import extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/import/sources: get: summary: GET import description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - import extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra: get: summary: GET integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/connect: options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/disconnect: options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/discovery: options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/mappings/confirm: options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/mappings/preview: get: summary: GET integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/mappings/remap: options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/mappings/unmap: options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/sync: options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/sync/runs: get: summary: GET integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/sync/runs/{runId}: get: summary: GET integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/validate-cipp: options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/entra/validate-direct: options: summary: OPTIONS integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/ninjaone/callback: get: summary: GET integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/xero/callback: get: summary: GET integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/integrations/xero/connect: get: summary: GET integrations description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - integrations extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/internal/check-tenant-email: post: summary: POST internal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - internal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/internal/collab/persist: post: summary: POST internal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - internal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/internal/ext-clients/install/{installId}: post: summary: POST internal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - internal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/internal/ext-invoicing/install/{installId}: post: summary: POST internal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - internal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/internal/ext-runner/install-config: post: summary: POST internal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - internal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/internal/ext-scheduler/install/{installId}: post: summary: POST internal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - internal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/internal/ext-services/install/{installId}: post: summary: POST internal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - internal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/internal/ext-storage/install/{installId}: post: summary: POST internal description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - internal extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/online-meetings/recordings/{artifactId}: get: summary: GET online-meetings description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - online-meetings extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/public/appointment-request: post: summary: POST public description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - public extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/public/appointment-request/available-dates: get: summary: GET public description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - public extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/public/appointment-request/available-services: get: summary: GET public description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - public extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/public/appointment-request/available-slots: get: summary: GET public description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - public extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/secrets: get: summary: GET secrets description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - secrets extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST secrets description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - secrets extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/secrets/{name}: delete: summary: DELETE secrets description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - secrets extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: GET secrets description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - secrets extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" head: summary: HEAD secrets description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - secrets extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" patch: summary: PATCH secrets description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - secrets extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/share/{token}: get: summary: GET share description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - share extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/share/{token}/info: get: summary: GET share description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - share extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/teams/auth/callback/bot: get: summary: GET teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/teams/auth/callback/message-extension: get: summary: GET teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/teams/auth/callback/tab: get: summary: GET teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/teams/bot/messages: options: summary: OPTIONS teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/teams/message-extension/query: options: summary: OPTIONS teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/teams/package: get: summary: GET teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/teams/package/download: get: summary: GET teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/teams/quick-actions: options: summary: OPTIONS teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/teams/webhooks/recordings: get: summary: GET teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST teams description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - teams extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/tickets/{id}/live-token: get: summary: GET tickets description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tickets extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/account/delete: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/auth/apple: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/auth/apple/link: delete: summary: DELETE v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/auth/apple/notifications: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/auth/capabilities: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/auth/exchange: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/auth/refresh: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/auth/revoke: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/iap/check-email: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/iap/notifications: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/iap/provision: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/iap/restore: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/moderation/mutes: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/moderation/mutes/{userId}: delete: summary: DELETE v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/moderation/report: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mobile/push-token: delete: summary: DELETE v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: PUT v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - mobile extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-feature-flags: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-feature-flags/{flagId}: delete: summary: DELETE v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" patch: summary: PATCH v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-feature-flags/{flagId}/tenants: options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-feature-flags extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-notifications: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-notifications/resolve-recipients: options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-notifications/{notificationId}: delete: summary: DELETE v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: PUT v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-notifications/{notificationId}/reads: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-notifications/{notificationId}/stats: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-notifications extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-reports: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-reports/access: options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-reports/audit: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-reports/schema: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-reports/{reportId}: delete: summary: DELETE v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "204": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: PUT v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/platform-reports/{reportId}/execute: options: summary: OPTIONS v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - platform-reports extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/storage/namespaces/{namespace}/records: get: summary: List records in a namespace tags: - Storage security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: storage x-chat-callable: true x-chat-display-name: List Storage Records x-chat-rbac-resource: storage x-chat-approval-required: false x-edition: CE x-alga-products: - psa parameters: - schema: type: string minLength: 1 maxLength: 128 required: true name: namespace in: path - schema: type: integer minimum: 1 maximum: 100 required: false name: limit in: query - schema: type: string required: false name: cursor in: query - schema: type: string maxLength: 256 required: false name: keyPrefix in: query - schema: type: boolean required: false name: includeValues in: query - schema: type: boolean required: false name: includeMetadata in: query responses: "200": description: List of records content: application/json: schema: $ref: "#/components/schemas/StorageListResponse" "400": description: Validation error content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: Bulk insert or update records tags: - Storage security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: storage x-chat-callable: true x-chat-display-name: Upsert Storage Records x-chat-rbac-resource: storage x-chat-approval-required: true x-edition: CE x-alga-products: - psa parameters: - schema: type: string minLength: 1 maxLength: 128 required: true name: namespace in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/StorageBulkPutRequest" responses: "200": description: Bulk operation result content: application/json: schema: $ref: "#/components/schemas/StorageBulkPutResponse" "400": description: Validation error content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Revision mismatch content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "429": description: Quota exceeded content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/storage/namespaces/{namespace}/records/{key}: delete: summary: Delete a record by key tags: - Storage security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: storage x-edition: CE x-alga-products: - psa parameters: - schema: type: string minLength: 1 maxLength: 128 required: true name: namespace in: path - schema: type: string minLength: 1 maxLength: 256 required: true name: key in: path - schema: type: - integer - "null" minimum: 0 required: false name: ifRevision in: query responses: "204": description: Record deleted "400": description: Validation error content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: summary: Get a record by key tags: - Storage security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: storage x-chat-callable: true x-chat-display-name: Get Storage Record x-chat-rbac-resource: storage x-chat-approval-required: false x-edition: CE x-alga-products: - psa parameters: - schema: type: string minLength: 1 maxLength: 128 required: true name: namespace in: path - schema: type: string minLength: 1 maxLength: 256 required: true name: key in: path - schema: type: string required: false name: if-revision-match in: header responses: "200": description: Record content: application/json: schema: $ref: "#/components/schemas/StorageGetResponse" "400": description: Validation error content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Revision mismatch content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: summary: Create or update a record by key tags: - Storage security: - ApiKeyAuth: [] extensions: x-tenant-header-required: true x-rbac-resource: storage x-chat-callable: true x-chat-display-name: Put Storage Record x-chat-rbac-resource: storage x-chat-approval-required: true x-edition: CE x-alga-products: - psa parameters: - schema: type: string minLength: 1 maxLength: 128 required: true name: namespace in: path - schema: type: string minLength: 1 maxLength: 256 required: true name: key in: path requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/StoragePutRequest" responses: "200": description: Updated record content: application/json: schema: $ref: "#/components/schemas/StoragePutResponse" "400": description: Validation error content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Revision mismatch content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "429": description: Quota exceeded content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/addons: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/audit: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/confirm-deletion: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/create-tenant: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/export-tenant: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/exports: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/exports/{exportId}/download-url: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/pending-deletions: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/resend-welcome-email: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/rollback-deletion: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/start-deletion: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/start-premium-trial: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/tenants: get: summary: GET v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/tenant-management/tenants/{tenantId}/addons: post: summary: POST v1 description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - tenant-management extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/webhooks/ninjaone: get: summary: GET webhooks description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - webhooks extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" options: summary: OPTIONS webhooks description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - webhooks extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST webhooks description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - webhooks extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/webhooks/stripe: post: summary: POST webhooks description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - webhooks extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/webhooks/stripe/payments: post: summary: POST webhooks description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - webhooks extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/webhooks/tacticalrmm: options: summary: OPTIONS webhooks description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - webhooks extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa responses: "200": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: summary: POST webhooks description: This operation was generated automatically from the route inventory. Replace with canonical OpenAPI metadata. tags: - webhooks extensions: x-generated-from: docs/openapi/route-inventory.json x-placeholder: true x-alga-products: - psa requestBody: description: Placeholder request body required: true content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" description: Placeholder request body responses: "201": description: Placeholder success response content: application/json: schema: $ref: "#/components/schemas/PlaceholderObject" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" webhooks: ticket.created: post: summary: "Outbound delivery: ticket.created" description: Emitted when a ticket is first created. `data.changes` and `data.comment` are not included on this event. Delivered with HMAC-SHA256 signature header X-Alga-Signature, and the X-Alga-* metadata headers. Retried with backoff (1m, 5m, 30m, 2h, 12h) before being abandoned. tags: - Webhooks extensions: x-alga-event-type: ticket.created x-rbac-resource: webhook x-alga-products: - psa parameters: - schema: type: string description: "`t=,v1=` over `${timestamp}.${raw_body}`." required: true description: "`t=,v1=` over `${timestamp}.${raw_body}`." name: x-alga-signature in: header - schema: type: string format: uuid required: true name: x-alga-webhook-id in: header - schema: type: string format: uuid required: true name: x-alga-event-id in: header - schema: $ref: "#/components/schemas/WebhookEventTypeV1" required: true name: x-alga-event-type in: header - schema: type: string format: uuid required: true name: x-alga-delivery-id in: header - schema: type: string description: Stringified attempt count, starts at 1. required: true description: Stringified attempt count, starts at 1. name: x-alga-delivery-attempt in: header requestBody: description: Signed JSON envelope. required: true content: application/json: schema: $ref: "#/components/schemas/TicketCreatedDeliveryV1" description: Signed JSON envelope. responses: "200": description: Endpoint accepted the delivery (any 2xx is treated as success). "410": description: Endpoint indicates the resource is permanently gone; webhook will be auto-disabled. ticket.updated: post: summary: "Outbound delivery: ticket.updated" description: Emitted when a ticket is updated. `data.changes` is a record keyed by changed field name with `{previous, new}` entries. Delivered with HMAC-SHA256 signature header X-Alga-Signature, and the X-Alga-* metadata headers. Retried with backoff (1m, 5m, 30m, 2h, 12h) before being abandoned. tags: - Webhooks extensions: x-alga-event-type: ticket.updated x-rbac-resource: webhook x-alga-products: - psa parameters: - schema: type: string description: "`t=,v1=` over `${timestamp}.${raw_body}`." required: true description: "`t=,v1=` over `${timestamp}.${raw_body}`." name: x-alga-signature in: header - schema: type: string format: uuid required: true name: x-alga-webhook-id in: header - schema: type: string format: uuid required: true name: x-alga-event-id in: header - schema: $ref: "#/components/schemas/WebhookEventTypeV1" required: true name: x-alga-event-type in: header - schema: type: string format: uuid required: true name: x-alga-delivery-id in: header - schema: type: string description: Stringified attempt count, starts at 1. required: true description: Stringified attempt count, starts at 1. name: x-alga-delivery-attempt in: header requestBody: description: Signed JSON envelope. required: true content: application/json: schema: $ref: "#/components/schemas/TicketUpdatedDeliveryV1" description: Signed JSON envelope. responses: "200": description: Endpoint accepted the delivery (any 2xx is treated as success). "410": description: Endpoint indicates the resource is permanently gone; webhook will be auto-disabled. ticket.status_changed: post: summary: "Outbound delivery: ticket.status_changed" description: Emitted when a ticket status changes. `data.previous_status_id` / `previous_status_name` are populated. Delivered with HMAC-SHA256 signature header X-Alga-Signature, and the X-Alga-* metadata headers. Retried with backoff (1m, 5m, 30m, 2h, 12h) before being abandoned. tags: - Webhooks extensions: x-alga-event-type: ticket.status_changed x-rbac-resource: webhook x-alga-products: - psa parameters: - schema: type: string description: "`t=,v1=` over `${timestamp}.${raw_body}`." required: true description: "`t=,v1=` over `${timestamp}.${raw_body}`." name: x-alga-signature in: header - schema: type: string format: uuid required: true name: x-alga-webhook-id in: header - schema: type: string format: uuid required: true name: x-alga-event-id in: header - schema: $ref: "#/components/schemas/WebhookEventTypeV1" required: true name: x-alga-event-type in: header - schema: type: string format: uuid required: true name: x-alga-delivery-id in: header - schema: type: string description: Stringified attempt count, starts at 1. required: true description: Stringified attempt count, starts at 1. name: x-alga-delivery-attempt in: header requestBody: description: Signed JSON envelope. required: true content: application/json: schema: $ref: "#/components/schemas/TicketStatusChangedDeliveryV1" description: Signed JSON envelope. responses: "200": description: Endpoint accepted the delivery (any 2xx is treated as success). "410": description: Endpoint indicates the resource is permanently gone; webhook will be auto-disabled. ticket.assigned: post: summary: "Outbound delivery: ticket.assigned" description: Emitted when a ticket assignment changes (assigned_to or assigned_team_id). Delivered with HMAC-SHA256 signature header X-Alga-Signature, and the X-Alga-* metadata headers. Retried with backoff (1m, 5m, 30m, 2h, 12h) before being abandoned. tags: - Webhooks extensions: x-alga-event-type: ticket.assigned x-rbac-resource: webhook x-alga-products: - psa parameters: - schema: type: string description: "`t=,v1=` over `${timestamp}.${raw_body}`." required: true description: "`t=,v1=` over `${timestamp}.${raw_body}`." name: x-alga-signature in: header - schema: type: string format: uuid required: true name: x-alga-webhook-id in: header - schema: type: string format: uuid required: true name: x-alga-event-id in: header - schema: $ref: "#/components/schemas/WebhookEventTypeV1" required: true name: x-alga-event-type in: header - schema: type: string format: uuid required: true name: x-alga-delivery-id in: header - schema: type: string description: Stringified attempt count, starts at 1. required: true description: Stringified attempt count, starts at 1. name: x-alga-delivery-attempt in: header requestBody: description: Signed JSON envelope. required: true content: application/json: schema: $ref: "#/components/schemas/TicketAssignedDeliveryV1" description: Signed JSON envelope. responses: "200": description: Endpoint accepted the delivery (any 2xx is treated as success). "410": description: Endpoint indicates the resource is permanently gone; webhook will be auto-disabled. ticket.closed: post: summary: "Outbound delivery: ticket.closed" description: Emitted when a ticket transitions to a closed status. `data.is_closed` is true and `data.closed_at` is set. Delivered with HMAC-SHA256 signature header X-Alga-Signature, and the X-Alga-* metadata headers. Retried with backoff (1m, 5m, 30m, 2h, 12h) before being abandoned. tags: - Webhooks extensions: x-alga-event-type: ticket.closed x-rbac-resource: webhook x-alga-products: - psa parameters: - schema: type: string description: "`t=,v1=` over `${timestamp}.${raw_body}`." required: true description: "`t=,v1=` over `${timestamp}.${raw_body}`." name: x-alga-signature in: header - schema: type: string format: uuid required: true name: x-alga-webhook-id in: header - schema: type: string format: uuid required: true name: x-alga-event-id in: header - schema: $ref: "#/components/schemas/WebhookEventTypeV1" required: true name: x-alga-event-type in: header - schema: type: string format: uuid required: true name: x-alga-delivery-id in: header - schema: type: string description: Stringified attempt count, starts at 1. required: true description: Stringified attempt count, starts at 1. name: x-alga-delivery-attempt in: header requestBody: description: Signed JSON envelope. required: true content: application/json: schema: $ref: "#/components/schemas/TicketClosedDeliveryV1" description: Signed JSON envelope. responses: "200": description: Endpoint accepted the delivery (any 2xx is treated as success). "410": description: Endpoint indicates the resource is permanently gone; webhook will be auto-disabled. ticket.comment.added: post: summary: "Outbound delivery: ticket.comment.added" description: Emitted when a comment is added to a ticket. `data.comment` carries the new comment block; attachments are never included. Delivered with HMAC-SHA256 signature header X-Alga-Signature, and the X-Alga-* metadata headers. Retried with backoff (1m, 5m, 30m, 2h, 12h) before being abandoned. tags: - Webhooks extensions: x-alga-event-type: ticket.comment.added x-rbac-resource: webhook x-alga-products: - psa parameters: - schema: type: string description: "`t=,v1=` over `${timestamp}.${raw_body}`." required: true description: "`t=,v1=` over `${timestamp}.${raw_body}`." name: x-alga-signature in: header - schema: type: string format: uuid required: true name: x-alga-webhook-id in: header - schema: type: string format: uuid required: true name: x-alga-event-id in: header - schema: $ref: "#/components/schemas/WebhookEventTypeV1" required: true name: x-alga-event-type in: header - schema: type: string format: uuid required: true name: x-alga-delivery-id in: header - schema: type: string description: Stringified attempt count, starts at 1. required: true description: Stringified attempt count, starts at 1. name: x-alga-delivery-attempt in: header requestBody: description: Signed JSON envelope. required: true content: application/json: schema: $ref: "#/components/schemas/TicketCommentAddedDeliveryV1" description: Signed JSON envelope. responses: "200": description: Endpoint accepted the delivery (any 2xx is treated as success). "410": description: Endpoint indicates the resource is permanently gone; webhook will be auto-disabled.