# Item

## Endpoints Overview

| Method | Endpoint                          | Description                    |
| ------ | --------------------------------- | ------------------------------ |
| GET    | `/api/v2/item/get`                | List items with filters        |
| POST   | `/api/v2/item/get`                | List items with filters (body) |
| POST   | `/api/v2/item/query`              | Full-text search               |
| GET    | `/api/v2/item/countAll`           | Count all items                |
| POST   | `/api/v2/item/add`                | Add a new item                 |
| POST   | `/api/v2/item/update`             | Update an item                 |
| POST   | `/api/v2/item/setCustomThumbnail` | Set a custom thumbnail         |
| POST   | `/api/v2/item/refreshThumbnail`   | Refresh item thumbnail         |

***

## GET /api/v2/item/get <a href="#list" id="list"></a>

List items with optional filtering. Returns paginated results.

### Query Parameters

* `id` string (optional) — Return a single item by ID
* `ids` string (optional) — Comma-separated item IDs
* `isSelected` boolean (optional) — Return currently selected items
* `isUntagged` boolean (optional) — Return items without tags
* `isUnfiled` boolean (optional) — Return items not in any folder
* `keywords` string (optional) — Filter by keywords (comma-separated)
* `tags` string (optional) — Filter by tags (comma-separated)
* `folders` string (optional) — Filter by folder IDs (comma-separated)
* `ext` string (optional) — Filter by file extension (e.g., `jpg`, `png`)
* `annotation` string (optional) — Filter by annotation text
* `rating` integer (optional) — Filter by rating (`0`–`5`)
* `url` string (optional) — Filter by source URL
* `shape` string (optional) — Filter by shape: `square`, `portrait`, `panoramic-portrait`, `landscape`, `panoramic-landscape`
* `fields` string (optional) — Comma-separated list of fields to return (improves performance)
* `offset` integer (optional) — Pagination offset, default `0`
* `limit` integer (optional) — Pagination limit, default `50`, max `1000`

### Response

```json
{
    "status": "success",
    "data": {
        "data": [
            {
                "id": "M3QSGJNQTC2DG",
                "name": "sunset-photo",
                "ext": "jpg",
                "width": 1920,
                "height": 1080,
                "url": "https://example.com/photo.jpg",
                "tags": ["nature", "sunset"],
                "folders": ["FOLDER_ID_1"],
                "star": 4,
                "annotation": "Beautiful sunset at the beach",
                "modificationTime": 1700000000000
            }
        ],
        "total": 1250,
        "offset": 0,
        "limit": 50
    }
}
```

### Examples

```javascript
// List first 50 items (default)
await fetch("http://localhost:41595/api/v2/item/get").then(r => r.json());

// Get a single item by ID
await fetch("http://localhost:41595/api/v2/item/get?id=M3QSGJNQTC2DG").then(r => r.json());

// Filter by extension with pagination
await fetch("http://localhost:41595/api/v2/item/get?ext=png&offset=0&limit=100").then(r => r.json());

// Return only specific fields for better performance
await fetch("http://localhost:41595/api/v2/item/get?fields=id,name,tags").then(r => r.json());
```

***

## POST /api/v2/item/get <a href="#list-post" id="list-post"></a>

Same as GET, but accepts filter parameters in the JSON body. Useful for complex queries with arrays.

### Request Body

* `id` string (optional) — Item ID
* `ids` string\[] (optional) — Array of item IDs
* `isSelected` boolean (optional) — Currently selected items
* `isUntagged` boolean (optional) — Items without tags
* `isUnfiled` boolean (optional) — Items not in any folder
* `keywords` string\[] (optional) — Keywords to match
* `tags` string\[] (optional) — Tags to match
* `folders` string\[] (optional) — Folder IDs to match
* `smartFolders` string\[] (optional) — Filter by smart folder IDs (OR logic, matches any)
* `ext` string (optional) — File extension
* `annotation` string (optional) — Annotation text
* `rating` integer (optional) — Rating (`0`–`5`)
* `url` string (optional) — Source URL
* `shape` string (optional) — Image shape
* `fields` string\[] (optional) — Fields to return
* `offset` integer (optional) — Pagination offset, default `0`
* `limit` integer (optional) — Pagination limit, default `50`, max `1000`

### Examples

