openapi: 3.1.0 info: title: SnapOtter API version: 1.15.9 description: | REST API for SnapOtter, a self-hosted image processing platform with 48 tools. ## Authentication Most endpoints require authentication via one of two methods: 1. **Session cookie** — Call `POST /api/auth/login` with username and password. The response includes a `token` field. Pass it as `Authorization: Bearer ` on subsequent requests. 2. **API key** — Generate a key via the Settings UI or `POST /api/v1/api-keys`. Keys are prefixed with `si_`. Pass as `Authorization: Bearer si_...`. Endpoints marked with a lock icon require authentication. Admin-only endpoints are noted in their description. license: name: AGPL-3.0 url: https://github.com/snapotter-hq/snapotter/blob/main/LICENSE servers: - url: / description: Current instance tags: - name: Tools description: Image processing tools. Each accepts a multipart file upload and returns a download URL. - name: Batch description: Process multiple images through a tool in one request. - name: Pipelines description: Chain multiple tools into reusable workflows. - name: Files description: Upload, download, and manage processed images. - name: Auth description: Login, logout, session management, and user administration. - name: API Keys description: Create and manage API keys for programmatic access. - name: Settings description: System-wide configuration (admin only for writes). - name: Teams description: Organize users into teams. - name: Roles description: Custom role management with fine-grained permissions. - name: Audit description: Audit log for tracking administrative actions. - name: Analytics description: Analytics configuration and user consent. - name: Features description: AI feature bundle installation and management. - name: Admin description: Administrative health diagnostics. - name: System description: Health checks, configuration, and job progress. components: securitySchemes: bearerAuth: type: http scheme: bearer description: Session token from login or API key (prefixed with si_) schemas: Error: type: object required: [error] properties: error: type: string example: Invalid image format details: type: string description: Additional error details (e.g. Zod validation errors) ToolResponse: type: object properties: jobId: type: string description: Unique job identifier downloadUrl: type: string description: URL to download the processed image example: /api/v1/download/abc123/output.png originalSize: type: integer description: Original file size in bytes processedSize: type: integer description: Processed file size in bytes previewUrl: type: string description: URL to a WebP preview (present when output is not browser-previewable, e.g. TIFF, HEIF) savedFileId: type: string description: ID of the auto-saved file in the library (present when fileId was provided in the request) UnauthorizedError: type: object properties: statusCode: type: integer example: 401 error: type: string example: Unauthorized message: type: string example: Authentication required ForbiddenError: type: object properties: statusCode: type: integer example: 403 error: type: string example: Forbidden message: type: string example: Insufficient permissions ConflictError: type: object properties: statusCode: type: integer example: 409 error: type: string example: Conflict message: type: string example: Resource already exists FeatureNotInstalledError: type: object properties: error: type: string example: Feature not installed code: type: string example: FEATURE_NOT_INSTALLED feature: type: string description: Feature bundle identifier featureName: type: string description: Human-readable feature name estimatedSize: type: string description: Estimated download size HealthResponse: type: object properties: status: type: string enum: [healthy, degraded] version: type: string uptime: type: string database: type: string enum: [ok, error] AdminHealthResponse: type: object properties: status: type: string enum: [healthy, degraded] version: type: string uptime: type: string storage: type: object properties: mode: type: string available: type: string database: type: string enum: [ok, error] queue: type: object properties: active: type: integer pending: type: integer ai: type: object properties: gpu: type: boolean security: - bearerAuth: [] paths: /api/v1/health: get: tags: [System] summary: Health check description: Returns server health status. Used by Docker HEALTHCHECK. Public endpoint. security: [] responses: "200": description: Server health content: application/json: schema: $ref: "#/components/schemas/HealthResponse" /api/v1/tools/resize: post: tags: [Tools] summary: Resize description: Resize an image to specific dimensions or by percentage. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `width` (number, optional) — Target width in pixels - `height` (number, optional) — Target height in pixels - `fit` (string, default "contain") — One of: contain, cover, fill, inside, outside - `withoutEnlargement` (boolean, default false) — Prevent upscaling - `percentage` (number, optional) — Scale by percentage instead of fixed dimensions responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/content-aware-resize: post: tags: [Tools] summary: Content-aware resize description: Resize an image using seam carving to intelligently remove or insert content while preserving important features. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `width` (number, optional) — Target width in pixels - `height` (number, optional) — Target height in pixels - `protectFaces` (boolean, default false) — Detect and protect faces from distortion - `blurRadius` (number 0-20, default 4) — Blur radius for energy map - `sobelThreshold` (number 1-20, default 2) — Edge detection threshold - `square` (boolean, default false) — Crop to square aspect ratio At least one of `width`, `height`, or `square` must be provided. responses: "200": description: Processed image content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: width: type: integer height: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/crop: post: tags: [Tools] summary: Crop description: Crop an image to a specific region. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `left` (number, required) — Left offset in pixels (min 0) - `top` (number, required) — Top offset in pixels (min 0) - `width` (number, required) — Width of crop region in pixels - `height` (number, required) — Height of crop region in pixels - `unit` (string, optional) — One of: px, percent responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/rotate: post: tags: [Tools] summary: Rotate and flip description: Rotate an image by angle or flip horizontally/vertically. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `angle` (number, default 0) — Rotation angle in degrees - `horizontal` (boolean, default false) — Flip horizontally - `vertical` (boolean, default false) — Flip vertically responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/convert: post: tags: [Tools] summary: Convert format description: Convert an image to a different format. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `format` (string, required) — One of: jpg, png, webp, avif, tiff, gif, heic, heif - `quality` (number 1-100, optional) — Output quality responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/compress: post: tags: [Tools] summary: Compress description: Reduce image file size by quality level or target size. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `mode` (string, default "quality") — One of: quality, targetSize - `quality` (number 1-100, optional) — Compression quality level - `targetSizeKb` (number, optional) — Target file size in kilobytes responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/strip-metadata: post: tags: [Tools] summary: Strip metadata description: Remove EXIF, GPS, ICC, or XMP metadata from an image. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `stripExif` (boolean, default false) — Remove EXIF data - `stripGps` (boolean, default false) — Remove GPS data - `stripIcc` (boolean, default false) — Remove ICC profile - `stripXmp` (boolean, default false) — Remove XMP data - `stripAll` (boolean, default true) — Remove all metadata responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/border: post: tags: [Tools] summary: Border and frame description: Add a border, rounded corners, padding, or shadow to an image. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `borderWidth` (number 0-2000, default 10) — Border thickness in pixels - `borderColor` (hex string, default "#000000") — Border color - `padding` (number 0-200, default 0) — Inner padding in pixels - `paddingColor` (hex string, default "#FFFFFF") — Padding fill color - `cornerRadius` (number 0-2000, default 0) — Corner rounding radius - `shadow` (boolean, default false) — Enable drop shadow - `shadowBlur` (number 1-200, default 15) — Drop shadow blur radius - `shadowOffsetX` (number -50 to 50, default 0) — Shadow horizontal offset - `shadowOffsetY` (number -50 to 50, default 5) — Shadow vertical offset - `shadowColor` (hex string, default "#000000") — Drop shadow color - `shadowOpacity` (number 0-100, default 40) — Shadow opacity percentage responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/adjust-colors: post: tags: [Tools] summary: Color adjustments description: | Consolidated color adjustment tool. Adjusts brightness, contrast, exposure, saturation, temperature, tint, hue, sharpness, color channels, and effects in a single pass. This is the primary color adjustment endpoint; the brightness-contrast, saturation, color-channels, and color-effects endpoints are aliases that accept the same settings schema. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `brightness` (number -100 to 100, default 0) - Brightness adjustment - `contrast` (number -100 to 100, default 0) - Contrast adjustment - `exposure` (number -100 to 100, default 0) - Exposure adjustment (gamma) - `saturation` (number -100 to 100, default 0) - Color saturation - `temperature` (number -100 to 100, default 0) - Color temperature (cool to warm) - `tint` (number -100 to 100, default 0) - Tint shift (green to magenta) - `hue` (number -180 to 180, default 0) - Hue rotation in degrees - `sharpness` (number 0 to 100, default 0) - Sharpness enhancement - `red` (number 0-200, default 100) - Red channel multiplier - `green` (number 0-200, default 100) - Green channel multiplier - `blue` (number 0-200, default 100) - Blue channel multiplier - `effect` (string, default "none") - One of: none, grayscale, sepia, invert responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/brightness-contrast: post: tags: [Tools] summary: Brightness and contrast description: Adjust brightness, contrast, saturation, color channels, and effects. Alias for adjust-colors. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `brightness` (number -100 to 100, default 0) — Brightness adjustment - `contrast` (number -100 to 100, default 0) — Contrast adjustment - `saturation` (number -100 to 100, default 0) — Saturation adjustment - `exposure` (number -100 to 100, default 0) — Exposure adjustment - `temperature` (number -100 to 100, default 0) — Color temperature - `tint` (number -100 to 100, default 0) — Tint adjustment - `hue` (number -180 to 180, default 0) — Hue rotation - `sharpness` (number 0 to 100, default 0) — Sharpness - `red` (number 0-200, default 100) — Red channel multiplier - `green` (number 0-200, default 100) — Green channel multiplier - `blue` (number 0-200, default 100) — Blue channel multiplier - `effect` (string, default "none") — One of: none, grayscale, sepia, invert responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/saturation: post: tags: [Tools] summary: Saturation and exposure description: Adjust color saturation and exposure settings. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `brightness` (number -100 to 100, default 0) — Brightness adjustment - `contrast` (number -100 to 100, default 0) — Contrast adjustment - `saturation` (number -100 to 100, default 0) — Saturation adjustment - `exposure` (number -100 to 100, default 0) — Exposure adjustment - `temperature` (number -100 to 100, default 0) — Color temperature - `tint` (number -100 to 100, default 0) — Tint adjustment - `hue` (number -180 to 180, default 0) — Hue rotation - `sharpness` (number 0 to 100, default 0) — Sharpness - `red` (number 0-200, default 100) — Red channel multiplier - `green` (number 0-200, default 100) — Green channel multiplier - `blue` (number 0-200, default 100) — Blue channel multiplier - `effect` (string, default "none") — One of: none, grayscale, sepia, invert responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/color-channels: post: tags: [Tools] summary: Color channels description: Adjust individual RGB color channels. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `brightness` (number -100 to 100, default 0) — Brightness adjustment - `contrast` (number -100 to 100, default 0) — Contrast adjustment - `saturation` (number -100 to 100, default 0) — Saturation adjustment - `exposure` (number -100 to 100, default 0) — Exposure adjustment - `temperature` (number -100 to 100, default 0) — Color temperature - `tint` (number -100 to 100, default 0) — Tint adjustment - `hue` (number -180 to 180, default 0) — Hue rotation - `sharpness` (number 0 to 100, default 0) — Sharpness - `red` (number 0-200, default 100) — Red channel multiplier - `green` (number 0-200, default 100) — Green channel multiplier - `blue` (number 0-200, default 100) — Blue channel multiplier - `effect` (string, default "none") — One of: none, grayscale, sepia, invert responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/color-effects: post: tags: [Tools] summary: Color effects description: Apply color effects like grayscale, sepia, or invert. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `brightness` (number -100 to 100, default 0) — Brightness adjustment - `contrast` (number -100 to 100, default 0) — Contrast adjustment - `saturation` (number -100 to 100, default 0) — Saturation adjustment - `exposure` (number -100 to 100, default 0) — Exposure adjustment - `temperature` (number -100 to 100, default 0) — Color temperature - `tint` (number -100 to 100, default 0) — Tint adjustment - `hue` (number -180 to 180, default 0) — Hue rotation - `sharpness` (number 0 to 100, default 0) — Sharpness - `red` (number 0-200, default 100) — Red channel multiplier - `green` (number 0-200, default 100) — Green channel multiplier - `blue` (number 0-200, default 100) — Blue channel multiplier - `effect` (string, default "none") — One of: none, grayscale, sepia, invert responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/sharpening: post: tags: [Tools] summary: Sharpening description: Sharpen an image using adaptive, unsharp mask, or high-pass methods with optional noise reduction. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `method` (string, default "adaptive") - One of: adaptive, unsharp-mask, high-pass - `sigma` (number 0.5-10, default 1.0) - Gaussian sigma (adaptive) - `m1` (number 0-10, default 1.0) - Flat area sharpening (adaptive) - `m2` (number 0-20, default 3.0) - Jagged area sharpening (adaptive) - `x1` (number 0-10, default 2.0) - Flat/jagged threshold (adaptive) - `y2` (number 0-50, default 12) - Maximum brightening (adaptive) - `y3` (number 0-50, default 20) - Maximum darkening (adaptive) - `amount` (number 0-1000, default 100) - Sharpen amount (unsharp-mask) - `radius` (number 0.1-5, default 1.0) - Blur radius (unsharp-mask) - `threshold` (number 0-255, default 0) - Luminance threshold (unsharp-mask) - `strength` (number 0-100, default 50) - Blend strength (high-pass) - `kernelSize` (integer, default 3) - One of: 3, 5 (high-pass) - `denoise` (string, default "off") - One of: off, light, medium, strong responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/optimize-for-web: post: tags: [Tools] summary: Optimize for web description: Optimize an image for web delivery by converting to modern formats, adjusting quality, and optionally resizing. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `format` (string, default "webp") - One of: webp, jpeg, avif, png - `quality` (number 1-100, default 80) - Output quality - `maxWidth` (number, optional) - Maximum width in pixels - `maxHeight` (number, optional) - Maximum height in pixels - `progressive` (boolean, default true) - Enable progressive encoding - `stripMetadata` (boolean, default true) - Remove metadata responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/optimize-for-web/preview: post: tags: [Tools] summary: Optimize for web (preview) description: | Lightweight preview endpoint for live parameter tuning. Returns the optimized image binary directly (not JSON). Size information is in response headers. Does not create a workspace or persist results. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to preview settings: type: string description: Same settings as the main optimize-for-web endpoint responses: "200": description: Optimized image binary headers: X-Original-Size: schema: type: string description: Original file size in bytes X-Processed-Size: schema: type: string description: Processed file size in bytes X-Output-Filename: schema: type: string description: Suggested output filename content: image/*: schema: type: string format: binary "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/image-enhancement: post: tags: [Tools] summary: Image enhancement description: | AI-powered automatic image enhancement. Analyzes the image and applies corrections for exposure, contrast, white balance, saturation, sharpness, and noise based on the selected scene mode. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `mode` (string, default "auto") - One of: auto, portrait, landscape, low-light, food, document - `intensity` (number 0-100, default 50) - Overall enhancement intensity - `corrections` (object, optional) - Toggle individual corrections: - `exposure` (boolean, default true) - `contrast` (boolean, default true) - `whiteBalance` (boolean, default true) - `saturation` (boolean, default true) - `sharpness` (boolean, default true) - `denoise` (boolean, default true) responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/image-enhancement/analyze: post: tags: [Tools] summary: Analyze image for enhancement description: | Analyze an image and return suggested corrections without applying them. Useful for previewing what enhancements would be made. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to analyze responses: "200": description: Image analysis with suggested corrections content: application/json: schema: type: object properties: corrections: type: object description: Suggested correction values metrics: type: object description: Image quality metrics "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "422": description: Analysis failed content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/noise-removal: post: tags: [Tools] summary: Noise removal description: | AI-powered noise removal using the Python sidecar. Supports multiple quality tiers from quick preview to maximum quality. Requires the noise-removal feature bundle to be installed. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `tier` (string, default "balanced") - One of: quick, balanced, quality, maximum - `strength` (number, default 50) - Denoising strength - `detailPreservation` (number, default 50) - Detail preservation level - `colorNoise` (number, default 30) - Color noise reduction - `format` (string, default "original") - One of: original, png, jpeg, webp, avif - `quality` (number, default 90) - Output quality (1-100) clientJobId: type: string description: Client-provided job ID for SSE progress tracking responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/red-eye-removal: post: tags: [Tools] summary: Red-eye removal description: | AI-powered red-eye detection and removal. Detects faces and corrects red-eye artifacts in photographs. Requires the red-eye-removal feature bundle to be installed. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `sensitivity` (number 0-100, default 50) - Detection sensitivity - `strength` (number 0-100, default 70) - Correction strength - `format` (string, optional) - Output format - `quality` (number 1-100, default 90) - Output quality clientJobId: type: string description: Client-provided job ID for SSE progress tracking responses: "200": description: Processed image with correction details content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: facesDetected: type: integer description: Number of faces detected eyesCorrected: type: integer description: Number of eyes corrected "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/restore-photo: post: tags: [Tools] summary: Photo restoration description: | AI-powered photo restoration pipeline. Repairs scratches, enhances faces, denoises, and optionally colorizes old or damaged photographs. Requires the photo-restoration feature bundle to be installed. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `mode` (string, default "auto") - One of: auto, light, heavy - `scratchRemoval` (boolean, default true) - Enable scratch repair - `faceEnhancement` (boolean, default true) - Enhance detected faces - `fidelity` (number 0-1, default 0.7) - Face enhancement fidelity - `denoise` (boolean, default true) - Enable denoising - `denoiseStrength` (number 0-100, default 40) - Denoising strength - `colorize` (boolean, default false) - Colorize grayscale photos clientJobId: type: string description: Client-provided job ID for SSE progress tracking responses: "200": description: Restored image with processing details content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: previewUrl: type: string description: WebP preview URL for non-previewable formats width: type: integer height: type: integer steps: type: array items: type: string description: Processing steps performed scratchCoverage: type: number description: Percentage of image with scratches detected facesEnhanced: type: integer description: Number of faces enhanced isGrayscale: type: boolean description: Whether the input was grayscale colorized: type: boolean description: Whether colorization was applied "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/passport-photo/analyze: post: tags: [Tools] summary: Passport photo - analyze description: | Phase 1 of passport photo generation. Detects face landmarks and removes the background. Returns landmark data and a base64-encoded preview for the client to use in the generate phase. Requires the passport-photo feature bundle to be installed. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Photo with a clear, front-facing face clientJobId: type: string description: Client-provided job ID for SSE progress tracking responses: "200": description: Face analysis and background removal result content: application/json: schema: type: object properties: jobId: type: string description: Job ID to pass to the generate endpoint filename: type: string preview: type: string description: Base64-encoded PNG preview of the background-removed image previewWidth: type: integer previewHeight: type: integer landmarks: type: object description: Normalized face landmark coordinates (0-1) properties: leftEye: type: object properties: x: type: number y: type: number rightEye: type: object properties: x: type: number y: type: number eyeCenter: type: object properties: x: type: number y: type: number chin: type: object properties: x: type: number y: type: number forehead: type: object properties: x: type: number y: type: number crown: type: object properties: x: type: number y: type: number nose: type: object properties: x: type: number y: type: number faceCenterX: type: number imageWidth: type: integer imageHeight: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: No face detected or analysis failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/passport-photo/generate: post: tags: [Tools] summary: Passport photo - generate description: | Phase 2 of passport photo generation. Uses the jobId and landmarks from the analyze phase to crop, resize, and tile the photo to the specified country/document specification. Fast response (no AI re-run). security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [jobId, filename, countryCode, landmarks, imageWidth, imageHeight] properties: jobId: type: string description: Job ID from the analyze phase filename: type: string description: Original filename from analyze phase countryCode: type: string description: ISO country code for passport specification documentType: type: string default: passport description: Document type (passport, visa, etc.) bgColor: type: string default: "#FFFFFF" description: Background color (hex) printLayout: type: string default: none description: Print sheet layout (none, 4x6, A4, letter) maxFileSizeKb: type: number default: 0 description: Max file size in KB (0 = no limit) dpi: type: number minimum: 72 maximum: 1200 default: 300 description: Output DPI customWidthMm: type: number description: Custom photo width in mm (overrides country spec) customHeightMm: type: number description: Custom photo height in mm (overrides country spec) zoom: type: number minimum: 0.5 maximum: 3 default: 1 description: Zoom level (>1 = tighter crop) adjustX: type: number default: 0 description: Horizontal position adjustment adjustY: type: number default: 0 description: Vertical position adjustment landmarks: type: object description: Face landmarks from analyze phase imageWidth: type: integer description: Original image width from analyze phase imageHeight: type: integer description: Original image height from analyze phase responses: "200": description: Generated passport photo content: application/json: schema: type: object properties: jobId: type: string downloadUrl: type: string dimensions: type: object properties: widthMm: type: number heightMm: type: number widthPx: type: integer heightPx: type: integer dpi: type: integer spec: type: object properties: country: type: string countryCode: type: string documentType: type: string documentLabel: type: string printDownloadUrl: type: string description: URL for print sheet download (if printLayout was specified) "400": description: Invalid settings or unknown country code content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Generation failed content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/colorize: post: tags: [Tools] summary: Colorize description: | AI-powered photo colorization. Converts black-and-white or grayscale photographs to full color using DDColor with OpenCV DNN fallback. Requires the colorize feature bundle to be installed. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Grayscale or B&W image file settings: type: string description: | JSON string with options: - `intensity` (number 0-1, default 1.0) - Colorization intensity - `model` (string, default "auto") - One of: auto, ddcolor, opencv clientJobId: type: string description: Client-provided job ID for SSE progress tracking responses: "200": description: Colorized image content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: previewUrl: type: string description: WebP preview URL for non-previewable formats width: type: integer height: type: integer method: type: string description: Colorization model used (ddcolor or opencv) "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/enhance-faces: post: tags: [Tools] summary: Face enhancement description: | AI-powered face enhancement using GFPGAN or CodeFormer. Detects faces in the image and enhances facial details, skin texture, and clarity. Requires the enhance-faces feature bundle to be installed. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file containing faces settings: type: string description: | JSON string with options: - `model` (string, default "auto") - One of: auto, gfpgan, codeformer - `strength` (number 0-1, default 0.8) - Enhancement strength - `onlyCenterFace` (boolean, default false) - Only enhance the center face - `sensitivity` (number 0-1, default 0.5) - Face detection sensitivity clientJobId: type: string description: Client-provided job ID for SSE progress tracking responses: "200": description: Enhanced image with face details content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: previewUrl: type: string description: WebP preview URL facesDetected: type: integer description: Number of faces detected faces: type: array items: type: object description: Per-face bounding boxes and confidence scores model: type: string description: Model actually used (gfpgan or codeformer) "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/image-to-base64: post: tags: [Tools] summary: Image to Base64 description: | Convert one or more images to Base64-encoded strings with data URIs. Supports optional format conversion and resizing. Returns both the raw Base64 string and a ready-to-use data URI for each file. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: array items: type: string format: binary description: One or more image files to convert settings: type: string description: | JSON string with options: - `outputFormat` (string, default "original") - One of: original, jpeg, png, webp, avif - `quality` (integer 1-100, default 80) - Output quality for lossy formats - `maxWidth` (integer, default 0) - Max width in pixels (0 = no limit) - `maxHeight` (integer, default 0) - Max height in pixels (0 = no limit) responses: "200": description: Base64-encoded results content: application/json: schema: type: object properties: results: type: array items: type: object properties: filename: type: string mimeType: type: string width: type: integer height: type: integer originalSize: type: integer description: Original file size in bytes encodedSize: type: integer description: Base64 string size in bytes overheadPercent: type: number description: Size overhead of Base64 encoding base64: type: string description: Raw Base64-encoded image data dataUri: type: string description: Complete data URI (data:mime;base64,...) errors: type: array items: type: object properties: filename: type: string error: type: string "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/watermark-text: post: tags: [Tools] summary: Text watermark description: Add a text watermark to an image. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `text` (string 1-500, required) — Watermark text - `fontSize` (number 8-1000, default 48) — Font size in pixels - `color` (hex string, default "#000000") — Text color - `opacity` (number 0-100, default 50) — Opacity percentage - `position` (string, default "center") — One of: center, top-left, top-right, bottom-left, bottom-right, tiled - `rotation` (number -360 to 360, default 0) — Text rotation angle responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/text-overlay: post: tags: [Tools] summary: Text overlay description: Add styled text overlay with optional background box. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `text` (string 1-500, required) — Overlay text - `fontSize` (number 8-200, default 48) — Font size in pixels - `color` (hex string, default "#FFFFFF") — Text color - `position` (string, default "bottom") — One of: top, center, bottom - `backgroundBox` (boolean, default false) — Show background box behind text - `backgroundColor` (hex string, default "#000000") — Background box color - `shadow` (boolean, default true) — Add text shadow responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/replace-color: post: tags: [Tools] summary: Replace color description: Replace a specific color in an image with another color or transparency. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `sourceColor` (hex string, default "#FF0000") — Color to replace - `targetColor` (hex string, default "#00FF00") — Replacement color - `makeTransparent` (boolean, default false) — Make matched pixels transparent instead - `tolerance` (number 0-255, default 30) — Color matching tolerance responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/gif-tools: post: tags: [Tools] summary: GIF tools description: Resize, extract frames from, or optimize animated GIFs. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: GIF file to process settings: type: string description: | JSON string with options: - `mode` (string, default "resize") — One of: resize, optimize, speed, reverse, extract, rotate - `width` (number 1-16384, optional) — Target width in pixels (resize mode) - `height` (number 1-16384, optional) — Target height in pixels (resize mode) - `percentage` (number 1-500, optional) — Scale by percentage (resize mode) - `colors` (number 2-256, default 256) — Color palette size (optimize mode) - `dither` (number 0-1, default 1.0) — Dither amount (optimize mode) - `effort` (number 1-10, default 7) — Compression effort (optimize mode) - `speedFactor` (number 0.1-10, default 1.0) — Speed multiplier (speed mode) - `extractMode` (string, default "single") — One of: single, range, all (extract mode) - `frameNumber` (number, default 0) — Frame index to extract (extract/single mode) - `frameStart` (number, default 0) — Start frame index (extract/range mode) - `frameEnd` (number, optional) — End frame index (extract/range mode) - `extractFormat` (string, default "png") — One of: png, webp (extract mode) - `angle` (number, optional) — Rotation angle, one of: 90, 180, 270 (rotate mode) - `flipH` (boolean, default false) — Flip horizontally (rotate mode) - `flipV` (boolean, default false) — Flip vertically (rotate mode) - `loop` (number 0-100, default 0) — Loop count, 0 = infinite responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/gif-tools/info: post: tags: [Tools] summary: GIF info description: Get metadata about an animated GIF including dimensions, frame count, delays, and duration. security: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: GIF file to inspect responses: "200": description: GIF metadata content: application/json: schema: type: object properties: width: type: integer height: type: integer pages: type: integer description: Number of frames delay: type: array items: type: integer description: Per-frame delay in milliseconds loop: type: integer description: Loop count (0 = infinite) fileSize: type: integer duration: type: integer description: Total duration in milliseconds "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/smart-crop: post: tags: [Tools] summary: Smart crop description: Smart crop with three modes - subject focus, face focus, or auto trim. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `mode` (string, default "subject") — One of: subject, face, trim, attention (alias for subject), content (alias for trim) - `strategy` (string, default "attention") — One of: attention, entropy (subject mode) - `width` (integer, optional) — Target width in pixels - `height` (integer, optional) — Target height in pixels - `padding` (integer 0-50, default 0) — Padding percentage around focus area - `facePreset` (string) — "closeup", "head-shoulders", "upper-body", "half-body" (face mode) - `sensitivity` (number 0-1) — Face detection sensitivity (face mode) - `threshold` (integer 0-255) — Trim tolerance (trim mode) - `padToSquare` (boolean) — Pad to square after trimming (trim mode) - `padColor` (string) — Hex color for padding (trim mode) - `targetSize` (integer) — Target size for padded output (trim mode) - `quality` (integer 1-100) — Output quality responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/vectorize: post: tags: [Tools] summary: Image to SVG description: Convert a raster image to SVG vector format using potrace (B&W) or VTracer (color). security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `colorMode` (string, default "bw") - One of: bw, color - `threshold` (number 0-255, default 128) - B&W binarization threshold - `colorPrecision` (number 1-16, default 6) - Color bits per channel - `layerDifference` (number 1-128, default 6) - Color gradient step - `filterSpeckle` (number 1-256, default 4) - Noise filter size - `pathMode` (string, default "spline") - One of: none, polygon, spline - `cornerThreshold` (number 0-180, default 60) - Corner detection angle - `invert` (boolean, default false) - Invert colors before tracing responses: "200": description: Processed image (downloadUrl points to .svg file) content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/svg-to-raster: post: tags: [Tools] summary: SVG to raster description: Convert an SVG file to a raster image format at custom scale and DPI. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: SVG file to convert settings: type: string description: | JSON string with options: - `width` (number 1-65536, optional) — Output width in pixels - `height` (number 1-65536, optional) — Output height in pixels - `dpi` (number 36-2400, default 300) — Render density for SVG rasterization - `quality` (number 1-100, default 90) — Output quality for lossy formats - `backgroundColor` (hex string, default "#00000000") — Background color - `outputFormat` (string, default "png") — One of: png, jpg, webp, avif, tiff, gif, heif responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/svg-to-raster/batch: post: tags: [Tools] summary: SVG to raster (batch) description: Convert multiple SVG files to raster images. Returns a ZIP archive. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: array items: type: string format: binary description: SVG files to convert settings: type: string description: Same settings as single-file endpoint clientJobId: type: string description: Optional client-generated job ID for progress tracking responses: "200": description: ZIP archive containing processed images content: application/zip: schema: type: string format: binary "400": description: Invalid input "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: All files failed processing /api/v1/tools/image-to-pdf: post: tags: [Tools] summary: Image to PDF description: Convert one or more images into a PDF document. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: array items: type: string format: binary description: One or more image files to include in the PDF settings: type: string description: | JSON string with options: - `pageSize` (string, default "A4") — One of: A4, Letter, A3, A5 - `orientation` (string, default "portrait") — One of: portrait, landscape - `margin` (number 0-500, default 20) — Page margin in points - `targetSize` (object, optional) — Target output file size - `value` (number, required) — Positive number (decimals allowed) - `unit` (string, required) — One of: KB, MB Minimum effective target is 50KB. When set, images are compressed as JPEG with quality auto-tuned to meet the target. responses: "200": description: Generated PDF (downloadUrl points to .pdf file) content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: pages: type: integer description: Number of images/pages in the PDF compression: type: object description: Present only when targetSize was specified properties: targetRequested: type: integer description: Target size in bytes targetMet: type: boolean description: Whether the target was achieved jpegQuality: type: integer description: Final JPEG quality used (10-95) "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/pdf-to-image: post: tags: [Tools] summary: PDF to image description: Convert PDF pages to images. Returns individual page downloads and a ZIP of all pages. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: PDF file to convert settings: type: string description: | JSON string with options: - `format` (string, default "png") — Output format: png, jpg, webp, avif, tiff, gif, heic, heif - `dpi` (number 36-2400, default 150) — Resolution in dots per inch - `quality` (number 1-100, default 85) — Output quality - `colorMode` (string, default "color") — One of: color, grayscale, bw - `pages` (string, default "all") — Page selection, e.g. "all", "1-3", "1,3,5" responses: "200": description: Converted pages content: application/json: schema: type: object properties: jobId: type: string pageCount: type: integer description: Total pages in the PDF selectedPages: type: array items: type: integer format: type: string pages: type: array items: type: object properties: page: type: integer downloadUrl: type: string size: type: integer zipUrl: type: string description: URL to download all pages as ZIP zipSize: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/pdf-to-image/info: post: tags: [Tools] summary: PDF page count description: Get the number of pages in a PDF file. security: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: PDF file to inspect responses: "200": description: PDF info content: application/json: schema: type: object properties: pageCount: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/pdf-to-image/preview: post: tags: [Tools] summary: PDF page thumbnails description: Generate thumbnail previews for each page in a PDF (max 200 pages, JPEG 300px wide). security: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: PDF file to preview responses: "200": description: Page thumbnails content: application/json: schema: type: object properties: pageCount: type: integer thumbnails: type: array items: type: object properties: page: type: integer dataUrl: type: string description: Base64-encoded JPEG data URL width: type: integer height: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/split: post: tags: [Tools] summary: Split image description: Split an image into a grid of tiles. Returns a ZIP file. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to split settings: type: string description: | JSON string with options: - `columns` (number 1-100, default 3) — Number of columns - `rows` (number 1-100, default 3) — Number of rows - `tileWidth` (number, min 10, optional) — Fixed tile width in pixels - `tileHeight` (number, min 10, optional) — Fixed tile height in pixels - `outputFormat` (string, default "original") — One of: original, png, jpg, webp, avif - `quality` (number 1-100, default 90) — Output quality responses: "200": description: ZIP archive with results content: application/zip: schema: type: string format: binary "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/bulk-rename: post: tags: [Tools] summary: Bulk rename description: Rename multiple images using a pattern template. Supports {{index}}, {{padded}}, and {{original}} tokens. Returns a ZIP file. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: array items: type: string format: binary description: Multiple image files to rename settings: type: string description: | JSON string with options: - `pattern` (string 1-1000, default "image-{{index}}") — Naming pattern template - `startIndex` (number, default 1) — Starting index number responses: "200": description: ZIP archive with results content: application/zip: schema: type: string format: binary "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/favicon: post: tags: [Tools] summary: Favicon generator description: Generate a complete favicon set (16px to 512px PNGs, ICO, and manifest.json) from an image. Returns a ZIP file. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to use as favicon source responses: "200": description: ZIP archive with results content: application/zip: schema: type: string format: binary "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/watermark-image: post: tags: [Tools] summary: Image watermark description: Add an image watermark overlay. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file, watermark, settings] properties: file: type: string format: binary description: Main image file watermark: type: string format: binary description: Watermark overlay image settings: type: string description: | JSON string with options: - `position` (string, default "bottom-right") — One of: center, top-left, top-right, bottom-left, bottom-right - `opacity` (number 0-100, default 50) — Watermark opacity percentage - `scale` (number 1-100, default 25) — Watermark size as percentage of base image responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/compose: post: tags: [Tools] summary: Image composition description: Composite an overlay image onto a base image with blend modes. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file, overlay, settings] properties: file: type: string format: binary description: Base image file overlay: type: string format: binary description: Overlay image file settings: type: string description: | JSON string with options: - `x` (number, default 0) — Horizontal offset of overlay - `y` (number, default 0) — Vertical offset of overlay - `opacity` (number 0-100, default 100) — Overlay opacity percentage - `blendMode` (string, default "over") — One of: over, multiply, screen, overlay, darken, lighten, hard-light, soft-light, difference, exclusion responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/compare: post: tags: [Tools] summary: Image compare description: Compare two images and generate a visual difference report. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file1, file2] properties: file1: type: string format: binary description: First image to compare file2: type: string format: binary description: Second image to compare responses: "200": description: Comparison result content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: similarity: type: number description: Structural similarity score (0-1) dimensions: type: object properties: width: type: integer height: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/erase-object: post: tags: [Tools] summary: Object eraser description: Erase objects from an image using a mask. White areas in the mask indicate regions to erase. Uses LaMa inpainting. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [image, mask] properties: image: type: string format: binary description: Source image file mask: type: string format: binary description: Mask image (white areas will be erased) format: type: string enum: [png, jpg, jpeg, webp, tiff, gif, avif, heic, heif] default: png description: Output format quality: type: integer minimum: 1 maximum: 100 default: 95 description: Output quality clientJobId: type: string description: Client-provided job ID for SSE progress tracking responses: "200": description: Processed image with erased regions content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/collage: post: tags: [Tools] summary: Collage / grid description: Combine multiple images into a grid collage. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: array items: type: string format: binary description: Multiple image files to combine settings: type: string description: | JSON string with options: - `templateId` (string, required) — Template ID defining the grid layout - `cells` (array, optional) — Per-cell configuration overrides - `gap` (number 0-500, default 8) — Gap between images in pixels - `cornerRadius` (number 0-500, default 0) — Corner rounding radius - `backgroundColor` (string, default "#FFFFFF") — Background fill color - `aspectRatio` (string, default "free") — Aspect ratio constraint - `outputFormat` (string, default "png") — One of: png, jpeg, webp, avif - `quality` (number 1-100, default 90) — Output quality responses: "200": description: Processed image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/stitch: post: tags: [Tools] summary: Stitch images description: Join multiple images horizontally, vertically, or in a grid layout. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: array items: type: string format: binary description: Two or more image files to stitch together settings: type: string description: | JSON string with options: - `direction` (string, default "horizontal") — One of: horizontal, vertical, grid - `gridColumns` (integer 2-100, default 2) — Columns when direction is grid - `resizeMode` (string, default "fit") — One of: fit, original, stretch, crop - `alignment` (string, default "center") — One of: start, center, end - `gap` (number 0-1000, default 0) — Gap between images in pixels - `border` (number 0-500, default 0) — Border width in pixels - `cornerRadius` (number 0-500, default 0) — Corner radius in pixels - `backgroundColor` (hex string, default "#FFFFFF") — Hex color for background and gap fill - `format` (string, default "png") — One of: png, jpeg, webp, avif - `quality` (number 1-100, default 90) — Output quality responses: "200": description: Stitched image content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/remove-background: post: tags: [Tools] summary: Remove background description: Remove the background from an image using AI (rembg). Runs locally. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `model` (string, optional) — AI model name - `backgroundType` (string, optional) — One of: transparent, color, gradient, blur, image - `backgroundColor` (string, optional) — Hex color to replace removed background with - `gradientColor1` (string, optional) — First gradient color - `gradientColor2` (string, optional) — Second gradient color - `gradientAngle` (number, optional) — Gradient angle in degrees - `blurEnabled` (boolean, optional) — Enable background blur effect - `blurIntensity` (number 0-100, optional) — Blur strength - `shadowEnabled` (boolean, optional) — Enable drop shadow - `shadowOpacity` (number 0-100, optional) — Shadow opacity responses: "200": description: Processed image with background removed content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: maskUrl: type: string description: URL to the mask image originalUrl: type: string description: URL to the original uploaded image filename: type: string model: type: string "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/remove-background/effects: post: tags: [Tools] summary: Apply background effects description: > Apply background replacement or effects to a previously processed remove-background result. Requires a jobId from a prior POST /api/v1/tools/remove-background call. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [settings] properties: backgroundImage: type: string format: binary description: Custom background image (required when backgroundType is "image") settings: type: string description: | JSON string with options: - `jobId` (string, required) — Job ID from the initial remove-background call - `filename` (string, required) — Original filename - `backgroundType` (string) — One of: transparent, color, gradient, blur, image - `backgroundColor` (string) — Hex color for solid background - `gradientColor1` (string) — First gradient color - `gradientColor2` (string) — Second gradient color - `gradientAngle` (number) — Gradient angle in degrees - `blurEnabled` (boolean) — Enable background blur effect - `blurIntensity` (number 0-100) — Blur strength - `shadowEnabled` (boolean) — Enable drop shadow - `shadowOpacity` (number 0-100) — Shadow opacity responses: "200": description: Image with applied effects content: application/json: schema: type: object properties: jobId: type: string downloadUrl: type: string processedSize: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/transparency-fixer: post: tags: [Tools] summary: Fix fake transparency description: | Fix "fake transparent" PNGs that have fringing, halos, or semi-transparent artifacts from a previous background removal. Uses BiRefNet HR-matting (2048x2048) to produce a clean alpha channel with configurable defringe processing. Falls back to birefnet-general, then u2net on OOM. Requires the background-removal feature bundle to be installed. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: PNG image with fake or damaged transparency settings: type: string description: | JSON string with options: - `defringe` (number 0-100, default 30) — Edge defringe strength to remove color contamination - `outputFormat` (string, default "png") — One of: png, webp clientJobId: type: string description: Client-provided job ID for SSE progress tracking responses: "200": description: Image with corrected transparency content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: width: type: integer height: type: integer model: type: string description: AI model that was used (may differ from default due to OOM fallback) "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/upscale: post: tags: [Tools] summary: Image upscaling description: Upscale an image using AI (Real-ESRGAN). Runs locally. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to upscale settings: type: string description: | JSON string with options: - `scale` (number, default 2) — Upscale factor - `model` (string, default "auto") — AI model name - `faceEnhance` (boolean, default false) — Enable face enhancement - `denoise` (number, default 0) — Denoise strength - `format` (string, default "png") — Output format - `quality` (number, default 95) — Output quality (1-100) responses: "200": description: Upscaled image content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: width: type: integer height: type: integer method: type: string "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/blur-faces: post: tags: [Tools] summary: Face blur description: Detect and blur faces in an image for privacy. Uses OpenCV. Runs locally. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `blurRadius` (number 1-100, default 30) — Blur strength radius - `sensitivity` (number 0-1, default 0.5) — Face detection sensitivity clientJobId: type: string responses: "200": description: Processed image with faces blurred content: application/json: schema: allOf: - $ref: "#/components/schemas/ToolResponse" - type: object properties: facesDetected: type: integer faces: type: array items: type: object warning: type: string "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/ocr: post: tags: [Tools] summary: OCR / text extraction description: Extract text from an image using OCR. Runs locally. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to extract text from settings: type: string description: | JSON string with options: - `quality` (string, default "balanced") — One of: fast, balanced, best - `language` (string, default "auto") — One of: auto, en, de, fr, es, zh, ja, ko - `enhance` (boolean, default true) — Pre-process image for better recognition - `engine` (string, optional) — One of: tesseract, paddleocr (backward compat) clientJobId: type: string responses: "200": description: Extracted text content: application/json: schema: type: object properties: jobId: type: string filename: type: string text: type: string description: Extracted text content engine: type: string "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/tools/info: post: tags: [Tools] summary: Image info description: Get detailed metadata about an image including dimensions, format, color space, and EXIF data. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to inspect responses: "200": description: Image metadata content: application/json: schema: type: object properties: width: type: integer height: type: integer filename: type: string format: type: string colorSpace: type: string channels: type: integer bitDepth: type: string density: type: integer nullable: true hasAlpha: type: boolean fileSize: type: integer hasExif: type: boolean isProgressive: type: boolean orientation: type: integer nullable: true hasProfile: type: boolean hasIcc: type: boolean hasXmp: type: boolean pages: type: integer histogram: type: array items: type: object properties: channel: type: string min: type: number max: type: number mean: type: number stdev: type: number "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/color-palette: post: tags: [Tools] summary: Color palette description: Extract the dominant colors from an image. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to analyze responses: "200": description: Dominant colors content: application/json: schema: type: object properties: filename: type: string colors: type: array items: type: string description: Hex color strings count: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/barcode-read: post: tags: [Tools] summary: Barcode reader description: Read QR codes and barcodes from an image. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file containing barcode or QR code settings: type: string description: | JSON string with options: - `tryHarder` (boolean, default true) — Enable more aggressive barcode detection responses: "200": description: Decoded barcode data content: application/json: schema: type: object properties: filename: type: string barcodes: type: array items: type: object properties: type: type: string text: type: string position: type: object properties: topLeft: type: object properties: x: { type: number } y: { type: number } topRight: type: object properties: x: { type: number } y: { type: number } bottomLeft: type: object properties: x: { type: number } y: { type: number } bottomRight: type: object properties: x: { type: number } y: { type: number } annotatedUrl: type: string nullable: true previewUrl: type: string nullable: true "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/find-duplicates: post: tags: [Tools] summary: Find duplicates description: Find duplicate images in a set using perceptual hashing. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: array items: type: string format: binary description: Multiple image files to check for duplicates settings: type: string description: | JSON string with options: - `threshold` (number 0-20, default 8) — Hamming distance threshold for duplicate detection responses: "200": description: Duplicate groups content: application/json: schema: type: object properties: totalImages: type: integer duplicateGroups: type: array items: type: object properties: groupId: type: integer files: type: array items: type: object properties: filename: type: string similarity: type: number width: type: integer height: type: integer fileSize: type: integer format: type: string isBest: type: boolean thumbnail: type: string uniqueImages: type: integer spaceSaveable: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/tools/qr-generate: post: tags: [Tools] summary: QR code generator description: Generate a QR code image from text. This tool accepts a JSON body, not multipart. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [text] properties: text: type: string maxLength: 2000 description: Text to encode in the QR code size: type: integer minimum: 100 maximum: 10000 default: 400 description: Image size in pixels errorCorrection: type: string enum: [L, M, Q, H] default: M foreground: type: string default: "#000000" description: Foreground color (hex) background: type: string default: "#FFFFFF" description: Background color (hex) responses: "200": description: Generated QR code content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/strip-metadata/inspect: post: tags: [Tools] summary: Inspect metadata description: View all metadata (EXIF, GPS, ICC, XMP) in an image without removing it. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to inspect responses: "200": description: Image metadata content: application/json: schema: type: object properties: filename: type: string fileSize: type: integer exif: type: object description: EXIF metadata exifError: type: string description: Present when EXIF parsing fails gps: type: object description: GPS metadata icc: type: object description: ICC profile metadata xmp: type: object description: XMP metadata "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/edit-metadata: post: tags: [Tools] summary: Edit metadata description: Edit EXIF, IPTC, GPS, and other metadata fields in an image using ExifTool. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to process settings: type: string description: | JSON string with options: - `title` (string) — Image title - `author` (string) — Author name - `artist` (string) — Artist or author name - `copyright` (string) — Copyright notice - `imageDescription` (string) — Image description - `software` (string) — Software used - `dateTime` (string) — Date/time string - `dateTimeOriginal` (string) — Original capture date/time - `clearGps` (boolean, default false) — Remove all GPS data - `fieldsToRemove` (string[]) — Specific metadata fields to remove - `gpsLatitude` (number -90 to 90) — GPS latitude - `gpsLongitude` (number -180 to 180) — GPS longitude - `gpsAltitude` (number) — GPS altitude in meters - `keywords` (string[]) — Keywords or tags - `keywordsMode` (string, default "add") — One of: add, set - `dateShift` (string) — Shift dates by offset, e.g. "+2:00" or "-1:30" - `setAllDates` (string) — Set all date fields to this value - `iptcTitle` (string) — IPTC title - `iptcHeadline` (string) — IPTC headline - `iptcCity` (string) — IPTC city - `iptcState` (string) — IPTC state or province - `iptcCountry` (string) — IPTC country responses: "200": description: Image with updated metadata content: application/json: schema: $ref: "#/components/schemas/ToolResponse" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/tools/edit-metadata/inspect: post: tags: [Tools] summary: Inspect metadata (ExifTool) description: Read all metadata from an image using ExifTool. Returns all embedded EXIF, IPTC, XMP, and GPS fields. security: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to inspect responses: "200": description: Full metadata object (keys vary by image) content: application/json: schema: type: object additionalProperties: true "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" # ─── Batch ──────────────────────────────────────────────────────────────── /api/v1/tools/{toolId}/batch: post: tags: [Batch] summary: Batch process images description: > Send multiple images through a single tool. Returns a ZIP file. The response includes an X-Job-Id header for progress tracking. security: - bearerAuth: [] parameters: - name: toolId in: path required: true schema: type: string description: Tool identifier (e.g. resize, crop) requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: array items: type: string format: binary description: Image files to process (one or more) settings: type: string description: JSON string of tool settings applied to all images responses: "200": description: ZIP archive of processed images headers: X-Job-Id: schema: type: string description: Job identifier for progress tracking content: application/zip: schema: type: string format: binary "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" # ─── Pipelines ──────────────────────────────────────────────────────────── /api/v1/pipeline/execute: post: tags: [Pipelines] summary: Execute a pipeline description: Run an image through a chain of tools. The pipeline definition is sent as a JSON string in the `pipeline` multipart field. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file, pipeline] properties: file: type: string format: binary description: Image file to process pipeline: type: string description: 'JSON string: { "steps": [{ "toolId": "resize", "settings": {...} }, ...] }' responses: "200": description: Pipeline result content: application/json: schema: type: object properties: jobId: type: string downloadUrl: type: string originalSize: type: integer processedSize: type: integer stepsCompleted: type: integer steps: type: array items: type: object "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "422": description: Processing failed content: application/json: schema: $ref: "#/components/schemas/Error" "501": description: Feature not installed content: application/json: schema: $ref: "#/components/schemas/FeatureNotInstalledError" /api/v1/pipeline/save: post: tags: [Pipelines] summary: Save a pipeline security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [name, steps] properties: name: type: string description: type: string steps: type: array items: type: object properties: toolId: type: string settings: type: object responses: "201": description: Pipeline saved content: application/json: schema: type: object properties: id: type: string name: type: string description: type: string steps: type: array items: type: object createdAt: type: string format: date-time "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/pipeline/list: get: tags: [Pipelines] summary: List saved pipelines security: - bearerAuth: [] responses: "200": description: List of pipelines content: application/json: schema: type: object properties: pipelines: type: array items: type: object properties: id: type: string name: type: string description: type: string steps: type: array items: type: object createdAt: type: string format: date-time "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/pipeline/{id}: delete: tags: [Pipelines] summary: Delete a pipeline security: - bearerAuth: [] parameters: - name: id in: path required: true description: Pipeline UUID schema: type: string responses: "200": description: Pipeline deleted content: application/json: schema: type: object properties: ok: type: boolean "403": description: Not authorized to delete this pipeline content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "404": description: Pipeline not found content: application/json: schema: $ref: "#/components/schemas/Error" "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/pipeline/tools: get: tags: [Pipelines] summary: List pipeline-compatible tools description: Returns all tool IDs that can be used as pipeline steps. security: [] responses: "200": description: Tool IDs content: application/json: schema: type: object properties: toolIds: type: array items: type: string /api/v1/pipeline/batch: post: tags: [Pipelines] summary: Run pipeline on multiple files description: Execute a pipeline across multiple images. Returns a ZIP file with all processed results. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file, pipeline] properties: file: type: array items: type: string format: binary description: Image files to process pipeline: type: string description: | JSON string with pipeline definition: - `steps` (array, required, 1-20 items) — Pipeline steps - `steps[].toolId` (string, required) — Tool ID for this step - `steps[].settings` (object, optional) — Tool-specific settings clientJobId: type: string description: Optional client-provided job ID for progress tracking via SSE responses: "200": description: ZIP file with processed images headers: X-Job-Id: schema: type: string description: Job ID for progress tracking X-File-Results: schema: type: string description: JSON mapping of input index to output filename content: application/zip: schema: type: string format: binary "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" # ─── Files ──────────────────────────────────────────────────────────────── /api/v1/upload: post: tags: [Files] summary: Upload an image security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary responses: "200": description: Upload result content: application/json: schema: type: object properties: jobId: type: string files: type: array items: type: object properties: name: type: string size: type: integer format: type: string "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/download/{jobId}/{filename}: get: tags: [Files] summary: Download a processed image security: [] parameters: - name: jobId in: path required: true description: Job identifier from a tool processing response schema: type: string - name: filename in: path required: true description: Output filename from the processing response schema: type: string responses: "200": description: Image binary content: image/*: schema: type: string format: binary "404": description: File not found /api/v1/preview: post: tags: [Files] summary: Generate image preview description: Convert any image (including HEIC/HEIF) to a WebP preview, resized to fit within 1200x1200 pixels. security: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary description: Image file to preview responses: "200": description: WebP preview image content: image/webp: schema: type: string format: binary "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/files: get: tags: [Files] summary: List saved files description: Returns the latest version of each file (one per version chain). Supports pagination and search. security: - bearerAuth: [] parameters: - name: limit in: query description: Maximum number of files to return (default 50) schema: type: integer default: 50 - name: offset in: query description: Number of files to skip for pagination (default 0) schema: type: integer default: 0 - name: search in: query description: Filter files by original filename (substring match) schema: type: string responses: "200": description: List of saved files content: application/json: schema: type: object properties: files: type: array items: type: object properties: id: type: string filename: type: string size: type: integer contentType: type: string createdAt: type: string format: date-time total: type: integer description: Total number of matching files (for pagination) limit: type: integer description: Applied limit value offset: type: integer description: Applied offset value "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" delete: tags: [Files] summary: Bulk delete saved files description: Delete files and their entire version chains. Non-admin users can only delete their own files. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [ids] properties: ids: type: array items: type: string description: File IDs to delete (deletes entire version chain for each) responses: "200": description: Deletion result content: application/json: schema: type: object properties: deleted: type: integer description: Total number of records deleted across all version chains "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/files/upload: post: tags: [Files] summary: Save file to library security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary responses: "201": description: Files uploaded content: application/json: schema: type: object properties: files: type: array items: type: object description: Full file object with all metadata "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/files/save-result: post: tags: [Files] summary: Save a processing result to library description: Save a tool processing result as a new version of an existing file. Creates a version chain. security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: [file, parentId] properties: file: type: string format: binary description: The processed image file parentId: type: string description: ID of the parent file in the version chain toolId: type: string description: Tool that produced this result responses: "201": description: File saved content: application/json: schema: type: object properties: file: type: object description: Full file object with all metadata "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "404": description: Parent file not found content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/files/{id}: get: tags: [Files] summary: Get file metadata and version history security: - bearerAuth: [] parameters: - name: id in: path required: true description: Saved file UUID schema: type: string responses: "200": description: File metadata with version history content: application/json: schema: type: object properties: file: type: object properties: id: type: string originalName: type: string mimeType: type: string size: type: integer width: type: integer height: type: integer version: type: integer parentId: type: string nullable: true toolChain: type: array items: type: string createdAt: type: string format: date-time versions: type: array items: type: object description: Full version chain of this file "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "404": description: File not found content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/files/{id}/download: get: tags: [Files] summary: Download a saved file security: - bearerAuth: [] parameters: - name: id in: path required: true description: Saved file UUID schema: type: string responses: "200": description: Image binary content: image/*: schema: type: string format: binary "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "404": description: File not found content: application/json: schema: $ref: "#/components/schemas/Error" /api/v1/files/{id}/thumbnail: get: tags: [Files] summary: Get file thumbnail security: [] parameters: - name: id in: path required: true description: Saved file UUID schema: type: string responses: "200": description: 300px JPEG thumbnail content: image/jpeg: schema: type: string format: binary "404": description: File not found content: application/json: schema: $ref: "#/components/schemas/Error" "422": description: Thumbnail generation failed content: application/json: schema: $ref: "#/components/schemas/Error" # ─── Auth ───────────────────────────────────────────────────────────────── /api/auth/login: post: tags: [Auth] summary: Log in security: [] requestBody: required: true content: application/json: schema: type: object required: [username, password] properties: username: type: string password: type: string format: password responses: "200": description: Login successful content: application/json: schema: type: object properties: token: type: string user: type: object properties: id: type: string username: type: string role: type: string mustChangePassword: type: boolean permissions: type: array items: type: string teamName: type: string analyticsEnabled: type: boolean nullable: true analyticsConsentShownAt: type: integer nullable: true analyticsConsentRemindAt: type: integer nullable: true expiresAt: type: string format: date-time "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Invalid credentials content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/auth/logout: post: tags: [Auth] summary: Log out security: - bearerAuth: [] responses: "200": description: Logged out content: application/json: schema: type: object properties: ok: type: boolean "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/auth/session: get: tags: [Auth] summary: Get current session security: [] responses: "200": description: Session info content: application/json: schema: type: object properties: user: type: object properties: id: type: string username: type: string role: type: string mustChangePassword: type: boolean permissions: type: array items: type: string analyticsEnabled: type: boolean nullable: true analyticsConsentShownAt: type: integer nullable: true analyticsConsentRemindAt: type: integer nullable: true expiresAt: type: string format: date-time nullable: true /api/auth/change-password: post: tags: [Auth] summary: Change password security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [currentPassword, newPassword] properties: currentPassword: type: string format: password newPassword: type: string format: password responses: "200": description: Password changed content: application/json: schema: type: object properties: ok: type: boolean "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/auth/users: get: tags: [Auth] summary: List users description: Requires users:manage permission. security: - bearerAuth: [] responses: "200": description: List of users content: application/json: schema: type: object properties: users: type: array items: type: object properties: id: type: string username: type: string role: type: string team: type: string createdAt: type: string format: date-time maxUsers: type: integer "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" /api/auth/register: post: tags: [Auth] summary: Create user description: Requires users:manage permission. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [username, password] properties: username: type: string password: type: string format: password role: type: string description: Built-in role (admin, editor, user) or custom role name default: user team: type: string default: Default responses: "201": description: User created content: application/json: schema: type: object properties: id: type: string username: type: string role: type: string team: type: string "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "409": description: Username already exists content: application/json: schema: $ref: "#/components/schemas/ConflictError" /api/auth/users/{id}: put: tags: [Auth] summary: Update user description: Requires users:manage permission. security: - bearerAuth: [] parameters: - name: id in: path required: true description: User UUID schema: type: string requestBody: required: true content: application/json: schema: type: object properties: role: type: string description: Built-in role (admin, editor, user) or custom role name team: type: string responses: "200": description: User updated content: application/json: schema: type: object properties: ok: type: boolean "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" delete: tags: [Auth] summary: Delete user description: Requires users:manage permission. security: - bearerAuth: [] parameters: - name: id in: path required: true description: User UUID schema: type: string responses: "200": description: User deleted content: application/json: schema: type: object properties: ok: type: boolean "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" /api/auth/users/{id}/reset-password: post: tags: [Auth] summary: Reset user password description: Requires users:manage permission. security: - bearerAuth: [] parameters: - name: id in: path required: true description: User UUID schema: type: string requestBody: required: true content: application/json: schema: type: object required: [newPassword] properties: newPassword: type: string format: password responses: "200": description: Password reset content: application/json: schema: type: object properties: ok: type: boolean "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" # ─── API Keys ───────────────────────────────────────────────────────────── /api/v1/api-keys: post: tags: [API Keys] summary: Create an API key description: > Generate a new API key. The full key (prefixed with si_) is returned only once. Keys are stored using scrypt hashing. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: name: type: string maxLength: 100 default: Default API Key permissions: type: array items: type: string description: Scoped permissions for this key expiresAt: type: string format: date-time description: Optional expiration date responses: "201": description: API key created content: application/json: schema: type: object properties: id: type: string key: type: string description: Full key (only shown once) name: type: string permissions: type: array items: type: string expiresAt: type: string format: date-time nullable: true createdAt: type: string format: date-time "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" get: tags: [API Keys] summary: List API keys description: Returns key metadata but not the full key. security: - bearerAuth: [] responses: "200": description: List of API keys content: application/json: schema: type: object properties: apiKeys: type: array items: type: object properties: id: type: string name: type: string permissions: type: array items: type: string createdAt: type: string format: date-time lastUsedAt: type: string format: date-time nullable: true expiresAt: type: string format: date-time nullable: true "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/api-keys/{id}: delete: tags: [API Keys] summary: Delete an API key security: - bearerAuth: [] parameters: - name: id in: path required: true description: API key UUID schema: type: string responses: "200": description: API key deleted content: application/json: schema: type: object properties: ok: type: boolean "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" # ─── Settings ───────────────────────────────────────────────────────────── /api/v1/settings: get: tags: [Settings] summary: Get all settings security: - bearerAuth: [] responses: "200": description: All settings wrapped in a settings object content: application/json: schema: type: object properties: settings: type: object additionalProperties: type: string "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" put: tags: [Settings] summary: Update settings description: Accepts a flat JSON object of key-value pairs to set. Requires admin role. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object additionalProperties: type: string responses: "200": description: Settings updated content: application/json: schema: type: object properties: ok: type: boolean updatedCount: type: integer "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Admin access required content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" /api/v1/settings/{key}: get: tags: [Settings] summary: Get a single setting security: - bearerAuth: [] parameters: - name: key in: path required: true description: Setting key name schema: type: string responses: "200": description: Setting value content: application/json: schema: type: object properties: key: type: string value: type: string updatedAt: type: string format: date-time "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "404": description: Setting not found content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" # ─── Teams ──────────────────────────────────────────────────────────────── /api/v1/teams: get: tags: [Teams] summary: List teams description: Requires teams:manage permission. security: - bearerAuth: [] responses: "200": description: List of teams content: application/json: schema: type: object properties: teams: type: array items: type: object properties: id: type: string name: type: string memberCount: type: integer createdAt: type: string format: date-time "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" post: tags: [Teams] summary: Create a team description: Requires teams:manage permission. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [name] properties: name: type: string responses: "201": description: Team created content: application/json: schema: type: object properties: id: type: string name: type: string "400": description: Invalid input content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "409": description: Team name already exists content: application/json: schema: $ref: "#/components/schemas/ConflictError" /api/v1/teams/{id}: put: tags: [Teams] summary: Rename a team description: Requires teams:manage permission. security: - bearerAuth: [] parameters: - name: id in: path required: true description: Team UUID schema: type: string requestBody: required: true content: application/json: schema: type: object required: [name] properties: name: type: string responses: "200": description: Team updated content: application/json: schema: type: object properties: ok: type: boolean "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "404": description: Team not found content: application/json: schema: $ref: "#/components/schemas/Error" "409": description: Team name already exists content: application/json: schema: $ref: "#/components/schemas/ConflictError" delete: tags: [Teams] summary: Delete a team description: Requires teams:manage permission. security: - bearerAuth: [] parameters: - name: id in: path required: true description: Team UUID schema: type: string responses: "200": description: Team deleted content: application/json: schema: type: object properties: ok: type: boolean "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "404": description: Team not found content: application/json: schema: $ref: "#/components/schemas/Error" # ─── System (additional) ────────────────────────────────────────────────── /api/v1/config/auth: get: tags: [System] summary: Auth configuration security: [] responses: "200": description: Auth config content: application/json: schema: type: object properties: authEnabled: type: boolean /api/v1/jobs/{jobId}/progress: get: tags: [System] summary: Job progress (SSE) description: > Server-Sent Events stream for tracking long-running jobs. Closes automatically 5 seconds after completion. security: [] parameters: - name: jobId in: path required: true description: Job UUID from a tool processing or installation response schema: type: string responses: "200": description: > SSE stream of job progress events. Two event types: `single` (single-file tools) and `batch` (batch processing). Single events have `status` and `progress`. Batch events have `completedFiles`, `totalFiles`, `failedFiles` (integers), and an `errors` array. content: text/event-stream: schema: type: object description: > Event shape varies by type. Single: { status, progress }. Batch: { completedFiles, totalFiles, failedFiles, errors }. properties: status: type: string enum: [processing, completed, failed] progress: type: integer minimum: 0 maximum: 100 completedFiles: type: integer description: Number of completed files (batch mode) totalFiles: type: integer description: Total files to process (batch mode) failedFiles: type: integer description: Number of failed files (batch mode) errors: type: array items: type: object properties: filename: type: string error: type: string description: Error details for failed files (batch mode) # ─── Admin ─────────────────────────────────────────────────────────────── /api/v1/admin/health: get: tags: [Admin] summary: Admin health check description: | Full system diagnostics including database status, storage mode, queue state, and GPU availability. Requires the system:health permission. security: - bearerAuth: [] responses: "200": description: Detailed system health content: application/json: schema: $ref: "#/components/schemas/AdminHealthResponse" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" # ─── Analytics ─────────────────────────────────────────────────────────── /api/v1/config/analytics: get: tags: [Analytics] summary: Get analytics configuration description: | Returns analytics provider configuration. When ANALYTICS_ENABLED is false on the server, all values are empty. Public endpoint. security: [] responses: "200": description: Analytics configuration content: application/json: schema: type: object properties: enabled: type: boolean posthogApiKey: type: string posthogHost: type: string sentryDsn: type: string sampleRate: type: number instanceId: type: string /api/v1/user/analytics: put: tags: [Analytics] summary: Update user analytics consent description: | Set the authenticated user's analytics consent preference, or snooze the consent prompt for 7 days with remindLater. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: enabled: type: boolean description: Whether the user consents to analytics remindLater: type: boolean description: Snooze the consent prompt for 7 days responses: "200": description: Consent updated content: application/json: schema: type: object properties: ok: type: boolean analyticsEnabled: type: boolean nullable: true "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" # ─── Features ──────────────────────────────────────────────────────────── /api/v1/features: get: tags: [Features] summary: List feature bundles description: | Returns all available AI feature bundles and their installation status. In non-Docker environments, all bundles show as installed. security: - bearerAuth: [] responses: "200": description: Feature bundle list content: application/json: schema: type: object properties: bundles: type: array items: type: object properties: id: type: string name: type: string description: type: string status: type: string enum: [installed, not_installed, installing, error] installedVersion: type: string nullable: true estimatedSize: type: string enablesTools: type: array items: type: string progress: type: object nullable: true properties: percent: type: number stage: type: string error: type: string nullable: true "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" /api/v1/admin/features/{bundleId}/install: post: tags: [Features] summary: Install a feature bundle description: | Start async installation of an AI feature bundle. Downloads models and configures the Python sidecar. Returns a jobId for progress tracking via the SSE endpoint. Requires features:manage permission. security: - bearerAuth: [] parameters: - name: bundleId in: path required: true description: Feature bundle identifier schema: type: string responses: "202": description: Installation started content: application/json: schema: type: object properties: jobId: type: string description: Job ID for tracking installation progress via SSE "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "404": description: Unknown bundle ID content: application/json: schema: $ref: "#/components/schemas/Error" "409": description: Bundle already installed or another install in progress content: application/json: schema: $ref: "#/components/schemas/ConflictError" /api/v1/admin/features/{bundleId}/uninstall: post: tags: [Features] summary: Uninstall a feature bundle description: | Uninstall an AI feature bundle and delete its model files (unless shared with another installed bundle). Requires features:manage permission. security: - bearerAuth: [] parameters: - name: bundleId in: path required: true description: Feature bundle identifier schema: type: string responses: "200": description: Bundle uninstalled content: application/json: schema: type: object properties: ok: type: boolean "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "404": description: Unknown bundle ID content: application/json: schema: $ref: "#/components/schemas/Error" "409": description: Bundle is not installed content: application/json: schema: $ref: "#/components/schemas/ConflictError" /api/v1/admin/features/disk-usage: get: tags: [Features] summary: AI model disk usage description: | Returns the total disk space used by AI model files. Requires features:manage permission. security: - bearerAuth: [] responses: "200": description: Disk usage content: application/json: schema: type: object properties: totalBytes: type: integer description: Total bytes used by AI model files "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" # ─── Audit Log ─────────────────────────────────────────────────────────── /api/v1/audit-log: get: tags: [Audit] summary: Query audit log description: | Paginated audit log of administrative actions. Supports filtering by action type and date range. Requires audit:read permission. security: - bearerAuth: [] parameters: - name: page in: query description: Page number (default 1) schema: type: integer minimum: 1 default: 1 - name: limit in: query description: Results per page (1-100, default 50) schema: type: integer minimum: 1 maximum: 100 default: 50 - name: action in: query description: Filter by action type schema: type: string - name: from in: query description: Filter entries after this ISO 8601 date schema: type: string format: date-time - name: to in: query description: Filter entries before this ISO 8601 date schema: type: string format: date-time responses: "200": description: Paginated audit log entries content: application/json: schema: type: object properties: entries: type: array items: type: object properties: id: type: string actorId: type: string actorUsername: type: string action: type: string targetType: type: string targetId: type: string details: type: object nullable: true ipAddress: type: string createdAt: type: string format: date-time total: type: integer description: Total matching entries page: type: integer limit: type: integer "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" # ─── Roles ─────────────────────────────────────────────────────────────── /api/v1/roles: get: tags: [Roles] summary: List roles description: | List all roles (built-in and custom) with their permissions and user counts. Requires audit:read permission. security: - bearerAuth: [] responses: "200": description: Role list content: application/json: schema: type: object properties: roles: type: array items: type: object properties: id: type: string name: type: string description: type: string permissions: type: array items: type: string isBuiltin: type: boolean userCount: type: integer createdAt: type: string format: date-time updatedAt: type: string format: date-time "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" post: tags: [Roles] summary: Create a custom role description: | Create a new custom role with specified permissions. Role names must be 2-30 characters, lowercase alphanumeric with hyphens and underscores. Requires users:manage permission. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [name, permissions] properties: name: type: string minLength: 2 maxLength: 30 pattern: "^[a-z0-9_-]+$" description: Lowercase role name description: type: string description: Human-readable description permissions: type: array items: type: string description: | Permission strings. Valid values: tools:use, files:own, files:all, apikeys:own, apikeys:all, pipelines:own, pipelines:all, settings:read, settings:write, users:manage, teams:manage, features:manage, system:health, audit:read responses: "201": description: Role created content: application/json: schema: type: object properties: id: type: string name: type: string description: type: string permissions: type: array items: type: string isBuiltin: type: boolean "400": description: Validation error content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "409": description: Role name already exists content: application/json: schema: $ref: "#/components/schemas/ConflictError" /api/v1/roles/{id}: put: tags: [Roles] summary: Update a custom role description: | Update name, description, or permissions of a custom role. Built-in roles cannot be modified. Requires users:manage permission. security: - bearerAuth: [] parameters: - name: id in: path required: true description: Role UUID schema: type: string requestBody: required: true content: application/json: schema: type: object properties: name: type: string minLength: 2 maxLength: 30 description: type: string permissions: type: array items: type: string responses: "200": description: Role updated content: application/json: schema: type: object properties: ok: type: boolean "400": description: Validation error or cannot modify built-in role content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "404": description: Role not found content: application/json: schema: $ref: "#/components/schemas/Error" "409": description: Role name already exists content: application/json: schema: $ref: "#/components/schemas/ConflictError" delete: tags: [Roles] summary: Delete a custom role description: | Delete a custom role. Users assigned to this role are reassigned to the default "user" role. Built-in roles cannot be deleted. Requires users:manage permission. security: - bearerAuth: [] parameters: - name: id in: path required: true description: Role UUID schema: type: string responses: "200": description: Role deleted content: application/json: schema: type: object properties: ok: type: boolean "400": description: Cannot delete built-in role content: application/json: schema: $ref: "#/components/schemas/Error" "401": description: Authentication required content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "403": description: Insufficient permissions content: application/json: schema: $ref: "#/components/schemas/ForbiddenError" "404": description: Role not found content: application/json: schema: $ref: "#/components/schemas/Error"