> 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/overview.md).

# API Overview

The Umber API is a JSON-over-HTTPS API for managing [virtual assets](/umber/api-reference-v2/virtual-assets.md), their [versions](/umber/api-reference-v2/virtual-assets/versions.md), [collections](/umber/api-reference-v2/collections.md) and their [items](/umber/api-reference-v2/collections/collection-items.md), and for [deploying](/umber/api-reference-v2/virtual-assets/version-deployment.md) them to your [environments](/umber/api-reference-v2/environments.md). This page covers what every endpoint has in common. Each endpoint's own page covers its request and response.

{% hint style="info" %}
v2 is the only supported version of the API. Every path in this reference starts with `/api/v2`.
{% endhint %}

## Base URL

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

`{domainId}` is your workspace's domain ID. It's always a path segment, never a header or query parameter. Only [asset types](/umber/api-reference-v2/asset-types.md) and the health check sit outside it.

## Authentication

Send a **platform API key** as a bearer token on every call:

```bash
curl "https://api.umbercloud.io/api/v2/acme-games/va" \
  -H "Authorization: Bearer $UMBER_API_KEY"
```

A key covers your whole workspace and can call only the endpoints its [scopes](/umber/concepts/api-keys.md#scopes) allow. Each endpoint page lists the scope it needs. See [API Keys and Authentication](/umber/concepts/api-keys.md) to create, rotate and revoke keys.

The `apikey` header (an environment's download key) isn't accepted by this API. Download keys are only for fetching secured content from the delivery network.

## Naming the acting user

A platform key belongs to the workspace, not to a person. So every call that changes something must also name the member it acts for, by email:

| Request                                                     | Field       |
| ----------------------------------------------------------- | ----------- |
| `POST` that creates something                               | `createdBy` |
| `PUT` / `PATCH`, and every deploy, rollback or state change | `updatedBy` |
| `DELETE`                                                    | `deletedBy` |

The user must be an active member of your workspace, and their [role](/umber/concepts/roles-and-permissions.md) must allow the action. A call that names nobody gets `400 "Please provide createdBy"` (or `updatedBy`/`deletedBy`). An email that isn't an active member gets `400 "Invalid domain Id or email information"`. A role that doesn't allow the action gets `403`. Each endpoint page names the field it reads.

## Naming the environment

Deploy, undeploy and rollback calls act on one environment, so they must name it with `envId` in the path, query string or body. A missing `envId` gets `400`, and one that doesn't exist gets `404 "No Environment found for '<envId>'"`. See [Environments](/umber/api-reference-v2/environments.md) to list the IDs.

## Errors

Errors are [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem documents:

```json
{
  "type": "https://docs.umbercloud.io/errors/asset-service",
  "title": "No Asset found for hero-skin-01",
  "status": 404,
  "detail": "No Asset found for hero-skin-01"
}
```

Some errors add fields that help you act on them. For example, a duplicate upload adds `duplicateOf`. Authentication and scope failures use their own `type`:

| `type` ends in   | Status | Meaning                                                                      |
| ---------------- | ------ | ---------------------------------------------------------------------------- |
| `/unauthorized`  | `403`  | No key, or the key is unknown, revoked or expired.                           |
| `/missing-scope` | `403`  | The key is valid but lacks the scope this endpoint needs. `detail` names it. |
| `/not-found`     | `404`  | No such route.                                                               |
| `/asset-service` | any    | Every other error. `detail` says what went wrong.                            |

Two exceptions don't use the problem document shape:

* [Moving and copying items](/umber/api-reference-v2/collections/collection-items.md#move-items-to-another-collection) reports a refusal as `{ "error": "<message>" }`.
* A rate-limited call (`429`) gets `{ "message": "<message>" }`. See [Rate limits](#rate-limits).

## Pagination

List endpoints take `pageNumber` (default `1`) and `pageSize` (default `50`) and return this envelope:

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

[Search](/umber/api-reference-v2/virtual-assets.md#search-virtual-assets), [asset types](/umber/api-reference-v2/asset-types.md) and [environments](/umber/api-reference-v2/environments.md) return their own shapes; their pages describe them.

## Uploads

Files go up in one of two ways, for both [versions](/umber/api-reference-v2/virtual-assets/versions.md) and [collection items](/umber/api-reference-v2/collections/collection-items.md):

| Method                  | How                                                                                                    | Use it for                                                     |
| ----------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- |
| **Single request**      | `multipart/form-data`, with the file in a field named `assetFile` and the metadata as other fields.    | Small files and simple scripts.                                |
| **Two-step (streamed)** | `POST .../uploads` with the metadata as JSON, then `PUT` the raw bytes to the `upload.url` it returns. | Large files. The server streams the bytes straight to storage. |

Every upload is checked before it's stored:

* The file extension must belong to an [asset type](/umber/concepts/asset-types.md) the asset or collection accepts. An unrecognised extension, or one of another type, gets `400`.
* The first bytes must match the declared format, where the format can be fingerprinted.
* Each format has its own size limit, and a file over it gets `400` (or `413` while streaming).
* The legacy type `9999` (Other) no longer accepts uploads.

## Rate limits

Each platform API key has a budget of **600 requests per minute**. When the budget is enforced, responses carry `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` headers. A call over the budget gets `429` with a `Retry-After` header (in seconds):

```json
{ "message": "Rate limit exceeded: 600 requests per minute. Retry after 23s." }
```

Wait for `Retry-After` before retrying.

## Billing

On pay-as-you-go accounts, every API call made with a platform API key counts toward your monthly API-call usage. Calls the server fails on its own side (`5xx`) and rate-limited calls (`429`) aren't counted.

## Health check

`GET /api/v2/health` needs no key:

```json
{ "status": "ok", "version": "v2" }
```
