# Virtual Tags API V2 (Beta)

The Virtual Tags API V2 allows you to create, retrieve, update, and delete [Virtual Tags](https://docs.finout.io/user-guide/inform/virtual-tags) programmatically.

{% hint style="info" %}
**Note**: Reallocation is currently unsupported in the Virtual Tags API V2.
{% endhint %}

***

### Prerequisites

Before calling this API, [generate a Finout API token](https://docs.finout.io/api/finout-api/generate-an-api-token) and include these headers in every request:

* `x-finout-client-id`
* `x-finout-secret-key`

***

### Rate Limits

| Method   | Endpoint                | Description                    | Rate Limit (per account, per route) |
| -------- | ----------------------- | ------------------------------ | ----------------------------------- |
| `GET`    | `/v2/virtual-tags`      | Retrieve all Virtual Tags      | 50 req / min                        |
| `GET`    | `/v2/virtual-tags/{id}` | Retrieve a Virtual Tag by ID   | 100 req / min                       |
| `POST`   | `/v2/virtual-tags`      | Create a new Virtual Tag       | 50 req / min                        |
| `PUT`    | `/v2/virtual-tags/{id}` | Update an existing Virtual Tag | 100 req / min                       |
| `DELETE` | `/v2/virtual-tags/{id}` | Delete a Virtual Tag           | 100 req / min                       |

***

### GET /Virtual Tags

Retrieves all Virtual Tag configurations for your account.

> **Prerequisites:** [Generate a Client ID and Secret Key](https://docs.finout.io/api/finout-api/generate-an-api-token) from Finout to add in Headers. You also need a Virtual Tag ID.

**Request**

`https://app.finout.io/v2/virtual-tags`

**Response**

```json
{
  "requestId": "6dded699-9878-4e56-a462-5cfc334dbd5d",
  "data": {
    "virtualTags": [
      {
        "id": "f84c9ab0-dab2-4cf1-b7aa-f4a767d9724b",
        "name": "Environment",
        "defaultValue": "Untagged",
        "rules": [
          {
            "to": {
              "key": "environment",
              "costCenter": "Azure",
              "type": "tag"
            },
            "filters": {
              "costCenter": "Azure",
              "key": "environment",
              "displayName": "environment",
              "operator": "exists",
              "type": "tag"
            }
          },
          {
            "to": "Prod",
            "filters": {
              "costCenter": "GCP",
              "key": "env",
              "displayName": "env",
              "operator": "exists",
              "type": "tag"
            }
          }
        ],
        "acl": {
          "read": { "type": "public", "users": [], "groups": [] },
          "write": { "type": "private", "users": ["alice@example.com"], "groups": [] }
        },
        "createdBy": "alice@example.com",
        "updatedBy": "alice@example.com",
        "createdAt": "Wed Apr 15 2026 20:22:35 GMT+0000 (Greenwich Mean Time)",
        "updatedAt": "Wed Apr 15 2026 20:22:35 GMT+0000 (Greenwich Mean Time)"
      },
      {
        "id": "7559c174-b3e5-4c7d-ab00-fe8207b7a5b0",
        "name": "AWS Service Group",
        "defaultValue": "Untagged",
        "rules": [
          {
            "to": "compute",
            "filters": {
              "costCenter": "AWS",
              "key": "parent_cloud_service",
              "displayName": "Services",
              "operator": "oneOf",
              "value": ["AmazonEC2", "AmazonEKS"],
              "type": "billing_dimension"
            }
          }
        ],
        "createdBy": "bob@example.com",
        "updatedBy": "bob@example.com",
        "createdAt": "Sun Mar 29 2026 12:49:34 GMT+0000 (Greenwich Mean Time)",
        "updatedAt": "Sun Mar 29 2026 12:49:34 GMT+0000 (Greenwich Mean Time)"
      }
    ]
  }
}
```

#### Response fields

| Field              | Type   | Description                                                                   |
| ------------------ | ------ | ----------------------------------------------------------------------------- |
| `requestId`        | string | Unique identifier for the request.                                            |
| `data.virtualTags` | array  | List of Virtual Tag objects. See [Virtual Tag objects](#virtual-tag-objects). |

***

### GET /Virtual Tag by ID

Retrieves the configuration of a specific Virtual Tag.

> **Prerequisites:** [Generate a Client ID and Secret Key](https://docs.finout.io/api/finout-api/generate-an-api-token) from Finout to add in Headers. You also need a Virtual Tag ID.

**Request**

`https://app.finout.io/v2/virtual-tags/{id}`

**Path parameter**

| Parameter | Type   | Description                            |
| --------- | ------ | -------------------------------------- |
| `id`      | string | The ID of the Virtual Tag to retrieve. |

**Response**

```json
{
  "requestId": "2cfe3847-49b3-491e-8fcb-9cb8c7a08d88",
  "data": {
    "id": "f84c9ab0-dab2-4cf1-b7aa-f4a767d9724b",
    "name": "Environment",
    "defaultValue": "Untagged",
    "rules": [
      {
        "to": {
          "key": "environment",
          "costCenter": "Azure",
          "type": "tag"
        },
        "filters": {
          "costCenter": "Azure",
          "key": "environment",
          "displayName": "environment",
          "operator": "exists",
          "type": "tag"
        }
      },
      {
        "to": "Prod",
        "filters": {
          "costCenter": "GCP",
          "key": "env",
          "displayName": "env",
          "operator": "exists",
          "type": "tag"
        }
      },
      {
        "to": {
          "key": "environment",
          "costCenter": "AWS",
          "type": "tag"
        },
        "filters": {
          "costCenter": "AWS",
          "key": "environment",
          "displayName": "environment",
          "operator": "exists",
          "type": "tag"
        }
      }
    ],
    "createdBy": "alice@example.com",
    "updatedBy": "alice@example.com",
    "createdAt": "Wed Apr 15 2026 20:22:35 GMT+0000 (Greenwich Mean Time)",
    "updatedAt": "Wed Apr 15 2026 20:22:35 GMT+0000 (Greenwich Mean Time)"
  }
}
```

***

### POST /Virtual Tag

Creates a new Virtual Tag.

> **Prerequisites:** [Generate a Client ID and Secret Key](https://docs.finout.io/api/finout-api/generate-an-api-token) from Finout to add in Headers.

**Request**

`https://app.finout.io/v2/virtual-tags`

**Request body — custom string value**

```json
{
  "name": "Environment",
  "defaultValue": "Untagged",
  "versionMetadata": {
    "changeDescription": "Initial setup: map AWS environment tag to production and staging"
  },
  "rules": [
    {
      "to": "production",
      "filters": {
        "costCenter": "AWS",
        "key": "environment",
        "displayName": "environment",
        "operator": "oneOf",
        "value": ["prod", "production"],
        "type": "tag"
      }
    },
    {
      "to": "staging",
      "filters": {
        "costCenter": "AWS",
        "key": "environment",
        "displayName": "environment",
        "operator": "oneOf",
        "value": ["staging", "stage"],
        "type": "tag"
      }
    }
  ]
}
```

**Request body — MegaBill key as destination**

```json
{
  "name": "Environment",
  "defaultValue": "Untagged",
  "versionMetadata": {
    "changeDescription": "Initial setup: passthrough environment tag from AWS, GCP, and Azure"
  },
  "rules": [
    {
      "to": {
        "key": "environment",
        "costCenter": "AWS",
        "type": "tag"
      },
      "filters": {
        "costCenter": "AWS",
        "key": "environment",
        "displayName": "environment",
        "operator": "exists",
        "type": "tag"
      }
    },
    {
      "to": {
        "key": "env",
        "costCenter": "GCP",
        "type": "tag"
      },
      "filters": {
        "costCenter": "GCP",
        "key": "env",
        "displayName": "env",
        "operator": "exists",
        "type": "tag"
      }
    },
    {
      "to": {
        "key": "environment",
        "costCenter": "Azure",
        "type": "tag"
      },
      "filters": {
        "costCenter": "Azure",
        "key": "environment",
        "displayName": "environment",
        "operator": "exists",
        "type": "tag"
      }
    }
  ]
}
```

**Body parameters**

| Parameter                           | Type             | Required | Description                                                                                                                                                               |
| ----------------------------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                              | string           | Yes      | The name of the Virtual Tag.                                                                                                                                              |
| `rules`                             | array            | Yes      | An array of rule objects defining the filters and conditions. See [Virtual Tag objects](https://claude.ai/chat/ab14c8f7-b67d-4184-9784-a3c92c0da758#virtual-tag-objects). |
| `defaultValue`                      | string or object | Yes      | Value assigned when no rules match. Use a string for a custom static value, or a `{ key, costCenter }` object for a MegaBill key.                                         |
| `versionMetadata`                   | object           | No       | Metadata about this version.                                                                                                                                              |
| `versionMetadata.changeDescription` | string           | No       | A human-readable description of what changed in this version, recorded in the version history.                                                                            |

**Response — custom string value**

```json
{
  "requestId": "d5fcd0f7-e10f-43f5-9668-480ee24e3816",
  "data": {
    "id": "a3b7c912-f4d8-4e1a-b2c3-7d8e9f012345",
    "name": "Environment",
    "defaultValue": "Untagged",
    "rules": [
      {
        "to": "production",
        "filters": {
          "costCenter": "AWS",
          "key": "environment",
          "displayName": "environment",
          "operator": "oneOf",
          "value": ["prod", "production"],
          "type": "tag"
        }
      },
      {
        "to": "staging",
        "filters": {
          "costCenter": "AWS",
          "key": "environment",
          "displayName": "environment",
          "operator": "oneOf",
          "value": ["staging", "stage"],
          "type": "tag"
        }
      }
    ],
    "acl": {
      "read": { "type": "public", "users": [], "groups": [] },
      "write": { "type": "private", "users": ["alice@example.com"], "groups": [] }
    },
    "createdBy": "alice@example.com",
    "updatedBy": "alice@example.com",
    "createdAt": "Wed Apr 30 2026 14:00:00 GMT+0000 (Greenwich Mean Time)",
    "updatedAt": "Wed Apr 30 2026 14:00:00 GMT+0000 (Greenwich Mean Time)"
  }
}
```

**Response — MegaBill key**

```json
{
  "requestId": "e5d094c6-bb3c-4da2-8209-6ec9a5f2dfaa",
  "data": {
    "id": "f84c9ab0-dab2-4cf1-b7aa-f4a767d9724b",
    "name": "Environment",
    "defaultValue": "Untagged",
    "rules": [
      {
        "to": {
          "key": "environment",
          "costCenter": "AWS",
          "type": "tag"
        },
        "filters": {
          "costCenter": "AWS",
          "key": "environment",
          "displayName": "environment",
          "operator": "exists",
          "type": "tag"
        }
      },
      {
        "to": {
          "key": "env",
          "costCenter": "GCP",
          "type": "tag"
        },
        "filters": {
          "costCenter": "GCP",
          "key": "env",
          "displayName": "env",
          "operator": "exists",
          "type": "tag"
        }
      },
      {
        "to": {
          "key": "environment",
          "costCenter": "Azure",
          "type": "tag"
        },
        "filters": {
          "costCenter": "Azure",
          "key": "environment",
          "displayName": "environment",
          "operator": "exists",
          "type": "tag"
        }
      }
    ],
    "createdBy": "alice@example.com",
    "updatedBy": "alice@example.com",
    "createdAt": "Wed Apr 30 2026 14:00:00 GMT+0000 (Greenwich Mean Time)",
    "updatedAt": "Wed Apr 30 2026 14:00:00 GMT+0000 (Greenwich Mean Time)"
  }
}
```

***

### PUT /Virtual Tag

Updates an existing Virtual Tag. The full configuration is replaced.

> **Prerequisites:** [Generate a Client ID and Secret Key](https://docs.finout.io/api/finout-api/generate-an-api-token) from Finout to add in Headers. You also need a Virtual Tag ID.

**Request**

`https://app.finout.io/v2/virtual-tags/{id}`

**Path parameter**

| Parameter | Type   | Description                          |
| --------- | ------ | ------------------------------------ |
| `id`      | string | The ID of the Virtual Tag to update. |

**Request body — custom string value**

```json
{
  "name": "Environment",
  "defaultValue": "Unknown",
  "versionMetadata": {
    "changeDescription": "Added development environment; updated default value to Unknown"
  },
  "rules": [
    {
      "to": "production",
      "filters": {
        "costCenter": "AWS",
        "key": "environment",
        "displayName": "environment",
        "operator": "oneOf",
        "value": ["prod", "production"],
        "type": "tag"
      }
    },
    {
      "to": "staging",
      "filters": {
        "costCenter": "AWS",
        "key": "environment",
        "displayName": "environment",
        "operator": "oneOf",
        "value": ["staging", "stage", "stg"],
        "type": "tag"
      }
    },
    {
      "to": "development",
      "filters": {
        "costCenter": "AWS",
        "key": "environment",
        "displayName": "environment",
        "operator": "oneOf",
        "value": ["dev", "development"],
        "type": "tag"
      }
    }
  ]
}
```

**Request body — MegaBill key as destination**

```json
{
  "name": "Environment",
  "defaultValue": "Untagged",
  "versionMetadata": {
    "changeDescription": "Removed Azure rule; now passthrough from AWS and GCP only"
  },
  "rules": [
    {
      "to": {
        "key": "environment",
        "costCenter": "AWS",
        "type": "tag"
      },
      "filters": {
        "costCenter": "AWS",
        "key": "environment",
        "displayName": "environment",
        "operator": "exists",
        "type": "tag"
      }
    },
    {
      "to": {
        "key": "env",
        "costCenter": "GCP",
        "type": "tag"
      },
      "filters": {
        "costCenter": "GCP",
        "key": "env",
        "displayName": "env",
        "operator": "exists",
        "type": "tag"
      }
    }
  ]
}
```

**Body parameters**

| Parameter                           | Type             | Required | Description                                                                                                                       |
| ----------------------------------- | ---------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `name`                              | string           | Yes      | The name of the Virtual Tag.                                                                                                      |
| `rules`                             | array            | Yes      | An array of rule objects defining the filters and conditions. See [Virtual Tag objects](#virtual-tag-objects).                    |
| `defaultValue`                      | string or object | Yes      | Value assigned when no rules match. Use a string for a custom static value, or a `{ key, costCenter }` object for a MegaBill key. |
| `versionMetadata`                   | object           | No       | Metadata about this version.                                                                                                      |
| `versionMetadata.changeDescription` | string           | No       | A human-readable description of the change, recorded in the version history.                                                      |

**Response — custom string value**

```json
{
  "requestId": "bd6a76b6-76d0-4e4c-a0b6-d3bad4e5ea87",
  "data": {
    "id": "a3b7c912-f4d8-4e1a-b2c3-7d8e9f012345",
    "name": "Environment",
    "defaultValue": "Unknown",
    "rules": [
      {
        "to": "production",
        "filters": {
          "costCenter": "AWS",
          "key": "environment",
          "displayName": "environment",
          "operator": "oneOf",
          "value": ["prod", "production"],
          "type": "tag"
        }
      },
      {
        "to": "staging",
        "filters": {
          "costCenter": "AWS",
          "key": "environment",
          "displayName": "environment",
          "operator": "oneOf",
          "value": ["staging", "stage", "stg"],
          "type": "tag"
        }
      },
      {
        "to": "development",
        "filters": {
          "costCenter": "AWS",
          "key": "environment",
          "displayName": "environment",
          "operator": "oneOf",
          "value": ["dev", "development"],
          "type": "tag"
        }
      }
    ],
    "acl": {
      "read": { "type": "public", "users": [], "groups": [] },
      "write": { "type": "private", "users": ["alice@example.com"], "groups": [] }
    },
    "createdBy": "alice@example.com",
    "updatedBy": "alice@example.com",
    "createdAt": "Wed Apr 30 2026 14:00:00 GMT+0000 (Greenwich Mean Time)",
    "updatedAt": "Wed Apr 30 2026 15:30:00 GMT+0000 (Greenwich Mean Time)"
  }
}
```

**Response — MegaBill key**

```json
{
  "requestId": "e5d094c6-bb3c-4da2-8209-6ec9a5f2dfaa",
  "data": {
    "id": "f84c9ab0-dab2-4cf1-b7aa-f4a767d9724b",
    "name": "Environment",
    "defaultValue": "Untagged",
    "rules": [
      {
        "to": {
          "key": "environment",
          "costCenter": "AWS",
          "type": "tag"
        },
        "filters": {
          "costCenter": "AWS",
          "key": "environment",
          "displayName": "environment",
          "operator": "exists",
          "type": "tag"
        }
      },
      {
        "to": {
          "key": "env",
          "costCenter": "GCP",
          "type": "tag"
        },
        "filters": {
          "costCenter": "GCP",
          "key": "env",
          "displayName": "env",
          "operator": "exists",
          "type": "tag"
        }
      }
    ],
    "createdBy": "alice@example.com",
    "updatedBy": "alice@example.com",
    "createdAt": "Wed Apr 30 2026 14:00:00 GMT+0000 (Greenwich Mean Time)",
    "updatedAt": "Wed Apr 30 2026 15:30:00 GMT+0000 (Greenwich Mean Time)"
  }
}
```

***

### DELETE /Virtual Tag

Deletes a Virtual Tag.

> **Prerequisites:** [Generate a Client ID and Secret Key](https://docs.finout.io/api/finout-api/generate-an-api-token) from Finout to add in Headers. You also need a Virtual Tag ID.

**Request**

`https://app.finout.io/v2/virtual-tags/{id}`

**Path parameter**

| Parameter | Type   | Description                          |
| --------- | ------ | ------------------------------------ |
| `id`      | string | The ID of the Virtual Tag to delete. |

**Response**

```json
{
  "requestId": "43aaf058-8ca1-442f-908b-5f6760565334",
  "data": {
    "id": "a3b7c912-f4d8-4e1a-b2c3-7d8e9f012345",
    "name": "Environment"
  }
}
```

> **Warning:** Deleting a Virtual Tag also removes all its version history. This action cannot be undone.

***

### Virtual Tag objects

The Virtual Tag object represents a configuration used for resource allocation and filtering.

| Field          | Type              | Description                                                                                                | Example value                                                        |
| -------------- | ----------------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `id`           | string            | The unique identifier of the Virtual Tag.                                                                  | `"2e29ad96-3616-43d7-9858-a00477457e6a"`                             |
| `name`         | string            | The name of the Virtual Tag.                                                                               | `"Team Allocation"`                                                  |
| `rules`        | array             | An array of rule objects. See [Rules object definition](#rules-object-definition).                         | —                                                                    |
| `defaultValue` | string or object  | Value assigned when no rules match. Can be a static string or a `{ key, costCenter }` MegaBill key object. | `"Untagged"` or `{ "key": "eks_cluster_name", "costCenter": "AWS" }` |
| `createdBy`    | string            | Email of the user who created the Virtual Tag.                                                             | `"sam.smith@finout.io"`                                              |
| `updatedBy`    | string            | Email of the user who last updated the Virtual Tag.                                                        | `"sam.smith@finout.io"`                                              |
| `createdAt`    | string (ISO-8601) | Timestamp when the Virtual Tag was created.                                                                | `"2024-09-09T21:47:55.000Z"`                                         |
| `updatedAt`    | string (ISO-8601) | Timestamp when the Virtual Tag was last updated.                                                           | `"2024-11-13T17:55:07.000Z"`                                         |

#### Rules object definition

| Field       | Type             | Description                                                                                                                                                                         | Example value                                                         |
| ----------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `to`        | string or object | The tag value to assign when the rule matches. Use a string for a static value, or a `{ key, costCenter }` object for a MegaBill key.                                               | `"Backend"` or `{ "key": "k8s_cluster", "costCenter": "Kubernetes" }` |
| `filters`   | object           | The filter conditions for this rule. See [Filter object definition V2](/api/finout-api/finout-api-v2/filter-object-definition-v2.md).                                               | —                                                                     |
| `timeframe` | object           | Optional. Applies the rule only within a defined date range. Uses unix timestamps in milliseconds: `{ "from": <timestamp>, "to": <timestamp> }`. Omit `to` for an open-ended range. | `{ "from": 1756166400000, "to": 1756166400100 }`                      |

***

### Error handling

| Code                      | Meaning                                                        | What to do                                                                                    |
| ------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| 400 Bad Request           | Malformed request or missing required parameters.              | Check the request body structure and resubmit.                                                |
| 401 Unauthorized          | Missing or invalid credentials.                                | Verify your `x-finout-client-id` and `x-finout-secret-key` headers.                           |
| 403 Forbidden             | Valid credentials but insufficient permissions.                | Check the Virtual Tag's write ACL or contact Finout support.                                  |
| 404 Not Found             | The requested Virtual Tag ID does not exist.                   | Confirm the ID with `GET /v2/virtual-tags`.                                                   |
| 422 Unprocessable Request | Request structure is valid JSON but fails business validation. | Review the Virtual Tag rule and filter composition.                                           |
| 429 Too Many Requests     | Rate limit exceeded.                                           | Reduce request frequency and retry after the window resets.                                   |
| 500 Internal Server Error | Unexpected server-side error.                                  | Retry the request. If the issue persists, contact [Finout Support](mailto:support@finout.io). |

***

### FAQs

**What happens if I exceed the rate limits?**\
The API returns a `429 Too Many Requests` response. Use the following response headers to monitor your rate limit consumption:

* `ratelimit`
* `x-account-ratelimit-*`
* `x-endpoint-ratelimit-*`

***

**In what order are rules evaluated?**

Rules are evaluated top to bottom. Order your rules from most specific to most general, and place your catch-all rules last.

***

**How many rules can a Virtual Tag have?**

50 rules per Virtual Tag. If you need more granular allocation, consider splitting your logic across multiple Virtual Tags or using nested `AND`/`OR` filter conditions within a single rule.

***

**Does a PUT request create a new version in the version history?**

Yes. Every successful POST and PUT automatically creates a new version. You can annotate it by passing `versionMetadata.changeDescription` in the request body (max 280 characters). Each Virtual Tag retains up to 100 versions for one year — when a 101st version is created, the oldest non-live version is deleted automatically.

***

**Do I need to include `displayName` in filter objects when creating or updating a Virtual Tag?**

No. `displayName` is a read-only convenience field that Finout returns in GET responses for human readability. You do not need to include it in POST or PUT request bodies.

***

**What is the difference between the `is` and `oneOf` operators?**

`is` matches a single exact string value — pass a string in `value`. `oneOf` matches if the field equals any item in an array — pass an array in `value`. Use `oneOf` whenever you need to match more than one value; `is` for a single exact match only.

***

**Can I create Virtual Tags with reallocation via the API?**

No. Reallocation rules are not supported in the Virtual Tags API.

***

**What ACL permissions does a Virtual Tag get when created via the API?**

Read access is always public — all users in your account can view and use the Virtual Tag for filtering and grouping. Write access defaults to your account-level ACL setting.&#x20;

***

**What happens to dashboards and views that reference a deleted Virtual Tag?**

They lose that Virtual Tag dimension permanently. Finout does not cascade-update any saved views, dashboard widgets, or reports that referenced the deleted tag. Verify all downstream dependencies before sending a DELETE request.

***

**What is `changeDescription` and how do I set it?**

`changeDescription` is an optional human-readable note describing what changed in that version. Include a `changeDescription` string in the body of a Virtual Tag V2 POST or PUT request.


---

# 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://docs.finout.io/api/finout-api/finout-api-v2/virtual-tags-api-v2-beta.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.
