Tags
The Tags API provides endpoints for creating, managing, and applying tags to images. Tags can be organized hierarchically with parent-child relationships. All endpoints require JWT authentication.
Tag Management
Section titled “Tag Management”Get All Tags
Section titled “Get All Tags”Endpoint: GET /api/tags
Query Parameters:
searchTerm(string, optional) - Filter tags by name (max 255 characters)parentId(string, optional) - Filter by parent tag UUID for nested tagsrootOnly(boolean, optional) - Return only root-level tags (no parent)includeChildren(boolean, optional) - Include child tags in resultslimit(integer, optional) - Number of results per page (1-100, default: 50)page(integer, optional) - Page number (default: 1)orderBy(string, optional) - Sort field:name,path,createdAt,updatedAt(default:name)order(string, optional) - Sort direction:asc,desc(default:asc)
Response:
HTTP 200 OK
{ "meta": { "size": 10, "page": 1, "total": 6 }, "data": [ { "id": "52257a45-5799-4755-8407-29fd16dbb634", "name": "Nature", "path": "#Nature", "children": [ { "id": "0c1d58ad-713e-4f36-a733-099ced68829b", "name": "Mountains", "path": "#Nature/Mountains", "children": [], "createdAt": { "formattedDate": "2025-10-04 23:03:03", "timestamp": 1759608183 }, "updatedAt": { "formattedDate": "2025-10-04 23:03:03", "timestamp": 1759608183 }, "isRoot": false, "depth": 2, "imageCount": 0 } ], "createdAt": { "formattedDate": "2025-10-04 20:24:58", "timestamp": 1759598698 }, "updatedAt": { "formattedDate": "2025-10-04 20:24:58", "timestamp": 1759598698 }, "isRoot": true, "depth": 1, "imageCount": 1 } ]}Response Fields:
id- Tag UUIDname- Tag namepath- Full hierarchical path (e.g.,#Nature/Mountains)children- Array of child tags (whenincludeChildrenis true)createdAt- Creation timestamp with formatted dateupdatedAt- Last update timestamp with formatted dateisRoot- Whether tag is at root level (no parent)depth- Hierarchical depth level (1 for root, 2+ for nested)imageCount- Number of images tagged with this tag
Get Tag by ID
Section titled “Get Tag by ID”Endpoint: GET /api/tags/{id}
Parameters:
id(string) - Tag UUID
Response:
HTTP 200 OK
{ "id": "52257a45-5799-4755-8407-29fd16dbb634", "name": "Nature", "path": "#Nature", "children": [], "createdAt": { "formattedDate": "2025-10-04 20:24:58", "timestamp": 1759598698 }, "updatedAt": { "formattedDate": "2025-10-04 20:24:58", "timestamp": 1759598698 }, "isRoot": true, "depth": 1, "imageCount": 1}Create Tag
Section titled “Create Tag”Endpoint: POST /api/tags
Request Body:
{ "name": "Landscapes", "parentId": "parent-tag-uuid"}Parameters:
name(string, required) - Tag name (1-50 characters, alphanumeric with hyphens and underscores only)parentId(string, optional) - Parent tag UUID for nested tags
Response:
HTTP 201 CreatedLocation: /api/tags/new-tag-uuid
{ "id": "new-tag-uuid"}Delete Tag
Section titled “Delete Tag”Endpoint: DELETE /api/tags/{id}
Parameters:
id(string) - Tag UUID to delete
Response:
HTTP 204 No ContentDeleting a tag removes it from all associated images. Nested child tags may be handled based on cascade rules.
Image Tagging
Section titled “Image Tagging”Get Image Tags
Section titled “Get Image Tags”Endpoint: GET /api/images/{imageId}/tags
Parameters:
imageId(string) - Image UUID
Response:
HTTP 200 OK
{ "data": [ { "id": "52257a45-5799-4755-8407-29fd16dbb634", "name": "Nature", "path": "#Nature", "children": [], "createdAt": { "formattedDate": "2025-10-04 20:24:58", "timestamp": 1759598698 }, "updatedAt": { "formattedDate": "2025-10-04 20:24:58", "timestamp": 1759598698 }, "isRoot": true, "depth": 1, "imageCount": 1 }, { "id": "0c1d58ad-713e-4f36-a733-099ced68829b", "name": "Mountains", "path": "#Nature/Mountains", "children": [], "createdAt": { "formattedDate": "2025-10-04 23:03:03", "timestamp": 1759608183 }, "updatedAt": { "formattedDate": "2025-10-04 23:03:03", "timestamp": 1759608183 }, "isRoot": false, "depth": 2, "imageCount": 0 } ]}Tag Image
Section titled “Tag Image”Endpoint: POST /api/images/{imageId}/tags/{tagId}
Parameters:
imageId(string) - Image UUID to tagtagId(string) - Tag UUID to apply
Response:
HTTP 204 No ContentUser must own the image to tag it. Tag must exist and belong to the user. Duplicate tagging is idempotent.
Untag Image
Section titled “Untag Image”Endpoint: DELETE /api/images/{imageId}/tags/{tagId}
Parameters:
imageId(string) - Image UUIDtagId(string) - Tag UUID to remove
Response:
HTTP 204 No ContentRemoves the association between image and tag without deleting either. User must own the image.
Nested Tags
Section titled “Nested Tags”Tags can be organized hierarchically with parent-child relationships.
Example Hierarchy:
Nature (parent)├── Landscapes│ ├── Mountains│ └── Beaches└── Wildlife ├── Birds └── MammalsCreating Nested Tags:
- Create parent tag:
POST /api/tags{ "name": "Nature"}- Create child tag with parent reference:
POST /api/tags{ "name": "Mountains", "parentId": "nature-tag-uuid"}Filtering by Parent:
GET /api/tags?parentId=nature-tag-uuidError Responses
Section titled “Error Responses”Validation Error (HTTP 422)
Section titled “Validation Error (HTTP 422)”{ "error": { "title": "Symfony.Component.HttpKernel.Exception.HttpException", "message": "Validation Error", "violations": [ { "property": "name", "message": "This value should not be blank." } ] }}Unauthorized (HTTP 401)
Section titled “Unauthorized (HTTP 401)”Returned when no valid authentication is provided.
{ "error": { "message": "Authentication failed" }}Not Found (HTTP 404)
Section titled “Not Found (HTTP 404)”Returned when the requested tag does not exist.