```javascript
// Filter by tags
await fetch("http://localhost:41595/api/v2/item/get", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        tags: ["design", "inspiration"],
        limit: 20
    })
}).then(r => r.json());

// Get items by multiple IDs
await fetch("http://localhost:41595/api/v2/item/get", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        ids: ["ITEM_ID_1", "ITEM_ID_2", "ITEM_ID_3"]
    })
}).then(r => r.json());

// Filter JPG files in a specific folder, return only id and name
await fetch("http://localhost:41595/api/v2/item/get", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        ext: "jpg",
        folders: ["FOLDER_ID"],
        fields: ["id", "name", "tags"],
        offset: 0,
        limit: 100
    })
}).then(r => r.json());
```

```javascript
// Filter with smart folders
await fetch("http://localhost:41595/api/v2/item/get", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        smartFolders: ["SMART_FOLDER_ID"],
        tags: ["cat"],
        limit: 20
    })
}).then(r => r.json());
```

{% hint style="info" %}
**Performance Tip:** Use the `fields` parameter to return only the data you need. This significantly improves response time when working with large libraries.
{% endhint %}

***

## POST /api/v2/item/query <a href="#query" id="query"></a>

Full-text search across item names, tags, annotations, URLs, folder names, and more. Supports advanced query syntax. Returns paginated results.

### Request Body

* `query` string — Search query string
* `offset` integer (optional) — Pagination offset, default `0`
* `limit` integer (optional) — Pagination limit, default `50`, max `1000`

### Query Syntax

| Syntax       | Description             | Example             |
| ------------ | ----------------------- | ------------------- |
| `word`       | Must contain word       | `cat`               |
| `a b`        | Must contain both (AND) | `cat dog`           |
| `a OR b`     | Contains either (OR)    | `cat OR dog`        |
| `a \|\| b`   | Contains either (OR)    | `cat \|\| dog`      |
| `-word`      | Must NOT contain        | `cat -dog`          |
| `"phrase"`   | Exact phrase match      | `"orange cat"`      |
| `(a OR b) c` | Grouping                | `(cat OR dog) cute` |

### Examples

```javascript
// Simple search
await fetch("http://localhost:41595/api/v2/item/query", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ query: "sunset" })
}).then(r => r.json());

// Advanced search: items with "cat" or "dog" but not "cartoon"
await fetch("http://localhost:41595/api/v2/item/query", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        query: "(cat OR dog) -cartoon",
        limit: 20
    })
}).then(r => r.json());

// Paginate through search results
await fetch("http://localhost:41595/api/v2/item/query", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ query: "design", offset: 50, limit: 50 })
}).then(r => r.json());
```

***

## GET /api/v2/item/countAll <a href="#count" id="count"></a>

Returns the total number of items in the library.

### Response

```json
{
    "status": "success",
    "data": 12500
}
```

### Example

```javascript
await fetch("http://localhost:41595/api/v2/item/countAll").then(r => r.json());
```

***

## POST /api/v2/item/add <a href="#add" id="add"></a>

Add a new item to Eagle. Supports adding from URL, Base64 data, local file path, or bookmark.

### Request Body

* `id` string (optional) — Custom item ID
* `name` string (optional) — Item name
* `tags` string\[] (optional) — Tags to assign
* `folders` string\[] (optional) — Folder IDs to add the item to
* `annotation` string (optional) — Item annotation
* `website` string (optional) — Source website URL

**Plus one of the following:**

* `url` string — Image URL to download
* `base64` string — Base64 encoded image data
* `path` string — Local file path to import
* `bookmarkURL` string — URL to add as a bookmark

### Examples

```javascript
// Add from URL
await fetch("http://localhost:41595/api/v2/item/add", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        url: "https://example.com/photo.jpg",
        name: "Example Photo",
        tags: ["downloaded", "example"],
        folders: ["FOLDER_ID"]
    })
}).then(r => r.json());

// Add from local file path
await fetch("http://localhost:41595/api/v2/item/add", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        path: "C:\\Users\\User\\Downloads\\design.png",
        name: "My Design",
        tags: ["design"]
    })
}).then(r => r.json());

// Add a bookmark
await fetch("http://localhost:41595/api/v2/item/add", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        bookmarkURL: "https://www.example.com",
        name: "Example Site",
        tags: ["bookmark"]
    })
}).then(r => r.json());

// Batch add multiple items (up to 1000)
await fetch("http://localhost:41595/api/v2/item/add", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        items: [
            { url: "https://example.com/photo1.jpg", name: "Photo 1" },
            { path: "C:\\Users\\User\\Downloads\\design.png", name: "Design" },
            { bookmarkURL: "https://www.example.com", name: "Bookmark" }
        ]
    })
}).then(r => r.json());
```

