9.0 KiB
Image Upload & Management API
Upload images and manage your image library. For generation, see 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):
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
{
"success": true,
"data": {
"id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a",
"projectId": "57c7f7f4-47de-4d70-9ebd-3807a0b63746",
"flowId": null,
"storageKey": "default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a",
"storageUrl": "https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a",
"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"
}
}
Note: The
idfield equals the filename in storage (UUID). Original filename is preserved in object metadata.
flowId Behavior
| Value | Behavior |
|---|---|
| Not provided | Auto-generate pendingFlowId, lazy flow creation |
null |
No flow association |
"uuid" |
Associate with specified flow |
Upload with Flow
# 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:
{
"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:
{
"success": true,
"data": {
"id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a",
"projectId": "57c7f7f4-47de-4d70-9ebd-3807a0b63746",
"flowId": null,
"storageKey": "default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a",
"storageUrl": "https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a",
"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:
// 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:
// 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:
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:
outputImageIdset to null - Flow aliases: image removed from flow's aliases
- Referenced images: removed from generation's referencedImages
- Related generations:
Response: 200 OK
{
"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 (same as filename in storage) |
projectId |
string | Project UUID |
flowId |
string | Associated flow UUID (null if none) |
storageKey |
string | Storage path: {org}/{project}/img/{imageId} |
storageUrl |
string | CDN URL: https://cdn.banatie.app/{org}/{project}/img/{imageId} |
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 CDN access:
<!-- Direct access via UUID -->
<img src="https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a" />
<!-- Access via alias (goes through API) -->
<img src="https://cdn.banatie.app/default/my-project/img/@brand-logo" />
Note: UUID URLs are served directly from MinIO (fast, cacheable). Alias URLs require API resolution.
Storage Organization
Images are stored in MinIO with a simplified path structure:
bucket/
{orgSlug}/
{projectSlug}/
img/
{imageId} # UUID, no file extension
{imageId} # Content-Type in object metadata
...
Key points:
- Filename = Image ID (UUID) - No file extensions
- Content-Type stored in MinIO object metadata
- Original filename preserved in metadata for reference
- Single
img/directory for all images (generated + uploaded)
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 - Generate images
- Advanced Generation - References, aliases, flows
- Live URLs - CDN and public access