375 lines
8.3 KiB
Markdown
375 lines
8.3 KiB
Markdown
# 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
|
|
<img src="http://localhost:9000/banatie/.../image.png" />
|
|
```
|
|
|
|
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
|