> For the complete documentation index, see [llms.txt](https://umber.gitbook.io/umber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://umber.gitbook.io/umber/api-reference-v2/collections.md).

# Collections API

A [Virtual Collection](/umber/concepts/virtual-collections.md) is a named bundle of asset items — deployed and versioned as one unit, rather than one virtual asset at a time. This reference covers creating, reading, updating, listing, and the delete/restore/purge lifecycle of a collection container itself.

Two related surfaces are **not** covered here, and aren't available yet in this reference:

* **Items** — adding, uploading, moving, copying and removing the individual asset items inside a collection.
* **Deployments** — deploying/redeploying/undeploying a collection to an environment, and reading its deployed URL or status.

{% hint style="info" %}
This is a low-level HTTP reference. For deployment state concepts (Live/Offline), see [Deployment States](/umber/concepts/deployment-states.md).
{% endhint %}

## Base URL and authentication

```
https://api.umbercloud.io/api/v2/{domainId}/vc
```

Authenticate with the same `apikey` header as the [Virtual Assets API](/umber/api-reference-v2/virtual-assets.md#base-url-and-authentication).

## The collection object

| Field                     | Type                                                        | On create                                                                 | On update                                                                                       | Returned in responses |
| ------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | --------------------- |
| `collectionId`            | string, ≤ 50 chars, letters/numbers/`_`/`-`                 | required, unique in your domain                                           | not accepted — permanent once created                                                           | yes                   |
| `collectionName`          | string, ≤ 50 chars                                          | required                                                                  | optional                                                                                        | yes                   |
| `description`             | string, ≤ 400 chars                                         | optional                                                                  | optional                                                                                        | yes                   |
| `allowedAssetTypes`       | array of [asset type](/umber/concepts/asset-types.md) codes | required, non-empty, every code must be a real asset type                 | not accepted — permanent once created                                                           | yes                   |
| `maxAssets`               | integer, 1–5000 (service-configured ceiling)                | optional, defaults to the service's ceiling                               | optional — rejected if set below the collection's current item count                            | yes                   |
| `editable`                | boolean                                                     | optional, defaults to `true`                                              | optional                                                                                        | yes                   |
| `deployable`              | boolean                                                     | optional, defaults to `true`                                              | optional                                                                                        | yes                   |
| `anchorAsset`             | string (an item id)                                         | optional                                                                  | optional                                                                                        | yes                   |
| `assetItems`              | array of item id strings                                    | not accepted — every new collection starts empty                          | not accepted — use the items API to add/remove items                                            | yes                   |
| `targetPlatform`          | string (a target platform code)                             | optional, defaults to `"generic"`                                         | not accepted — permanent once created                                                           | yes                   |
| `createdBy`               | string (email)                                              | required — must be the email of an active admin/owner user in your domain | not accepted                                                                                    | yes                   |
| `updatedBy`               | string (email)                                              | optional, defaults to `createdBy`                                         | **not required by this endpoint — see note below**                                              | yes                   |
| `deleted` / `deletedAt`   | boolean / date                                              | not accepted                                                              | not accepted — use [delete](#delete-a-collection-soft)/[restore](#restore-a-collection) instead | yes                   |
| `localCacheControl`       | boolean                                                     | optional, defaults to `false`                                             | optional                                                                                        | yes                   |
| `localCacheMaxAge`        | integer, 1–525600                                           | optional, defaults to `30`                                                | optional                                                                                        | yes                   |
| `createdAt` / `updatedAt` | ISO 8601 timestamp                                          | set automatically                                                         | set automatically                                                                               | yes                   |

`secured` is accepted on create (defaults to `true`) but is **never returned** by any endpoint in this reference — there's currently no way to read it back through this API.

{% hint style="warning" %}
**Always send `updatedBy` on update, even though it isn't enforced.** Unlike create and delete, the update endpoint doesn't actually require `updatedBy` in the body. If you omit it, the request can still succeed but the acting-user check falls back to matching *any* active admin/owner in your domain rather than specifically you — so the safe practice is to always send it anyway.
{% endhint %}

Send a plain JSON body for every endpoint in this reference — there's no file upload here (that's on the items API).

## Errors

Every error is a small JSON body, same shape as [the Virtual Assets API](/umber/api-reference-v2/virtual-assets.md#errors):

```json
{
  "type": "https://docs.umbercloud.io/errors/asset-service",
  "title": "Asset collection season-pass-bundle not found.",
  "status": 400,
  "detail": "Asset collection season-pass-bundle not found."
}
```

| Status | Meaning                                                                                                                                                                                                                                        |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Missing/invalid field; an immutable field was sent on update; `collectionId` not found (on **get**, specifically — see the note below); already deleted or already restored; still Live in some environment (delete); not yet deleted (purge). |
| `403`  | Missing or invalid `apikey`.                                                                                                                                                                                                                   |
| `404`  | `collectionId` not found — on **update, delete, restore and purge** (a different status than get, see below).                                                                                                                                  |
| `409`  | `collectionId` already in use.                                                                                                                                                                                                                 |
| `500`  | Unexpected server error.                                                                                                                                                                                                                       |

{% hint style="warning" %}
**"Not found" is `400` for Get, but `404` everywhere else.** Getting a collection that doesn't exist returns `400`; updating, deleting, restoring, or purging one that doesn't exist returns `404`. Check the status code, not just the shape, when handling a missing `collectionId`.
{% endhint %}

## Pagination

Same envelope as [the Virtual Assets API](/umber/api-reference-v2/virtual-assets.md#pagination):

```json
{
  "totalResults": 137,
  "pageNumber": 1,
  "pageSize": 50,
  "results": []
}
```

***

## Create a collection

`POST /api/v2/{domainId}/vc`

{% tabs %}
{% tab title="JSON" %}

```json
{
  "collectionId": "season-pass-bundle",
  "collectionName": "Season Pass Bundle",
  "allowedAssetTypes": ["0001", "0002"],
  "createdBy": "dev@acme-games.com",
  "maxAssets": 20
}
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -X POST "https://api.umbercloud.io/api/v2/acme-games/vc" \
  -H "apikey: $ASSET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "collectionId": "season-pass-bundle",
    "collectionName": "Season Pass Bundle",
    "allowedAssetTypes": ["0001", "0002"],
    "createdBy": "dev@acme-games.com",
    "maxAssets": 20
  }'
```

{% endtab %}
{% endtabs %}

`201 Created`

```json
{
  "collectionId": "season-pass-bundle",
  "domainId": "acme-games",
  "collectionName": "Season Pass Bundle",
  "assetItems": [],
  "editable": true,
  "deployable": true,
  "maxAssets": 20,
  "allowedAssetTypes": ["0001", "0002"],
  "createdBy": "dev@acme-games.com",
  "updatedBy": "dev@acme-games.com",
  "targetPlatform": "generic",
  "createdAt": "2026-09-07T12:00:00.000Z",
  "updatedAt": "2026-09-07T12:00:00.000Z",
  "deleted": false,
  "localCacheControl": false,
  "localCacheMaxAge": 30
}
```

`assetItems` always comes back empty — a collection is created with no items; add them through the items API afterward.

## Get a collection

`GET /api/v2/{domainId}/vc/{collectionId}`

```bash
curl "https://api.umbercloud.io/api/v2/acme-games/vc/season-pass-bundle" \
  -H "apikey: $ASSET_API_KEY"
```

`200 OK` — same shape as the create response.

`400` if `collectionId` doesn't exist:

```json
{
  "type": "https://docs.umbercloud.io/errors/asset-service",
  "title": "Asset collection season-pass-bundle not found.",
  "status": 400,
  "detail": "Asset collection season-pass-bundle not found."
}
```

## List collections

`GET /api/v2/{domainId}/vc`

```bash
curl "https://api.umbercloud.io/api/v2/acme-games/vc?pageNumber=1&pageSize=50" \
  -H "apikey: $ASSET_API_KEY"
```

`200 OK`

```json
{
  "totalResults": 1,
  "pageNumber": 1,
  "pageSize": 50,
  "results": [
    {
      "collectionId": "season-pass-bundle",
      "domainId": "acme-games",
      "collectionName": "Season Pass Bundle",
      "assetItems": [],
      "editable": true,
      "deployable": true,
      "maxAssets": 20,
      "allowedAssetTypes": ["0001", "0002"],
      "createdBy": "dev@acme-games.com",
      "updatedBy": "dev@acme-games.com",
      "targetPlatform": "generic",
      "createdAt": "2026-09-07T12:00:00.000Z",
      "updatedAt": "2026-09-07T12:00:00.000Z",
      "deleted": false,
      "localCacheControl": false,
      "localCacheMaxAge": 30
    }
  ]
}
```

There's no filtering — every call returns your domain's full set of collections, paginated, **including soft-deleted ones** (`deleted: true`).

## Update a collection

`PATCH /api/v2/{domainId}/vc/{collectionId}`

Partial update — send only the fields you want to change. `collectionId`, `allowedAssetTypes` and `targetPlatform` can't be changed after creation. `assetItems` and `deleted` are rejected outright — use the items API or the [delete](#delete-a-collection-soft)/[restore](#restore-a-collection) endpoints instead.

{% tabs %}
{% tab title="JSON" %}

```json
{
  "updatedBy": "dev@acme-games.com",
  "collectionName": "Season Pass Bundle (v2)",
  "maxAssets": 30
}
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -X PATCH "https://api.umbercloud.io/api/v2/acme-games/vc/season-pass-bundle" \
  -H "apikey: $ASSET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "updatedBy": "dev@acme-games.com",
    "collectionName": "Season Pass Bundle (v2)",
    "maxAssets": 30
  }'
```

{% endtab %}
{% endtabs %}

`200 OK` — same shape as the create response, reflecting the change.

`400` if `maxAssets` is set below the collection's current item count, or if `assetItems`/`deleted` is present in the body. `404` if `collectionId` doesn't exist (see the [status-code note above](#errors)).

## Delete a collection (soft)

`DELETE /api/v2/{domainId}/vc/{collectionId}`

Soft delete — the collection is marked `deleted: true`, not removed, and can be [restored](#restore-a-collection) later. Requires `deletedBy` in the body. Fails if the collection is currently Live in any environment — take it offline everywhere first (see [Deployment States](/umber/concepts/deployment-states.md)).

{% tabs %}
{% tab title="JSON" %}

```json
{ "deletedBy": "dev@acme-games.com" }
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -X DELETE "https://api.umbercloud.io/api/v2/acme-games/vc/season-pass-bundle" \
  -H "apikey: $ASSET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "deletedBy": "dev@acme-games.com" }'
```

{% endtab %}
{% endtabs %}

`200 OK`

```json
{ "message": "Asset collection season-pass-bundle has been deleted." }
```

Not a collection object — just a confirmation message.

`400` if it's already deleted, or if it's still Live somewhere:

```json
{
  "type": "https://docs.umbercloud.io/errors/asset-service",
  "title": "Asset collection season-pass-bundle is LIVE. Please make it OFFLINE before deleting.",
  "status": 400,
  "detail": "Asset collection season-pass-bundle is LIVE. Please make it OFFLINE before deleting."
}
```

`404` if `collectionId` doesn't exist.

## Restore a collection

`POST /api/v2/{domainId}/vc/{collectionId}/restore`

Reverses a soft delete.

{% hint style="warning" %}
This endpoint asks for **`createdBy`** in the body, not `deletedBy` — even though you're restoring, not creating, anything.
{% endhint %}

{% tabs %}
{% tab title="JSON" %}

```json
{ "createdBy": "dev@acme-games.com" }
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -X POST "https://api.umbercloud.io/api/v2/acme-games/vc/season-pass-bundle/restore" \
  -H "apikey: $ASSET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "createdBy": "dev@acme-games.com" }'
```

{% endtab %}
{% endtabs %}

`200 OK`

```json
{ "message": "Asset collection season-pass-bundle has been restored." }
```

`400` if it isn't currently deleted. `404` if `collectionId` doesn't exist.

## Purge a collection

`POST /api/v2/{domainId}/vc/{collectionId}/purge`

**Hard delete** — permanently removes the collection, its deployment records in every environment, and any asset item whose *only* parent collection was this one (an item shared with another collection is kept). The collection must already be soft-[deleted](#delete-a-collection-soft) first.

{% hint style="warning" %}
Like restore, this endpoint asks for **`createdBy`** in the body.
{% endhint %}

{% tabs %}
{% tab title="JSON" %}

```json
{ "createdBy": "dev@acme-games.com" }
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -X POST "https://api.umbercloud.io/api/v2/acme-games/vc/season-pass-bundle/purge" \
  -H "apikey: $ASSET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "createdBy": "dev@acme-games.com" }'
```

{% endtab %}
{% endtabs %}

`200 OK`

```json
{ "message": "Asset collection season-pass-bundle has been purged." }
```

`400` if it isn't already deleted:

```json
{
  "type": "https://docs.umbercloud.io/errors/asset-service",
  "title": "Please delete Asset collection season-pass-bundle first.",
  "status": 400,
  "detail": "Please delete Asset collection season-pass-bundle first."
}
```

This is irreversible — purge removes the record permanently, unlike delete.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://umber.gitbook.io/umber/api-reference-v2/collections.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
