> For the complete documentation index, see [llms.txt](https://developer.eagle.cool/web-api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.eagle.cool/web-api/api/tag.md).

# Tag

## Endpoints Overview

| Method | Endpoint                     | Description            |
| ------ | ---------------------------- | ---------------------- |
| GET    | `/api/v2/tag/get`            | List all tags          |
| POST   | `/api/v2/tag/get`            | List tags (body)       |
| GET    | `/api/v2/tag/getRecentTags`  | Get recently used tags |
| GET    | `/api/v2/tag/getStarredTags` | Get starred tags       |
| POST   | `/api/v2/tag/update`         | Rename a tag           |
| POST   | `/api/v2/tag/merge`          | Merge two tags         |

***

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

List all tags in the library. Returns paginated results.

### Query Parameters

* `name` string (optional) — Filter tags by name (substring match)
* `offset` integer (optional) — Pagination offset, default `0`
* `limit` integer (optional) — Pagination limit, default `50`, max `1000`

### Response

```json
{
    "status": "success",
    "data": {
        "data": [
            {
                "name": "design",
                "count": 150,
                "color": "",
                "groups": ["GROUP_ID_1"],
                "pinyin": "design"
            },
            {
                "name": "photography",
                "count": 89,
                "color": "",
                "groups": [],
                "pinyin": "photography"
            }
        ],
        "total": 340,
        "offset": 0,
        "limit": 50
    }
}
```

### Examples

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

// Filter tags by name
await fetch("http://localhost:41595/api/v2/tag/get?name=design").then(r => r.json());

// Paginate through tags
await fetch("http://localhost:41595/api/v2/tag/get?offset=50&limit=100").then(r => r.json());
```

***

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

Same as GET, but accepts filter parameters in the JSON body.

### Request Body

* `name` string (optional) — Filter tags by name (substring match)
* `offset` integer (optional) — Pagination offset, default `0`
* `limit` integer (optional) — Pagination limit, default `50`, max `1000`

### Example

```javascript
await fetch("http://localhost:41595/api/v2/tag/get", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name: "design", limit: 100 })
}).then(r => r.json());
```

***

## GET /api/v2/tag/getRecentTags <a href="#recent" id="recent"></a>

Get recently used tags. Returns paginated results.

### Query Parameters

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

### Response

```json
{
    "status": "success",
    "data": {
        "data": [
            {
                "name": "ui-design",
                "count": 45,
                "color": "",
                "groups": [],
                "pinyin": "ui-design"
            }
        ],
        "total": 12,
        "offset": 0,
        "limit": 50
    }
}
```

### Example

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

***

## GET /api/v2/tag/getStarredTags <a href="#starred" id="starred"></a>

Get starred (pinned) tags. Returns paginated results.

### Query Parameters

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

### Response

Same format as `/api/v2/tag/getRecentTags`.

### Example

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

***

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

Rename an existing tag. All items using this tag will be updated automatically.

### Request Body

* `originalName` string (required) — The current tag name
* `name` string (required) — The new tag name

### Response

Returns the updated tag object.

```json
{
    "status": "success",
    "data": {
        "name": "new-tag-name",
        "count": 45,
        "color": "",
        "groups": [],
        "pinyin": "new-tag-name"
    }
}
```

### Example

```javascript
await fetch("http://localhost:41595/api/v2/tag/update", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        originalName: "old-tag-name",
        name: "new-tag-name"
    })
}).then(r => r.json());
```

***

## POST /api/v2/tag/merge <a href="#merge" id="merge"></a>

Merge a source tag into a target tag. All items with the source tag will have it replaced by the target tag. The source tag is removed after merging.

### Request Body

* `source` string (required) — The tag name to merge from (will be removed)
* `target` string (required) — The tag name to merge into (will be kept)

### Response

```json
{
    "status": "success",
    "data": {
        "affectedItems": 25,
        "sourceRemoved": true
    }
}
```

### Example

```javascript
// Merge "photograph" into "photography"
await fetch("http://localhost:41595/api/v2/tag/merge", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        source: "photograph",
        target: "photography"
    })
}).then(r => r.json());
```

***

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

Tags returned by the API contain the following properties:

| Property | Type      | Description                       |
| -------- | --------- | --------------------------------- |
| `name`   | string    | Tag name                          |
| `count`  | integer   | Number of items using this tag    |
| `color`  | string    | Tag color (empty string if unset) |
| `groups` | string\[] | Array of tag group IDs            |
| `pinyin` | string    | Pinyin representation of the name |
