> ## Documentation Index
> Fetch the complete documentation index at: https://developers.fireblocks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tags

> Create, attach, and manage tags through the Fireblocks API, including protected tags, the quorum approval flow, and filtering vault accounts by tag.

## Overview

New to tags? See the [Tags Overview](https://support.fireblocks.io/hc/en-us/articles/24809719517596) in the Help Center for a product introduction and a Console walkthrough, before following this API guide.

Tags are custom labels you attach to vault accounts to classify, filter, and govern your vault inventory at scale. Two fields determine how a tag behaves, `isProtected` and `type`:

* **Standard tags** (`isProtected: false`) are for organization and filtering. Every operation applies immediately.
* **Protected tags** (`isProtected: true`) can be referenced in Policy rules. Editing, deleting, attaching, and detaching them all require quorum approval before they take effect.
* **Wallet Pool tags** (`isProtected: true`, `type: WALLET_POOL`) are protected tags that also act as a single transaction source, routing across their member vault accounts by health. See [Wallet Pools](/docs/wallet-pools).

This guide covers the full API flow: create a tag, attach it to vault accounts, filter your vault inventory by tag, and manage the tag lifecycle. It also covers the approval flow that protected tags introduce, and how to tag vault accounts at creation time.

## Requirements

Tag operations are role-gated, and protected tags are gated more tightly than standard tags.

| Operation                      | Standard tags                                             | Protected tags                          |
| ------------------------------ | --------------------------------------------------------- | --------------------------------------- |
| Create                         | Owner, Admin, Non-Signing Admin, Signer, Editor, Approver | Owner, Admin, Non-Signing Admin, Editor |
| Update, delete, attach, detach | Owner, Admin, Non-Signing Admin, Signer, Editor, Approver | Owner, Admin, Non-Signing Admin, Editor |
| Approve a pending operation    | Not applicable                                            | Owner, Admin, Non-Signing Admin         |

Initiating a protected tag operation and approving one are separate permissions. Editor can initiate any protected tag operation, but cannot approve it; the approval must come from an Owner, Admin, or Non-Signing Admin.

Approvals are granted in the Fireblocks mobile app or through the API Co-signer, not through this API. Quorum requirements are configured in the Fireblocks Console under **Settings** > **Quorums** > **Approval Groups**, which provides two separate groups for protected tags: one covering edit and delete, and one covering attach and detach. See [Protected Tags](https://support.fireblocks.io/hc/en-us/articles/27718237234972) for how to configure them.

## API flow

The integration follows this order: create the tag, attach it to vault accounts, then read or filter by it.

```mermaid theme={"system"}
flowchart LR
  A[Create a tag] --> B[Attach to vault accounts]
  B --> C[Filter vault accounts]
  B --> D[Reference in Policy rules]
```

### Step 1: Create a tag

See [Create a new tag](/api-reference/tags/create-a-new-tag).

`POST /v1/tags`

**Request body**

```json theme={"system"}
{
  "label": "Treasury",
  "description": "Vaults holding long-term reserves",
  "color": "#FF5733",
  "isProtected": true
}
```

**Response**

```json theme={"system"}
{
  "id": "9b1c...",
  "label": "Treasury",
  "description": "Vaults holding long-term reserves",
  "color": "#FF5733",
  "isProtected": true,
  "updatedAt": 1754827143000
}
```

**Field notes:**

* `label`: required. 2 to 30 characters, alphanumeric plus spaces, hyphens, and underscores, and unique within your workspace. A duplicate label returns `409 Conflict`; a malformed one returns `400 Bad Request`.
* `isProtected`: **immutable after creation.** You cannot convert a standard tag into a protected tag or the reverse. If you need a protected version of an existing tag, create a second tag and re-attach.
* `type`: set to `WALLET_POOL`, together with `isProtected: true`, to create a [Wallet Pool](/docs/wallet-pools): a tag that also acts as a single transaction source with health-aware routing across its member vaults. Omit it for an ordinary tag.
* `description`: optional, up to 250 characters of plain text. `color`: optional, a valid hex value.

Creating a tag always takes effect immediately, including a protected tag. Approval applies only to the operations that follow.

All write endpoints in this guide accept an `Idempotency-Key` header, valid for 24 hours.

### Step 2: Attach tags to vault accounts

A single call attaches and detaches across many vault accounts at once. See [Attach or detach tags from vault accounts](/api-reference/vaults/attach-or-detach-tags-from-vault-accounts).

`POST /v1/vault/accounts/attached_tags`

**Request body**

```json theme={"system"}
{
  "vaultAccountIds": ["12", "13", "14"],
  "tagIdsToAttach": ["9b1c...", "4d2f..."],
  "tagIdsToDetach": ["7a3e..."]
}
```

The request is evaluated as a cartesian product: every tag in `tagIdsToAttach` is applied to every account in `vaultAccountIds`. Each resulting `(vaultAccountId, tagId, action)` triple is resolved independently and returned in one of three buckets.

**Response**

```json theme={"system"}
{
  "appliedOperations": [
    { "vaultAccountId": "12", "tagId": "4d2f...", "action": "ATTACH" }
  ],
  "pendingOperations": [
    { "vaultAccountId": "12", "tagId": "9b1c...", "action": "ATTACH",
      "approvalRequestId": "e81a..." }
  ],
  "rejectedOperations": [
    { "vaultAccountId": "13", "tagId": "9b1c...", "action": "ATTACH",
      "reason": "CAPACITY_EXCEEDED" }
  ]
}
```

| Bucket               | Meaning                                                                                         |
| -------------------- | ----------------------------------------------------------------------------------------------- |
| `appliedOperations`  | Applied immediately. Standard tags land here.                                                   |
| `pendingOperations`  | Staged awaiting quorum approval, with an `approvalRequestId` to poll. Protected tags land here. |
| `rejectedOperations` | Not applied and not staged, with a machine-readable `reason`.                                   |

<Warning>
  A `200 OK` does not mean every operation succeeded. Partial failure is reported inside `rejectedOperations`, not through the status code. Always inspect all three buckets rather than branching on the HTTP status alone.
</Warning>

Rejection reasons:

| Reason                      | Cause                                                   |
| --------------------------- | ------------------------------------------------------- |
| `CAPACITY_EXCEEDED`         | The vault account already holds the maximum of 20 tags. |
| `ATTACHMENT_ALREADY_EXISTS` | The tag is already attached to that vault account.      |
| `ATTACHMENT_DOES_NOT_EXIST` | A detach was requested for a tag that is not attached.  |
| `PENDING_REQUEST_EXISTS`    | An unresolved approval request already covers that tag. |

You can mix standard and protected tags in one request. The standard tag operations are applied immediately while the protected ones are staged, and the response separates them for you. The same tag ID must not appear in both `tagIdsToAttach` and `tagIdsToDetach`.

### Step 3: Filter vault accounts by tag

See [Get vault accounts (paginated)](/api-reference/vaults/get-vault-accounts-paginated).

`GET /v1/vault/accounts_paged?includeTagIds=9b1c...&excludeTagIds=7a3e...`

**Query parameters**

| Parameter       | Description                                                                 |
| --------------- | --------------------------------------------------------------------------- |
| `includeTagIds` | Return vault accounts carrying **any** of these tags. Up to 50 tag IDs.     |
| `excludeTagIds` | Filter out vault accounts carrying **any** of these tags. Up to 50 tag IDs. |
| `tagIds`        | **Deprecated.** Use `includeTagIds` instead.                                |

Both filters use OR semantics within the list, so `includeTagIds=A&includeTagIds=B` returns accounts tagged A, B, or both. Combine the two to express "in this group but not that one", for example every `Treasury` vault that is not also `Sanctioned`.

Each `VaultAccount` in the response carries a `tags` array with the full tag objects, so a filtered list is also a read of current attachments. [Get a vault account by ID](/api-reference/vaults/get-a-vault-account-by-id) returns the same `tags` array for a single account.

<Note>
  Tag filtering is available on vault accounts only. `GET /v1/vault/asset_wallets` accepts no tag parameters and does not return tags, so filter at the account level and resolve wallets from there.
</Note>

### Step 4: List, update, and delete tags

**List tags.** See [Get list of tags](/api-reference/tags/get-list-of-tags).

`GET /v1/tags`

| Parameter                     | Description                                                                 |
| ----------------------------- | --------------------------------------------------------------------------- |
| `pageCursor`, `pageSize`      | Cursor pagination. The response returns `next`, or `null` on the last page. |
| `label`                       | Match tags whose label starts with this prefix.                             |
| `tagIds`                      | Restrict the result to specific tag IDs, up to 100.                         |
| `isProtected`                 | Return only protected or only standard tags.                                |
| `type`                        | Filter by tag type, for example `WALLET_POOL`.                              |
| `includePendingApprovalsInfo` | Populate `pendingApprovalRequest` on each tag.                              |

To read one tag directly, use [Get a tag](/api-reference/tags/get-a-tag) at `GET /v1/tags/{tagId}`.

**Update a tag.** See [Update a tag](/api-reference/tags/update-a-tag).

`PATCH /v1/tags/{tagId}`

Only `label`, `description`, and `color` are mutable. `isProtected` and `type` are fixed at creation. Updating a protected tag requires approval, and a tag with an unresolved approval request cannot be updated again until that request settles.

**Delete a tag.** See [Delete a tag](/api-reference/tags/delete-a-tag).

`DELETE /v1/tags/{tagId}`

Detach the tag from every vault account first. A tag with active attachments cannot be deleted. Deleting a protected tag requires approval.

## Protected tags and the approval flow

Protected tag operations are two-phase. The API call stages the change and returns an `approvalRequestId`; the change applies only once the quorum approves it in the Mobile app or Co-signer.

Poll the request to follow it. See [Get an approval request by id](/api-reference/tags/get-an-approval-request-by-id).

`GET /v1/tags/approval_requests/{id}`

**Response**

```json theme={"system"}
{
  "id": "e81a...",
  "type": "TAG_ATTACH_DETACH",
  "state": "PENDING"
}
```

`type` is one of `TAG_UPDATE`, `TAG_DELETE`, or `TAG_ATTACH_DETACH`. `state` is one of:

| State       | Meaning                                                    |
| ----------- | ---------------------------------------------------------- |
| `PENDING`   | Awaiting quorum approval. The change has not been applied. |
| `APPROVED`  | Approved and applied.                                      |
| `REJECTED`  | Declined by an approver. No change was made.               |
| `CANCELLED` | Withdrawn before resolution. No change was made.           |
| `EXPIRED`   | Timed out before reaching quorum. Submit a new request.    |
| `FAILED`    | Approved but could not be applied.                         |

While a request is `PENDING`, further operations on the same tag are rejected with `PENDING_REQUEST_EXISTS`. Treat any non-`PENDING` state as terminal and re-read the tag or the vault account to confirm the resulting state.

<Note>
  This is the only approval endpoint exposed by the API. Listing pending requests, approving, rejecting, and cancelling are available in the Fireblocks Console and Mobile app only. To reverse an operation that has already been applied, submit the inverse operation, which itself requires approval.
</Note>

## Tag vault accounts at creation

`POST /v1/vault/accounts` does not accept tags. To create vault accounts that are tagged from the start, use the bulk endpoint with a `tagIds` array, which applies the same tags to every account it creates. See [Bulk creation of new vault accounts](/api-reference/vaults/bulk-creation-of-new-vault-accounts).

`POST /v1/vault/accounts/bulk`

**Request body**

```json theme={"system"}
{
  "count": 500,
  "baseAssetIds": ["ETH", "BTC"],
  "prefix": "deposit-",
  "tagIds": ["9b1c..."]
}
```

**Response**

```json theme={"system"}
{
  "jobId": "3f7d...",
  "approvalRequestId": "e81a..."
}
```

`approvalRequestId` is returned only when `tagIds` contains at least one protected tag; the accounts are still created, and the tag attachments apply once approved. Poll [Get job status of bulk creation of new vault accounts](/api-reference/vaults/get-job-status-of-bulk-creation-of-new-vault-accounts) at `GET /v1/vault/accounts/bulk/{jobId}`, which echoes `tagIds` and `approvalRequestId` alongside `status` and the created `vaultAccounts`.

To create a single tagged vault account in one call, send this endpoint with `count: 1`.

<Note>
  Bulk creation is in beta and is capped at 10,000 accounts per operation. HBAR, TON, SUI, TERRA, ALGO, and DOT are not supported.
</Note>

## Limits

| Limit                                            | Value                               |
| ------------------------------------------------ | ----------------------------------- |
| Tags per vault account                           | 20, standard and protected combined |
| Vault accounts per attach or detach request      | 100                                 |
| Tags to attach per request                       | 20                                  |
| Tags to detach per request                       | 20                                  |
| Tag IDs per `GET /v1/tags` list request          | 100                                 |
| Tag IDs per filter parameter on `accounts_paged` | 50                                  |

Exceeding a per-request limit returns `400 Bad Request`. Exceeding the per-vault-account tag ceiling is reported per operation as `CAPACITY_EXCEEDED` in `rejectedOperations`. For label rules and field constraints, see [Tag Limits and Label Rules](https://support.fireblocks.io/hc/en-us/articles/27718268311964).

## Troubleshooting

| Symptom                                                       | Cause and fix                                                                                                                     |
| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `409 Conflict` when creating a tag                            | The label already exists in the workspace. Labels are unique per workspace.                                                       |
| `400 Bad Request` when creating a tag                         | The label is outside 2 to 30 characters, uses disallowed characters, or `color` is not a valid hex value.                         |
| Attach returned `200` but the tag is not on the vault account | The operation is in `pendingOperations` awaiting approval, or in `rejectedOperations`. Inspect both.                              |
| `PENDING_REQUEST_EXISTS`                                      | An earlier protected tag request has not settled. Poll it to a terminal state first.                                              |
| Delete fails                                                  | The tag still has vault account attachments. Detach it everywhere, then delete.                                                   |
| Filtering by tag returns nothing                              | Confirm you are using `includeTagIds` rather than the deprecated `tagIds`, and that attachments are approved rather than pending. |

## Related

* [Wallet Pools](/docs/wallet-pools): the `WALLET_POOL` tag type, which adds transaction routing on top of protected tag governance.
* [Create vault accounts](/reference/create-vault-account): create the accounts you attach tags to.
* [Set Policies](/docs/set-transaction-authorization-policy): reference protected tags as sources and destinations in Policy rules.
* [Protected Tags](https://support.fireblocks.io/hc/en-us/articles/27718237234972): quorum configuration and Policy patterns.
