# Image Upload & Management API Upload images and manage your image library. For generation, see [image-generation.md](image-generation.md). All endpoints require Project Key authentication via `X-API-Key` header. --- ## Upload Image ``` POST /api/v1/images/upload ``` Upload an image file with optional alias and flow association. **Content-Type:** `multipart/form-data` **Form Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `file` | file | Yes | Image file (PNG, JPEG, WebP) | | `alias` | string | No | Project-scoped alias (e.g., `@logo`) | | `flowId` | string | No | Flow UUID to associate with | | `flowAlias` | string | No | Flow-scoped alias (requires flowId) | | `meta` | string | No | JSON string with custom metadata | **File Constraints:** | Constraint | Limit | |------------|-------| | Max file size | 5MB | | Supported formats | PNG, JPEG, JPG, WebP | | MIME types | `image/png`, `image/jpeg`, `image/webp` | **Example Request (curl):** ```bash curl -X POST http://localhost:3000/api/v1/images/upload \ -H "X-API-Key: YOUR_PROJECT_KEY" \ -F "file=@logo.png" \ -F "alias=@brand-logo" \ -F 'meta={"tags": ["logo", "brand"]}' ``` **Response:** `201 Created` ```json { "success": true, "data": { "id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a", "projectId": "57c7f7f4-47de-4d70-9ebd-3807a0b63746", "flowId": null, "storageKey": "default/project-id/uploads/2025-11/logo.png", "storageUrl": "http://localhost:9000/banatie/default/project-id/uploads/logo.png", "mimeType": "image/png", "fileSize": 45678, "width": 512, "height": 512, "source": "uploaded", "alias": "@brand-logo", "focalPoint": null, "meta": { "tags": ["logo", "brand"] }, "createdAt": "2025-11-28T10:00:00.000Z" } } ``` ### flowId Behavior | Value | Behavior | |-------|----------| | Not provided | Auto-generate `pendingFlowId`, lazy flow creation | | `null` | No flow association | | `"uuid"` | Associate with specified flow | ### Upload with Flow ```bash # Associate with existing flow curl -X POST .../images/upload \ -F "file=@reference.png" \ -F "flowId=flow-123" \ -F "flowAlias=@reference" ``` --- ## List Images ``` GET /api/v1/images ``` List all images with filtering and pagination. **Query Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `flowId` | string | - | Filter by flow UUID | | `source` | string | - | Filter by source: `generated`, `uploaded` | | `alias` | string | - | Filter by exact alias match | | `limit` | number | `20` | Results per page (max: 100) | | `offset` | number | `0` | Pagination offset | | `includeDeleted` | boolean | `false` | Include soft-deleted records | **Example:** ``` GET /api/v1/images?source=uploaded&limit=10 ``` **Response:** ```json { "success": true, "data": [ { "id": "7c4ccf47-...", "storageUrl": "http://...", "source": "uploaded", "alias": "@brand-logo", "width": 512, "height": 512, "createdAt": "2025-11-28T10:00:00.000Z" } ], "pagination": { "limit": 10, "offset": 0, "total": 25, "hasMore": true } } ``` --- ## Get Image ``` GET /api/v1/images/:id_or_alias ``` Get a single image by UUID or alias. **Path Parameter:** - `id_or_alias` - Image UUID or `@alias` **Query Parameters:** | Parameter | Type | Description | |-----------|------|-------------| | `flowId` | string | Flow context for alias resolution | **Examples:** ``` # By UUID GET /api/v1/images/7c4ccf47-41ce-4718-afbc-8c553b2c631a # By project alias GET /api/v1/images/@brand-logo # By technical alias (requires flowId) GET /api/v1/images/@last?flowId=flow-123 # By flow alias GET /api/v1/images/@hero?flowId=flow-123 ``` **Response:** ```json { "success": true, "data": { "id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a", "projectId": "57c7f7f4-47de-4d70-9ebd-3807a0b63746", "flowId": null, "storageKey": "default/project-id/uploads/2025-11/logo.png", "storageUrl": "http://localhost:9000/banatie/.../logo.png", "mimeType": "image/png", "fileSize": 45678, "width": 512, "height": 512, "source": "uploaded", "alias": "@brand-logo", "focalPoint": null, "fileHash": null, "generationId": null, "meta": { "tags": ["logo", "brand"] }, "createdAt": "2025-11-28T10:00:00.000Z", "updatedAt": "2025-11-28T10:00:00.000Z", "deletedAt": null } } ``` --- ## Update Image Metadata ``` PUT /api/v1/images/:id_or_alias ``` Update image metadata (focal point, custom metadata). **Request Body:** | Parameter | Type | Description | |-----------|------|-------------| | `focalPoint` | object | Focal point: `{ x: 0.0-1.0, y: 0.0-1.0 }` | | `meta` | object | Custom metadata | **Example:** ```json // PUT /api/v1/images/@brand-logo { "focalPoint": { "x": 0.5, "y": 0.3 }, "meta": { "description": "Updated brand logo", "tags": ["logo", "brand", "2025"] } } ``` **Response:** Updated image object. > **Note:** Alias assignment has its own dedicated endpoint. --- ## Assign Alias ``` PUT /api/v1/images/:id_or_alias/alias ``` Assign or remove a project-scoped alias. **Request Body:** ```json // Assign alias { "alias": "@new-logo" } // Remove alias { "alias": null } ``` **Override Behavior:** - If another image has this alias, it loses the alias - The new image gets the alias - Old image is preserved, just unlinked **Example:** ```bash curl -X PUT http://localhost:3000/api/v1/images/7c4ccf47-.../alias \ -H "X-API-Key: YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"alias": "@primary-logo"}' ``` --- ## Delete Image ``` DELETE /api/v1/images/:id_or_alias ``` Permanently delete an image and its storage file. **Behavior:** - **Hard delete** - image record permanently removed - Storage file deleted from MinIO - Cascading updates: - Related generations: `outputImageId` set to null - Flow aliases: image removed from flow's aliases - Referenced images: removed from generation's referencedImages **Response:** `200 OK` ```json { "success": true, "message": "Image deleted" } ``` > **Warning:** This cannot be undone. The image file is permanently removed. --- ## Image Response Fields | Field | Type | Description | |-------|------|-------------| | `id` | string | Image UUID | | `projectId` | string | Project UUID | | `flowId` | string | Associated flow UUID (null if none) | | `storageKey` | string | Internal storage path | | `storageUrl` | string | **Direct URL to access image** | | `mimeType` | string | Image MIME type | | `fileSize` | number | File size in bytes | | `width` | number | Image width in pixels | | `height` | number | Image height in pixels | | `source` | string | `"generated"` or `"uploaded"` | | `alias` | string | Project-scoped alias (null if none) | | `focalPoint` | object | `{ x, y }` coordinates (0.0-1.0) | | `fileHash` | string | SHA-256 hash for deduplication | | `generationId` | string | Source generation UUID (if generated) | | `meta` | object | Custom metadata | | `createdAt` | string | ISO timestamp | | `updatedAt` | string | ISO timestamp | | `deletedAt` | string | Soft delete timestamp (null if active) | ### Accessing Images Use `storageUrl` for direct image access: ```html ``` For public CDN access, see [Live URLs](live-url.md). --- ## Storage Organization Images are organized in MinIO storage: ``` bucket/ {orgId}/ {projectId}/ uploads/ # Uploaded images 2025-11/ image.png generated/ # AI-generated images 2025-11/ gen_abc123.png ``` --- ## Error Codes | HTTP Status | Code | Description | |-------------|------|-------------| | 400 | `VALIDATION_ERROR` | Invalid parameters | | 400 | `FILE_TOO_LARGE` | File exceeds 5MB limit | | 400 | `UNSUPPORTED_FILE_TYPE` | Not PNG, JPEG, or WebP | | 400 | `ALIAS_FORMAT_CHECK` | Alias must start with @ | | 401 | `UNAUTHORIZED` | Missing or invalid API key | | 404 | `IMAGE_NOT_FOUND` | Image or alias doesn't exist | | 404 | `ALIAS_NOT_FOUND` | Alias doesn't resolve to any image | --- ## See Also - [Basic Generation](image-generation.md) - Generate images - [Advanced Generation](image-generation-advanced.md) - References, aliases, flows - [Live URLs](live-url.md) - CDN and public access