### Batch Mode

Pass an `items` array to add multiple items at once (up to 1000). Each object in the array follows the same format as single mode, and you can mix `path`, `url`, `bookmarkURL`, and `base64`.

### Response

Single mode returns the new item's ID:

```json
{
    "status": "success",
    "data": { "id": "M3QSGJNQTC2DG" }
}
```

Batch mode returns all new item IDs:

```json
{
    "status": "success",
    "data": { "ids": ["ITEM_ID_1", "ITEM_ID_2", "ITEM_ID_3"] }
}
```

***

## POST /api/v2/item/update <a href="#update" id="update"></a>

Update an existing item's metadata. Only the fields you include will be modified.

### Request Body

* `id` string (required) — The item ID to update

**Modifiable fields:**

* `name` string (optional) — New name
* `tags` string\[] (optional) — Replace tags
* `folders` string\[] (optional) — Replace folder assignments
* `annotation` string (optional) — New annotation
* `url` string (optional) — New source URL
* `star` integer (optional) — Rating, `0`–`5`
* `modificationTime` integer (optional) — Modification timestamp
* `noThumbnail` boolean (optional) — Mark as having no thumbnail
* `noPreview` boolean (optional) — Mark as not previewable
* `isDeleted` boolean (optional) — Move to / restore from trash

### Response

Returns the updated item object.

### Examples

```javascript
// Update item name and tags
await fetch("http://localhost:41595/api/v2/item/update", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        id: "M3QSGJNQTC2DG",
        name: "Updated Name",
        tags: ["tag1", "tag2"],
        star: 5
    })
}).then(r => r.json());

// Move item to trash
await fetch("http://localhost:41595/api/v2/item/update", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        id: "M3QSGJNQTC2DG",
        isDeleted: true
    })
}).then(r => r.json());
```

***

## POST /api/v2/item/setCustomThumbnail <a href="#set-thumbnail" id="set-thumbnail"></a>

Set a custom thumbnail for an item from a local image file.

### Request Body

* `itemId` string (required) — The item ID
* `filePath` string (required) — Path to the thumbnail image

### Example

```javascript
await fetch("http://localhost:41595/api/v2/item/setCustomThumbnail", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        itemId: "M3QSGJNQTC2DG",
        filePath: "C:\\Users\\User\\thumbnails\\custom.png"
    })
}).then(r => r.json());
```

{% hint style="info" %}
This operation is asynchronous. The API waits up to 10 seconds for the thumbnail to be generated before responding.
{% endhint %}

***

## POST /api/v2/item/refreshThumbnail <a href="#refresh-thumbnail" id="refresh-thumbnail"></a>

Regenerate the thumbnail for an item, updating file size, dimensions, and color palette.

### Request Body

* `itemId` string (required) — The item ID

### Example

```javascript
await fetch("http://localhost:41595/api/v2/item/refreshThumbnail", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ itemId: "M3QSGJNQTC2DG" })
}).then(r => r.json());
```

***

## GET /api/v2/item/getComments <a href="#get-comments" id="get-comments"></a>

Get all comments (annotations) for an item. Returns image rect comments or video timestamp comments.

{% hint style="info" %}
**Version Requirement:** This endpoint requires **Eagle 4.0 Build 22** or later.
{% endhint %}

### Query Parameters

* `id` string (required) — The item ID

### Response

```json
{
    "status": "success",
    "data": [
        {
            "id": "MN3DZC0R7XYSZ",
            "x": 324,
            "y": 810,
            "width": 194,
            "height": 208,
            "annotation": "Face area",
            "lastModified": 1774282485915
        }
    ]
}
```

### Example

```javascript
await fetch("http://localhost:41595/api/v2/item/getComments?id=M3QSGJNQTC2DG")
    .then(r => r.json());
```

***

## POST /api/v2/item/addComment <a href="#add-comment" id="add-comment"></a>

Add a comment to an item. Supports two types:

