> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://next.developer.frame.io/platform/v2/manage-version-stacks/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server. # Manage Version Stacks ## Overview Version Stacks are an organizational principle in Frame.io that enable Assets to be vertically "stacked" without being put into folders. Stacked versions make for easier Asset-to-Asset navigation within the Frame.io UI, and support side-by-side review. We do not currently support uploading directly into a Stack, so the API sequence for managing basic Version Stack workflow will follow the same sequence as the Frame.io UI: 1. Upload the Asset (optionally: mark as private). 2. Assign the Asset into Stack. Existing Version Stacks can be reordered, and individual versions can be knocked out a stack. Finally, Version Stacks can be deleted without deleting any of their constituent assets. Version Stacks will always have an attribute called `cover_asset_id` at their top level. This is the `id` of the Asset whose thumbnail is displayed in the Frame.io web UI, and is the highest-numbered version in the stack. ### Core concepts **Version Stacks** -- like **Folders** -- are special `types` of Assets. You can fetch them with the same endpoints, and based on the value of the `type` key in the API response, parse and route accordingly. This is generally straightforward in practice, but can present a couple of wrinkles when managing Stacks at scale. The key to working with Version Stacks is separating the **four most common scenarios**: 1. An Asset can be added to an Asset, which will create a Stack with a new `id`. 2. An Asset can be added to an existing Stack. 3. A Stack can be reordered. 4. Individual Versions can be removed. **The first two scenarios** use the same [endpoint call](ref:post_assets-assetid-version), so the only real nuance is knowing whether you're creating a new Stack (from two Assets), or adding your Asset to an existing Stack. Aside from that, the constraints are predictable: 1. Stacks must match on `asset_type` (e.g. you can't stack an *image* on a *stream*). 2. The acting User must have permissions for both the source Asset and destination Asset or Stack. 3. Asset Stack sequentially. 4. You can't stack a Stack on a Stack. 5. Folders are right out. **The latter two scenarios** are also pretty simple, but require knowing a bit more about the Stack itself. For example, to reorder an Asset in a Stack, you'll need to know the `id`s of the Assets on either side of where you want your target Asset to land; and that will generally mean you've fetched the entire Stack already. ### Required scopes Before beginning this guide, you'll need to make sure you have a token that includes the following scopes: | Scope | Reason | | ---------- | ---------- | | **Assets:** Read, Update |- Fetch source and destination Assets.
- Add an Asset to a Version Stack.
- Reorder a Stack.
- Remove an Asset from a Stack.
- Delete a Stack. | ## Adding Assets to Version Stacks ### Step 1: locate your destination The first step is to identify which of the two key scenarios you're in -- adding an Asset to another Asset to create a Stack, or adding an Asset to a Stack to extend that Stack. If you know that you're working with an unversioned Asset, or you already have a Version Stack `id`, you can move onto Step 2. If not, the easiest way to determine whether or not a destination Asset is already part of a stack is to: 1. `GET` your target Asset via call to `/v2/assets/:id​` 2. Check the `type` that comes back. * If it's *version_stack*, the uuid you've just checked is your destination uuid. Move onto Step 2. 3. If the `type` is *file*, grab the `parent_id` 4. GET the parent via the same endpoint, and check its `type`. If the parent's `type` is *version_stack*, use its `id` as your destination. If the `type` is anything else, you're dealing with a regular Asset and can use the original id as your destination. ### Step 2: prepare your payload Now that you have your destination uuid, you need to know the uuid of the Asset you're adding to the Stack. 1. If you're uploading a new Asset, simply use the id returned with the success response when you [create the Asset](ref:post_assets-parentid-children). 2. If you're stacking an existing Asset, you should have the `id` via the process described above. The only body parameter required for a Version Stack addition is `next_asset_id`: ```json { "next_asset_id": "" } ``` ### Step 3: add your source Asset to the destination Now that you have both Asset `id` parameters, you're ready to `POST` to `/assets/:id/version`, where the :id is your destination Asset or Version Stack, and your source (new) Asset is in the body payload. ## Reordering Version Stacks Version Stacks rely on a simple ordinal concept of each asset have `next_asset_id` and `prev_asset_id` neighbors, where the order refers not the version numbering, but each Assets's `index` attribute. The `index` runs opposite the version numbers, so accordingly: * The first (lowest numbered) Version in the Stack has a `prev` Asset, but no `next` Asset * The more recent (highest numbered) Version in the Stack has a `next` Asset, but no `prev` Asset * All "inner" versions have both a `prev` and `next` Asset, which are the Assets with higher and lower Version IDs, respectively. This gives us three distinct scenarios, all of which rely on the same endpoint call: **Call:** ``` PUT https://api.frame.io/v2/asset/:id/tween ``` **Body:** ```json { "prev_asset_id": "", "next_asset_id": "" } ``` In all cases, the `id` in the URL path will be the Asset you're moving. | Scenario | `prev_asset_id` | `next_asset_id` | | ---------- | ---------- | ---------- | | Move to top of Stack | `null` | `id` of the previous top Asset (highest version number). | | Move to bottom of Stack | `id` of the previous bottom Asset (v1). | `null` | | Move Version within a stack | `id` of the Asset just *above* where you'd like to move your Asset. | `id` of the Asset just *below* where you'd like to move your new Asset. | ## Removing Assets and deleting Version Stacks ### Removing Assets When an Asset is moved into a Version Stack, it becomes a child of the Stack itself. The move an Asset out of a Version Stack, what you'll need to do is effectively re-parent it back into the Stack's containing folder. 1. `GET` the Version Stack itself via call to `/v2/assets/:id` 2. Grab the `parent_id` of the Stack itself (which becomes your new target folder `id`) 3. Move the your target Asset into the folder as follows: **Call**: ``` POST https://api.frame.io/v2/assets/:parent_id/move ``` **Body**: ```json { "id":"" } ``` ### Deleting Version Stacks Deleting a Version Stack is extremely straight-forward: ``` DELETE https://api.frame.io/v2/assets/:version_stack_id/unversion ``` That's it. Deleting a Stack will return all its constituent Assets to the Stack's containing folder. If you remove all elements from a Version Stack, you'll end up with a Version Stack with a single element in it. This is easy to spot -- if you `GET` the Version Stack by its `id`, you'll see that it has an attribute of `"version": 1`. All of this is technically ok -- the singleton version will load and play, new versions can be added, and everything will carry on as normal; but to avoid presenting a confusing scenario for users in Frame.io's web and other applications, we recommend deleting singleton Stacks. For more information on the Version Stacking endpoint, please refer to the [Assets](ref:assets) documentation.