# Virtual Tag Versions API V2 (Beta)

The Virtual Tag Versions API lets you retrieve the full version history of a Virtual Tag and inspect historical configuration snapshot — including its tagging rules, default value, and change description.

Use this API to audit changes over time and compare configurations across versions.

{% hint style="info" %}
**Note**: Each time a Virtual Tag is saved in Finout, a new version is automatically created. Only one version is live at any time and can be used by users when filtering or grouping by virtual tags in Finout.
{% endhint %}

***

### Prerequisites

Before calling either endpoint, make sure you have:

1. A Finout API token. [Generate a Finout API token](https://docs.finout.io/api/finout-api/generate-an-api-token) and add these headers to every request:
   * `x-finout-client-id`
   * `x-finout-secret-key`
2. The ID of the Virtual Tag whose versions you want to retrieve. Use the [Virtual Tags API V2](https://docs.finout.io/api/finout-api/virtual-tags-api-v1) to get a Virtual Tag ID.

***

### How it works

Every Virtual Tag can have multiple versions. Each version contains:

* **Metadata** — who created it and when
* **Change description** — an optional note describing what changed
* **Configuration snapshot** — the complete tagging rules and default value at the time of save

There are two endpoints:

* **List all versions** for a Virtual Tag, paginated and sortable
* **Fetch a single version by ID** to inspect its full configuration

***

### Rate Limits

| Route                                         | Rate Limit (per account, per route) |
| --------------------------------------------- | ----------------------------------- |
| `GET /v2/virtual-tags/{id}/versions`          | 50 req / min                        |
| `GET /v2/virtual-tags/{vtagId}/versions/{id}` | 100 req / min                       |

***

### GET /Virtual Tag Versions&#x20;

Returns a paginated list of all versions for a given Virtual Tag, sorted by creation date.

**Request**

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

#### Path Parameters

| Parameter | Type   | Required | Description                |
| --------- | ------ | -------- | -------------------------- |
| `id`      | string | Yes      | The Virtual Tag identifier |

#### Query Parameters

| Parameter       | Type                                     | Required | Description                                                  |
| --------------- | ---------------------------------------- | -------- | ------------------------------------------------------------ |
| `from`          | integer (unix timestamp in milliseconds) | No       | Return versions with `createdAt` on or after this timestamp  |
| `to`            | integer (unix timestamp in milliseconds) | No       | Return versions with `createdAt` on or before this timestamp |
| `pageSize`      | integer                                  | No       | Results per page. Default: `50`. Max: `100`                  |
| `cursor`        | string                                   | No       | Cursor for fetching the next page                            |
| `sortDirection` | string                                   | No       | `asc` or `desc`. Default: `desc`                             |

> **Important — pagination:** If your initial request includes `from`, `to`, `pageSize`, or `sortDirection`, you must repeat those same parameters alongside `cursor` on every subsequent request. The cursor encodes position only — omitting these parameters on a cursor request will return inconsistent results.

#### Response

```json
{
  "requestId": "828a4454-5a41-4473-9fea-15ce7b3557f4",
  "pagination": {
    "nextCursor": null,
    "hasMore": false
  },
  "data": [
    {
      "id": "eb14e00a-97a8-4af3-84c5-f3dd07d847d8",
      "createdBy": "sam.smith@finout.io",
      "createdAt": "2026-03-31T18:23:48.701Z",
      "isLive": true
    },
    {
      "id": "194f60db-7d2b-4599-b1c2-0fb58160a2d7",
      "createdBy": "sam.smith@finout.io",
      "createdAt": "2026-03-24T18:07:47.475Z",
      "isLive": false
    },
    {
      "id": "36aea575-cb7f-445f-963e-9e68c4a3a46b",
      "createdBy": "sam.smith@finout.io",
      "createdAt": "2026-03-24T16:59:49.766Z",
      "isLive": false,
      "changeDescription": "Duplicate from virtual tag \"AG/Team\""
    }
  ]
}
```

#### Response Fields

| Field               | Type              | Description                                    |
| ------------------- | ----------------- | ---------------------------------------------- |
| `id`                | string            | Version identifier                             |
| `createdAt`         | string (ISO-8601) | Timestamp when this version was created        |
| `createdBy`         | string (email)    | User who saved this version                    |
| `changeDescription` | string            | Optional description of what changed           |
| `isLive`            | boolean           | `true` if this is the currently active version |

#### Pagination Fields

| Field        | Type    | Description                                        |
| ------------ | ------- | -------------------------------------------------- |
| `hasMore`    | boolean | Whether additional pages are available             |
| `nextCursor` | string  | Pass this value as `cursor` to fetch the next page |

***

### GET /Virtual Tag Version by ID

Returns a single version, including its full configuration snapshot (rules and default value).

{% hint style="info" %} **Note**: To fetch a specific version, you must first call [GET /Virtual Tag Versions](https://claude.ai/chat/ab14c8f7-b67d-4184-9784-a3c92c0da758#get-virtual-tag-versions) to obtain a `versionId`. {% endhint %}

**Request**

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

#### Path Parameters

| Parameter | Type   | Required | Description                |
| --------- | ------ | -------- | -------------------------- |
| `vtagId`  | string | Yes      | The Virtual Tag identifier |
| `id`      | string | Yes      | The Version identifier     |

#### Response

```json
{
  "requestId": "c85f0423-7048-432b-a144-73f76c2e0512",
  "data": {
    "id": "aba7efe5-de85-4f4b-bd89-0861d140c018",
    "createdBy": "sam.smith@finout.io",
    "createdAt": "2026-03-25T13:19:06.200Z",
    "isLive": false,
    "changeDescription": "doc demo 1",
    "versionData": {
      "rules": [
        {
          "to": {
            "key": "4f816fc1-6b3a-4902-b6b5-9759ba5ca83c",
            "costCenter": "Virtual Tags",
            "type": "virtual_tag"
          },
          "filters": {
            "costCenter": "AWS",
            "key": "operation",
            "displayName": "API Operation",
            "operator": "oneOf",
            "value": ["AAAA"],
            "type": "billing_enrichment"
          }
        }
      ],
      "defaultValue": "Untagged"
    }
  }
}
```

#### Response Fields

| Field               | Type              | Description                                    |
| ------------------- | ----------------- | ---------------------------------------------- |
| `id`                | string            | Version identifier                             |
| `createdAt`         | string (ISO-8601) | Timestamp when this version was created        |
| `createdBy`         | string (email)    | User who saved this version                    |
| `changeDescription` | string            | Optional description of what changed           |
| `isLive`            | boolean           | `true` if this is the currently active version |
| `versionData`       | object            | Full configuration snapshot for this version   |

#### Version Data Fields

| Field          | Type   | Description                                    |
| -------------- | ------ | ---------------------------------------------- |
| `rules`        | array  | The list of matching rules at the time of save |
| `defaultValue` | string | The value assigned when no rules match         |

For the full definition of the `rules` object structure, see [Virtual Tags API V2 — Virtual Tags Objects](https://docs.finout.io/api/finout-api/virtual-tags-api-v1#virtual-tags-objects).

***

### Error Reference

| Error Code               | Description                                           | When it occurs                  |
| ------------------------ | ----------------------------------------------------- | ------------------------------- |
| `UNAUTHORIZED`           | Authentication credentials are missing or invalid     | Missing or invalid auth headers |
| `FORBIDDEN`              | You do not have permission to access this Virtual Tag | Access denied by ACL            |
| `VTAG_NOT_FOUND`         | The specified Virtual Tag was not found               | Invalid `id`                    |
| `VTAG_VERSION_NOT_FOUND` | The specified version was not found                   | Invalid `versionId`             |

***

### FAQs

**Does every Virtual Tag save create a new version?**

Yes. Every time a Virtual Tag is saved via the API a new version is automatically created.&#x20;

***

**How many versions are retained per Virtual Tag?**

Up to 100 versions are retained per Virtual Tag, for up to 1 year. Versions beyond these limits are removed automatically as long as they are not the live version, starting from the oldest.

***

**Is the Versions API V2 read-only?**

Yes. The Versions API only supports GET operations. You can list versions and retrieve version snapshots, but you cannot create, delete, or promote versions directly via this API.

To restore a previous configuration and resubmit it as a PUT request to [Virtual Tags API V2](https://docs.finout.io/api/finout-api/virtual-tags-api-v2#put-virtual-tag). See [How do I restore a previous version?](#how-do-i-restore-a-previous-version).

***

**How do I get a versionId?**

Call `GET /v2/virtual-tags/{id}/versions` first. This returns a paginated list of all versions for the Virtual Tag, each with an `id`, `createdAt`, `createdBy`, `isLive`, and optional `changeDescription`. Use the `id` from this list as the `versionId` in `GET /v2/virtual-tags/{vtagId}/versions/{id}`.

***

**What does `isLive` mean?**

`isLive: true` marks the version that is currently active — the configuration Finout is using for cost allocation right now when selecting this virtual tag in filter or group by. Only one version per Virtual Tag has `isLive: true` at any time. All other versions are historical snapshots.

***

**How does pagination work?**

The list endpoint returns up to `pageSize` results per page (default: 50, max: 100). When more pages exist, the response includes `pagination.hasMore: true` and a `pagination.nextCursor` value. Pass that value as the `cursor` query parameter in your next request. Continue until `hasMore: false`.

```
GET /v2/virtual-tags/{id}/versions?cursor=<nextCursor>
```

***

#### How do I restore a previous version?

The Versions API is read-only, so there is no direct rollback endpoint. To restore a previous version:

1. Call `GET /v2/virtual-tags/{id}/versions` to find the version you want.
2. Call `GET /v2/virtual-tags/{id}/versions/{versionId}` to retrieve its full configuration snapshot.
3. Extract `versionData.rules` and `versionData.defaultValue` from the response.
4. Submit a `PUT /v2/virtual-tags/{id}` request to [Virtual Tags API V2](https://docs.finout.io/api/finout-api/virtual-tags-api-v2#put-virtual-tag) with those values as the request body.

This creates a new version with the restored configuration, which then becomes the live version.

***

**Does restoring a version delete the version history?**

No. Submitting a PUT with a previous version's configuration creates a new version — it does not overwrite or remove any existing version history. All prior versions remain accessible via the Versions API.

***

**Can I restore a version if the Virtual Tag has been deleted?**

No. Deleting a Virtual Tag also removes all its associated version history.&#x20;

***

**What are the rate limits for the Versions endpoints?**

Rate limits are per account, per endpoint, measured in requests per minute. They are not shared with other Virtual Tags API endpoints.

| Endpoint                                      | Rate limit    |
| --------------------------------------------- | ------------- |
| `GET /v2/virtual-tags/{id}/versions`          | 100 req / min |
| `GET /v2/virtual-tags/{vtagId}/versions/{id}` | 300 req / min |

***

**What happens if I exceed the rate limit?**

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-*`

***

####


---

# 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-tag-versions-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.