* **Image rect comment** — provide `x`, `y`, `width`, `height` to mark a region on the image
* **Video timestamp comment** — provide `duration` to mark a point on the video timeline

The server automatically generates `id` and `lastModified` fields.

{% hint style="info" %}
**Version Requirement:** This endpoint requires **Eagle 4.0 Build 22** or later.
{% endhint %}

### Request Body

* `id` string (required) — The item ID
* `annotation` string (optional) — Comment text
* `x` number (optional) — Rect X position (image comment)
* `y` number (optional) — Rect Y position (image comment)
* `width` number (optional) — Rect width, must > 0 (image comment)
* `height` number (optional) — Rect height, must > 0 (image comment)
* `duration` number (optional) — Video timestamp in seconds, must >= 0 (video comment)

{% hint style="warning" %}
You must provide either `duration` (video) or all of `x`/`y`/`width`/`height` (image). Providing both or neither will return an error.
{% endhint %}

### Example

```javascript
// Add an image rect comment
await fetch("http://localhost:41595/api/v2/item/addComment", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        id: "M3QSGJNQTC2DG",
        x: 350, y: 480, width: 380, height: 400,
        annotation: "White fluffy toy face"
    })
}).then(r => r.json());

// Add a video timestamp comment
await fetch("http://localhost:41595/api/v2/item/addComment", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        id: "VIDEO_ITEM_ID",
        duration: 65.5,
        annotation: "Important scene"
    })
}).then(r => r.json());
```

***

## POST /api/v2/item/updateComment <a href="#update-comment" id="update-comment"></a>

Update an existing comment. Only the provided fields are updated; `lastModified` is refreshed automatically.

{% hint style="info" %}
**Version Requirement:** This endpoint requires **Eagle 4.0 Build 22** or later.
{% endhint %}

### Request Body

* `id` string (required) — The item ID
* `commentId` string (required) — The comment ID to update
* `annotation` string (optional) — New comment text
* `x` number (optional) — New X position (image comment only)
* `y` number (optional) — New Y position (image comment only)
* `width` number (optional) — New width, must > 0 (image comment only)
* `height` number (optional) — New height, must > 0 (image comment only)
* `duration` number (optional) — New timestamp, must >= 0 (video comment only)

{% hint style="warning" %}
Image comments can only update `x`/`y`/`width`/`height`. Video comments can only update `duration`. Cross-type updates will return an error.
{% endhint %}

### Example

```javascript
await fetch("http://localhost:41595/api/v2/item/updateComment", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        id: "M3QSGJNQTC2DG",
        commentId: "MN3DZC0R7XYSZ",
        annotation: "Updated annotation text"
    })
}).then(r => r.json());
```

***

## POST /api/v2/item/removeComment <a href="#remove-comment" id="remove-comment"></a>

Remove a comment from an item.

{% hint style="info" %}
**Version Requirement:** This endpoint requires **Eagle 4.0 Build 22** or later.
{% endhint %}

### Request Body

* `id` string (required) — The item ID
* `commentId` string (required) — The comment ID to remove

### Example

```javascript
await fetch("http://localhost:41595/api/v2/item/removeComment", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        id: "M3QSGJNQTC2DG",
        commentId: "MN3DZC0R7XYSZ"
    })
}).then(r => r.json());
```

***

## Item Properties <a href="#properties" id="properties"></a>

Items returned by the API contain the following properties:

| Property           | Type      | Description                              |
| ------------------ | --------- | ---------------------------------------- |
| `id`               | string    | Unique item ID                           |
| `name`             | string    | Item name                                |
| `ext`              | string    | File extension                           |
| `width`            | integer   | Image width in pixels                    |
| `height`           | integer   | Image height in pixels                   |
| `url`              | string    | Source URL                               |
| `isDeleted`        | boolean   | Whether the item is in trash             |
| `annotation`       | string    | Item annotation/notes                    |
| `tags`             | string\[] | Array of tag names                       |
| `folders`          | string\[] | Array of folder IDs                      |
| `palettes`         | Object\[] | Color palette information                |
| `size`             | integer   | File size in bytes                       |
| `star`             | integer   | Rating (0–5)                             |
| `modificationTime` | integer   | Last modification timestamp              |
| `noThumbnail`      | boolean   | Whether the file has no thumbnail        |
| `noPreview`        | boolean   | Whether double-click preview is disabled |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developer.eagle.cool/web-api/api/item.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
