# Assets

Source: https://docs.arcweave.com/rest-api/assets
Section: REST API
Description: REST API endpoints for asset folders, asset records, and files

Asset endpoints manage the asset tree and upload or download asset files.

Upload a media file and create its asset record in one multipart `POST /asset` request. The returned asset ID is ready to use for attachments, metadata requests, and downloads. Folders use a JSON request on the same endpoint.

**Warning: Breaking change: asset uploads**
The standalone `POST /asset/upload` route has been removed from both `/api/v1` and `/api`; requests to it return `405 Method Not Allowed`. Replace the old upload-then-register flow with [one multipart creation request](https://docs.arcweave.com/rest-api/assets#create-asset-or-folder) containing `name`, `type`, and the binary `file`. JSON media creation with a stored filename, media creation without a file, and creation requests containing `size` return `400 Bad Request`.

Creation returns `201 Created` with an asset `id` and project version data. To retrieve the stored filename and size, use [Get asset](https://docs.arcweave.com/rest-api/assets#get-asset) with that ID. Existing file replacement clients also need to follow the [replacement workflow](https://docs.arcweave.com/rest-api/assets#replace-an-asset-file).

## Endpoints

Context: Arcweave docs > REST API > Assets > Endpoints

### Get assets

Context: Arcweave docs > REST API > Assets > Endpoints > Get assets

`GET /api/v1/{hash}/asset`

**Request**

```http title="HTTP"
GET /api/v1/{hash}/asset
```

```bash title="curl"
curl --request GET \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Accept: application/json" \
  "https://arcweave.com/api/v1/PROJECT_HASH/asset"
```

**Response**

Returns `200 OK` with a compact representation of the complete asset tree:

```json
[
  {
    "id": "root_asset",
    "name": "Root",
    "type": "folder",
    "parentId": null,
    "children": ["image_1", "audio_folder"]
  },
  {
    "id": "image_1",
    "name": "Castle.png",
    "type": "image",
    "parentId": "root_asset",
    "children": []
  },
  {
    "id": "audio_folder",
    "name": "Audio",
    "type": "folder",
    "parentId": "root_asset",
    "children": []
  }
]
```

Every entry contains `id`, `name`, `type`, `parentId`, and `children`. Folder entries, including the internal root, use `type: "folder"`. File assets use their stored asset type. File asset names include the stored file extension when one is available.

### Get asset

Context: Arcweave docs > REST API > Assets > Endpoints > Get asset

`GET /api/v1/{hash}/asset/{assetID}`

**Request**

```http title="HTTP"
GET /api/v1/{hash}/asset/{assetID}
```

```bash title="curl"
curl --request GET \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Accept: application/json" \
  "https://arcweave.com/api/v1/PROJECT_HASH/asset/{assetID}"
```

**Response**

Returns `200 OK`.

File-bearing assets include `type` and `file`:

```json
{
  "id": "a01",
  "name": "asset 1",
  "type": "image",
  "file": "asset_1.jpg",
  "size": "12.06 KB"
}
```

Folders include `children` and do not include file-bearing properties.

### Create asset or folder

Context: Arcweave docs > REST API > Assets > Endpoints > Create asset or folder

`POST /api/v1/{hash}/asset`

**Request**

For media assets, send `multipart/form-data` containing the metadata and one binary file. The request requires **Write projects** API key permission, permission to edit the project, and a workspace plan that supports asset uploads.

```http title="HTTP"
POST /api/v1/{hash}/asset
Content-Type: multipart/form-data
```

```bash title="curl"
curl --request POST \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Accept: application/json" \
  --form-string "name=Castle" \
  --form-string "type=image" \
  --form "file=@path/to/file.png" \
  "https://arcweave.com/api/v1/PROJECT_HASH/asset"
```

Let your HTTP client set the multipart `Content-Type` header and boundary. With curl, `--form` does this automatically.

Request fields:

| Property   | Required  | Type                          | Description                                                                   |
| ---------- | --------- | ----------------------------- | ----------------------------------------------------------------------------- |
| `name`     | Yes       | String                        | Nonempty asset or folder name.                                                |
| `type`     | For media | String                        | `image`, `audio`, or `video`. Omit to create a folder.                        |
| `file`     | For media | File                          | Binary upload. Omit for folders.                                              |
| `volume`   | No        | Number                        | Initial volume metadata for a media asset, from `0` to `1`. Omit for folders. |
| `fadeIn`   | No        | Number                        | Default fade-in duration for an audio asset, in milliseconds (zero or more).  |
| `fadeOut`  | No        | Number                        | Default fade-out duration for an audio asset, in milliseconds (zero or more). |
| `parentId` | No        | String or `null`              | Existing target folder in this project. Omit or use `null` for the root.      |
| `index`    | No        | Non-negative integer or `"-"` | Position in the target folder. Defaults to `"-"`, which appends the item.     |

Multipart numeric strings are accepted for `volume`, `fadeIn`, `fadeOut`, and `index`. Audio references attached to elements use the asset's `volume`, `fadeIn`, and `fadeOut` unless they [override them](https://docs.arcweave.com/rest-api/elements#attach-audio). Arcweave generates the asset ID and stored filename and calculates the size from the uploaded file. Do not send `size`, `id`, or other fields outside this table.

The target parent must exist and be a folder. Template asset trees are read-only.

**Supported formats and limits**

The uploaded file must match the selected `type`:

| `type`  | Accepted formats                       |
| ------- | -------------------------------------- |
| `image` | JPEG (`.jpeg`, `.jpg`), PNG, GIF, WebP |
| `audio` | MPEG/MP3, Ogg, WAV, WebM               |
| `video` | MP4, WebM, Ogg                         |

Arcweave checks the file's content to determine its MIME type. Renaming a file's extension does not make an unsupported format valid.

- Images have separate width and height limits, each defaulting to **8192 pixels**. These limits are configurable on the server; a validation error reports the applicable limit.
- The workspace plan sets the maximum size of one file and the total asset size per project. Standard Team limits are **400 MB per file** and **10 GB per project**; see [asset upload limits](https://docs.arcweave.com/project-items/assets/overview#asset-upload-limits).
- The total-size check uses exact stored byte sizes and includes existing assets, in-progress uploads, and the incoming file. Concurrent uploads to the same project share the remaining allowance.

Unsupported file content, exceeded image dimensions, a plan without asset uploads, and exceeded plan limits return `400 Bad Request` with details in `errors.file`. Request-size limits on the server can reject an oversized upload before API validation runs.

**Create a folder**

Send JSON with `name` and, optionally, `parentId` and `index`. Omit `type`, `file`, `volume`, `fadeIn`, and `fadeOut`; do not send `type: "folder"`.

```http title="HTTP"
POST /api/v1/{hash}/asset
Content-Type: application/json
```

```bash title="curl"
curl --request POST \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data @payload.json \
  "https://arcweave.com/api/v1/PROJECT_HASH/asset"
```

```json
{
  "name": "Locations"
}
```

Folder creation requires REST API access and edit permissions, but does not require the plan's asset-upload feature or consume asset storage.

**Response**

Returns `201 Created` with the generated resource ID and project version data:

```json
{
  "version": 12,
  "newVersion": 13,
  "versionTime": ["1720788000", "123456"],
  "id": "65139ea3-331f-4b25-88b4-ea7a65ff106c"
}
```

For media assets, a successful response means the file is stored and the asset is registered. Use the returned `id` with [Get asset](https://docs.arcweave.com/rest-api/assets#get-asset) to read its `file` and `size`, or [Download asset file](https://docs.arcweave.com/rest-api/assets#download-asset-file) to retrieve the original binary. These read requests require **Read projects** API key permission.

**Upload failures and retries**

An upload reservation that expires before file storage begins returns `410 Gone`. Retry it with a fresh upload request. Failed uploads can continue to occupy reserved storage until cleanup succeeds.

A timeout, lost connection, or `500` response can occur after the asset has been created. Check [Get assets](https://docs.arcweave.com/rest-api/assets#get-assets) before retrying: another POST creates another asset. See [Retrying requests](https://docs.arcweave.com/rest-api/overview#retrying-requests) for general retry guidance.

### Update asset

Context: Arcweave docs > REST API > Assets > Endpoints > Update asset

`PATCH /api/v1/{hash}/asset/{assetID}`

**Request**

```http title="HTTP"
PATCH /api/v1/{hash}/asset/{assetID}
```

```bash title="curl"
curl --request PATCH \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data @payload.json \
  "https://arcweave.com/api/v1/PROJECT_HASH/asset/{assetID}"
```

```json
{
  "name": "Updated Castle"
}
```

Request fields:

| Property  | Required | Type   | Description                                                                           |
| --------- | -------- | ------ | ------------------------------------------------------------------------------------- |
| `name`    | No       | String | Updated name. If omitted, the current value is retained.                              |
| `type`    | No       | String | `image`, `audio`, or `video`. If omitted, the current value is retained.              |
| `file`    | No       | String | Existing stored filename in this project for the selected media type. Omit to retain. |
| `size`    | No       | String | Accepted, but replaced with the actual stored file size. Omit this field.             |
| `volume`  | No       | Number | Updated volume metadata, from `0` to `1`.                                             |
| `fadeIn`  | No       | Number | Updated default fade-in duration for an audio asset, in milliseconds.                 |
| `fadeOut` | No       | Number | Updated default fade-out duration for an audio asset, in milliseconds.                |

The effective `file` must exist in this project under the selected media type. Omitted `type` and `file` use the asset's current values. Every media update checks this reference, including name-only, volume-only, and fade-only updates, and refreshes `size` from the stored file. A missing filename or a file that does not exist for this project and type returns `400 Bad Request` with `errors.file`.

This endpoint accepts JSON metadata. To supply a new binary file while keeping the original asset's ID and references, follow [Replace an asset file](https://docs.arcweave.com/rest-api/assets#replace-an-asset-file).

- Folders may be renamed but cannot receive file-asset properties.
- Template assets cannot be modified.
- The internal `root_asset` container cannot be modified.

**Response**

Returns `200 OK` with project version data:

```json
{
  "version": 12,
  "newVersion": 13,
  "versionTime": ["1720788000", "123456"]
}
```

### Move or reorder asset

Context: Arcweave docs > REST API > Assets > Endpoints > Move or reorder asset

`PATCH /api/v1/{hash}/asset/{assetID}/index`

**Request**

```http title="HTTP"
PATCH /api/v1/{hash}/asset/{assetID}/index
```

```bash title="curl"
curl --request PATCH \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data @payload.json \
  "https://arcweave.com/api/v1/PROJECT_HASH/asset/{assetID}/index"
```

```json
{
  "parentId": "folder_1",
  "index": 0
}
```

Request fields:

| Property   | Required | Type                 | Description                                                              |
| ---------- | -------- | -------------------- | ------------------------------------------------------------------------ |
| `parentId` | No       | String or `null`     | Target folder. Omit to keep the current parent; use `null` for the root. |
| `index`    | Yes      | Non-negative integer | New position within the target folder.                                   |

- `index` is required.
- Omit `parentId` to reorder within the current folder.
- Use `"parentId": null` to move to the root asset container.
- The target must be a folder.
- An asset folder cannot be moved into itself or one of its descendants.
- The root and template asset trees cannot be moved.

**Response**

Returns `200 OK` with project version data:

```json
{
  "version": 12,
  "newVersion": 13,
  "versionTime": ["1720788000", "123456"]
}
```

### Delete asset

Context: Arcweave docs > REST API > Assets > Endpoints > Delete asset

`DELETE /api/v1/{hash}/asset/{assetID}`

**Request**

```http title="HTTP"
DELETE /api/v1/{hash}/asset/{assetID}
```

```bash title="curl"
curl --request DELETE \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Accept: application/json" \
  "https://arcweave.com/api/v1/PROJECT_HASH/asset/{assetID}"
```

Deleting a folder deletes its subtree. The root and template asset trees cannot be deleted.

Deleting an asset also removes its uses throughout the project: element and component covers, audio attachments, and entries in attribute asset lists. Deleting a folder applies this removal to every asset in its subtree.

To replace a file while retaining these references, [update the existing asset](https://docs.arcweave.com/rest-api/assets#update-asset).

**Response**

Returns `200 OK` with project version data:

```json
{
  "version": 12,
  "newVersion": 13,
  "versionTime": ["1720788000", "123456"]
}
```

### Download asset file

Context: Arcweave docs > REST API > Assets > Endpoints > Download asset file

`GET /api/v1/{hash}/asset/{assetID}/file`

**Request**

```http title="HTTP"
GET /api/v1/{hash}/asset/{assetID}/file
```

```bash title="curl"
curl --request GET \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Accept: application/json" \
  --output OUTPUT_FILE \
  "https://arcweave.com/api/v1/PROJECT_HASH/asset/{assetID}/file"
```

**Response**

Returns `200 OK` with the stored binary file. The `Content-Type` header is the file's MIME type, such as `image/png`.

Both project-uploaded and referenced template asset files can be returned. Requesting a folder returns `400 Bad Request`; a missing stored file returns `404 Not Found`.

**Info: Asset delivery URLs**
Arcweave can serve media files through `/media/` URLs on its own domain. If you already have a media link, use it as it is; existing public Google storage URLs remain accessible. API clients can continue to download file bytes through this authenticated endpoint.

## Replace an asset file

Context: Arcweave docs > REST API > Assets > Replace an asset file

To upload a replacement while preserving the original asset's ID and all references to it:

1. [Create a media asset](https://docs.arcweave.com/rest-api/assets#create-asset-or-folder) in the same project with the replacement binary and the original asset's `type`. This creates an additional asset; the upload needs enough remaining project storage for the new file.
2. [Get the new asset](https://docs.arcweave.com/rest-api/assets#get-asset) using the creation response's `id`, and read its `file` value.
3. [Update the original asset](https://docs.arcweave.com/rest-api/assets#update-asset) with a JSON body containing that stored filename, for example `{"file":"STORED_FILENAME_FROM_GET"}`. Use the original asset's ID in the PATCH URL.
4. After the update succeeds, [delete the additional asset record](https://docs.arcweave.com/rest-api/assets#delete-asset) if it is no longer needed. Use the new asset's ID for this DELETE. The original asset keeps its references and can still use the replacement file.

Both asset records count toward project storage while they reference the file. Removing the additional record avoids counting the replacement twice. This workflow requires both **Read projects** and **Write projects** API key permissions.

## Common errors

Context: Arcweave docs > REST API > Assets > Common errors

| Status | Meaning                                                                                                                                                               |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Invalid metadata/upload or PATCH file reference, folder file mutation or download, root/template mutation, non-folder parent, recursive move, or plan limit exceeded. |
| `403`  | Project permission denied.                                                                                                                                            |
| `404`  | Project, asset, or parent not found, or the stored file is missing when downloading.                                                                                  |
| `405`  | POST sent to the removed `/asset/upload` route.                                                                                                                       |
| `409`  | Asset or parent changed before the command was applied.                                                                                                               |
| `410`  | Upload reservation expired before file storage began. Retry with a fresh upload request.                                                                              |
