Skip to main content
All asset management endpoints require authentication via JWT Bearer token or API key. See Authentication for details.

Upload an asset

POST /api/v1/assets
Content-Type: multipart/form-data
Uploads a new image asset. The request must be multipart/form-data. On success, the server returns 202 Accepted and begins background processing (enrichment, derivative generation) if runEnrichment is enabled.

Request fields

file
file
required
The image file to upload. Must not be empty. Allowed content types are configured server-side (typically image/png, image/jpeg, image/gif, image/webp, etc.).
description
string
Optional description for the asset. Maximum 1000 characters.
altText
string
Optional alt text for the asset. Maximum 1000 characters.
isPublic
boolean
Whether the asset should be publicly accessible. Defaults to true.
storageProviderProfileId
string (uuid)
Optional. The ID of the storage provider profile to use. If omitted, the default storage provider is used.
runEnrichment
boolean
Whether to run AI enrichment after upload. Defaults to true.
commitMessage
string
Optional commit message for storage providers that support it (e.g. GitHub Repo).

Response — 202 Accepted

data
object

Errors

CodeDescription
asset_file_requiredThe file field was not included in the request.
asset_file_emptyThe uploaded file has zero bytes.
asset_file_too_largeThe file exceeds the configured maximum upload size.
asset_content_type_not_allowedThe file’s content type is not in the allowed list.
asset_description_too_longDescription exceeds 1000 characters.
asset_alt_text_too_longAlt text exceeds 1000 characters.

Example

curl -X POST http://localhost:5121/api/v1/assets \
  -H "Authorization: Bearer <token>" \
  -F "file=@kitten.png" \
  -F "description=A fluffy orange kitten" \
  -F "altText=Orange cat looking at camera" \
  -F "isPublic=true" \
  -F "runEnrichment=true"

List assets

GET /api/v1/assets
Returns a paginated list of all assets visible to the authenticated user.

Query parameters

page
integer
Page number. Defaults to 1.
pageSize
integer
Number of results per page. Defaults to the server-configured default, capped at the configured maximum.
query
string
Free-text search. Also accepted as keyword. Matches file name, description, and alt text.
contentType
string
Filter by MIME type (e.g. image/jpeg).
status
string
Filter by processing status. One of: pending, processing, ready, failed.
orderBy
string
Field to sort by. Also accepted as sortBy. Supported values: createdAtUtc (default), size.
orderDirection
string
Sort direction. Also accepted as sortDirection. One of: asc, desc (default).

Response

data
object

Example

curl "http://localhost:5121/api/v1/assets?page=1&pageSize=20&orderBy=createdAtUtc&orderDirection=desc" \
  -H "Authorization: Bearer your-api-key"

Get an asset

GET /api/v1/assets/{id}
Returns full details for a single asset, including all derivatives and structured AI results.

Path parameters

id
string (uuid)
required
The unique identifier of the asset.

Response

data
object
Returns 404 Not Found with error code asset_not_found if the asset does not exist.

Example

curl http://localhost:5121/api/v1/assets/01956f8d-88e4-7c6a-a8f1-5f235293db7a \
  -H "Authorization: Bearer <token>"

Update asset metadata

PATCH /api/v1/assets/{id}
Updates metadata fields for an existing asset. Only fields you include in the request body are changed (patch semantics).

Path parameters

id
string (uuid)
required
The unique identifier of the asset to update.

Request body

description
string
New description. Maximum 1000 characters. Omit to leave unchanged.
altText
string
New alt text. Maximum 1000 characters. Omit to leave unchanged.
originalFileName
string
New original filename. Omit to leave unchanged.
isPublic
boolean
Change public visibility. Omit to leave unchanged.

Response

Returns the full updated asset object (same shape as Get an asset).

Example

curl -X PATCH http://localhost:5121/api/v1/assets/01956f8d-88e4-7c6a-a8f1-5f235293db7a \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"description": "Updated description", "isPublic": false}'

Delete an asset

DELETE /api/v1/assets/{id}
Permanently deletes an asset. This is a hard delete — the asset record and its file in storage are both removed.

Path parameters

id
string (uuid)
required
The unique identifier of the asset to delete.

Request body (optional)

commitMessage
string
Optional commit message for storage backends that support versioning (e.g. GitHub Repo).

Response

data
object
Returns 404 Not Found with error code asset_not_found if the asset does not exist.

Example

curl -X DELETE http://localhost:5121/api/v1/assets/01956f8d-88e4-7c6a-a8f1-5f235293db7a \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"commitMessage": "Remove test asset"}'

Batch delete assets

POST /api/v1/assets/batch-delete
Deletes multiple assets in one request. Assets that do not exist are silently skipped and reported in notFoundIds.

Request body

ids
array of strings (uuid)
required
An array of asset IDs to delete.

Response

data
object

Example

curl -X POST http://localhost:5121/api/v1/assets/batch-delete \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '["01956f8d-88e4-7c6a-a8f1-5f235293db7a", "01956f8d-0000-0000-0000-000000000001"]'

Get asset content

GET /api/v1/assets/{id}/content
Accesses the content of an asset, with access control applied:
  • Public asset: Returns a 307 Temporary Redirect to the public content URL.
  • Private asset: Streams the content directly (requires valid JWT or API key).

Path parameters

id
string (uuid)
required
The unique identifier of the asset.
Returns 404 Not Found with error code asset_not_found if the asset does not exist.

Example

# For a public asset — follow the redirect
curl -L http://localhost:5121/api/v1/assets/01956f8d-88e4-7c6a-a8f1-5f235293db7a/content \
  -H "Authorization: Bearer <token>"

# For a private asset — save to file
curl http://localhost:5121/api/v1/assets/01956f8d-88e4-7c6a-a8f1-5f235293db7a/content \
  -H "Authorization: Bearer <token>" \
  -o asset.png

List available skills

GET /api/v1/assets/skills
Returns a list of AI skills available to run against assets.

Response

data
array

Example

curl http://localhost:5121/api/v1/assets/skills \
  -H "Authorization: Bearer your-api-key"

Run a skill on an asset

POST /api/v1/assets/{id}/skills/{skillName}/run
Triggers an AI skill to run against a specific asset. Skills can generate captions, alt text, thumbnails, and other derived outputs.

Path parameters

id
string (uuid)
required
The unique identifier of the asset.
skillName
string
required
The name of the skill to run. Use List available skills to discover valid skill names.

Request body (optional)

parameters
object
Optional skill-specific parameters as a JSON object. The accepted parameters depend on the skill being run.

Response

data
object

Example

curl -X POST http://localhost:5121/api/v1/assets/01956f8d-88e4-7c6a-a8f1-5f235293db7a/skills/caption/run \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{}'

Get usage statistics

GET /api/v1/assets/usage-stats
Returns aggregate usage statistics across all assets.

Response

data
object

Example

curl http://localhost:5121/api/v1/assets/usage-stats \
  -H "Authorization: Bearer <token>"
{
  "data": {
    "totalAssets": 42,
    "totalBytes": 104857600,
    "totalDerivatives": 38,
    "contentTypeBreakdown": [
      { "contentType": "image/png", "count": 25, "totalBytes": 62914560 },
      { "contentType": "image/jpeg", "count": 17, "totalBytes": 41943040 }
    ],
    "mostActiveSkill": {
      "skillName": "caption",
      "runCount": 30
    }
  }
}