# Buckets and objects

A bucket is the container [Object Storage](/en/documentation/platform/object-storage/) keeps objects in. An object is a file, the key it is stored under, and the content type it is served with. Buckets do not nest, and a bucket holds objects directly. This page lists the fields of both, the operations the Azion API v4 exposes, and the errors they return. For the S3 protocol and its credentials, refer to [S3 compatibility](/en/documentation/platform/object-storage/s3-compatibility/).

---

## Bucket names

A bucket name is chosen at creation and cannot be changed afterwards.

| Rule            | Value                                                                       |
| --------------- | --------------------------------------------------------------------------- |
| Length          | 6 to 63 characters                                                          |
| Characters      | Letters, numbers, and the hyphen (`-`)                                      |
| Reserved prefix | A name cannot begin with `azion`                                            |
| Uniqueness      | A name is unique across every Azion account, and never only within your own |

A name that is already taken returns `17000`, and a name beginning with `azion` returns `17001`. Because names are global, a short generic name is likely to be taken. Naming a bucket for the content it holds and the access it needs keeps names available and readable, as in `media-assets-ro`.

---

## Bucket fields

| Field              | Type                                       | Required | Default | Description                                         |
| ------------------ | ------------------------------------------ | -------- | ------- | --------------------------------------------------- |
| `name`             | string, 6 to 63 characters                 | Yes      | —       | The bucket name. Read-only after creation           |
| `workloads_access` | `read_only`, `read_write`, or `restricted` | Yes      | —       | What the Azion platform may do with the bucket      |
| `last_editor`      | string                                     | —        | —       | The account that last changed the bucket. Read-only |
| `last_modified`    | date-time                                  | —        | —       | When the bucket last changed. Read-only             |
| `product_version`  | string                                     | —        | `1.0`   | The bucket schema version. Read-only                |

`workloads_access` is the only field a `PATCH` accepts. Sending `name` in a `PATCH` body returns `17004`.

---

## Access levels

`workloads_access` decides what the Azion platform may do with the bucket when an application serves it. It does not restrict the Azion API or the S3 protocol: a credential that carries `writeFiles` writes to a bucket set to `read_only`.

| Value        | The platform may                                                  | The API and the S3 protocol may             |
| ------------ | ----------------------------------------------------------------- | ------------------------------------------- |
| `read_only`  | Read objects                                                      | Read and write, according to the credential |
| `read_write` | Read and write objects                                            | Read and write, according to the credential |
| `restricted` | Neither read nor write, and the bucket cannot back an application | Read and write, according to the credential |

Azion Console presents the same three levels under **Workloads Access**. For the control and where it sits, refer to [Create a bucket](/en/documentation/guides/application-development/data/create-and-modify-bucket/).

Set `read_only` for content an application serves and nothing writes back. Set `read_write` only where a function writes objects during a request, and guard the path in the function: any request that reaches a `read_write` bucket through an application can modify it. Set `restricted` for data that no application serves.

---

## Object keys and prefixes

An object key identifies one object inside a bucket. It is 1 to 1,024 characters and does not have to match the name of the file it came from.

A key may contain the forward slash (`/`), and the interfaces read a shared leading segment as a prefix. Prefixes are not folders and are not created in advance: uploading to the key `src/assets/logo.svg` in an empty bucket creates the object and the prefix in one request.

```text
README.md
src/index.js
src/assets/logo.svg
```

In that bucket, `README.md` sits at the root, `src` is a prefix holding one object and one nested prefix, and `src/assets` holds `logo.svg`. Listing with `prefix=src/assets/` returns `logo.svg` alone. A Connector that points at the prefix `src/assets` serves that object at the root of the application path.

A key cannot be renamed. Uploading to a key that already holds an object replaces it, and the earlier content cannot be recovered.

---

## Content type

The content type stored with an object is the one the `Content-Type` header of the upload request carries. When the request carries no `Content-Type`, Azion detects the type from the object.

The API also accepts a `Storage-Content-Type` header. It has no effect on the stored content type: an upload that sends `Storage-Content-Type: image/png` and no `Content-Type` stores the type Azion detected. Set `Content-Type` on the upload request.

---

## Operations

Every operation is authenticated and sits under `https://api.azion.com/v4/workspace/storage`.

| Operation          | Method and path                                                          |
| ------------------ | ------------------------------------------------------------------------ |
| List buckets       | `GET /buckets`                                                           |
| Create a bucket    | `POST /buckets`                                                          |
| Retrieve a bucket  | `GET /buckets/{bucket_name}`                                             |
| Update a bucket    | `PATCH /buckets/{bucket_name}`                                           |
| Delete a bucket    | `DELETE /buckets/{bucket_name}`                                          |
| List objects       | `GET /buckets/{bucket_name}/objects`                                     |
| Download an object | `GET /buckets/{bucket_name}/objects/{object_key}`                        |
| Create an object   | `POST /buckets/{bucket_name}/objects/{object_key}`                       |
| Replace an object  | `PUT /buckets/{bucket_name}/objects/{object_key}`                        |
| Delete an object   | `DELETE /buckets/{bucket_name}/objects/{object_key}`                     |
| Copy an object     | `POST /buckets/{bucket_name}/objects/{object_key}/copy/{new_object_key}` |

`POST` on an object key creates the object, and replaces it when the key is already in use. `PUT` replaces an object that exists and returns `17013` for a key that does not, so it never creates one.

### Create a bucket

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/storage/buckets \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "my-bucket-ro",
  "workloads_access": "read_only"
}'
```

The response carries `201` and the created bucket:

```json
{
  "state": "executed",
  "data": {
    "name": "my-bucket-ro",
    "workloads_access": "read_only",
    "last_editor": "user@example.com",
    "last_modified": "2026-01-01T12:00:00.442763+00:00",
    "product_version": "1.0"
  }
}
```

Retrieving a bucket returns the same object under `data` with no `state` key. Creating, updating, and deleting return `state`.

### List buckets

```bash
curl --request GET \
  --url 'https://api.azion.com/v4/workspace/storage/buckets?page_size=10' \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

```json
{
  "count": 1,
  "total_pages": 1,
  "page": 1,
  "page_size": 10,
  "next": null,
  "previous": null,
  "results": [
    {
      "name": "my-bucket-ro",
      "workloads_access": "read_only",
      "last_editor": "user@example.com",
      "last_modified": "2026-01-01T12:00:00.442763+00:00",
      "product_version": "1.0"
    }
  ]
}
```

| Query parameter                           | Effect                                                                             |
| ----------------------------------------- | ---------------------------------------------------------------------------------- |
| `page`, `page_size`                       | Page through the list. `page_size` accepts up to 100                               |
| `search`                                  | Match part of a bucket name                                                        |
| `name`                                    | Match a bucket name exactly                                                        |
| `workloads_access`                        | Filter by access level. Accepts comma-separated values                             |
| `ordering`                                | Order the results by a field                                                       |
| `fields`                                  | Return only the fields named, comma-separated                                      |
| `last_editor`, `created`, `last_modified` | Filter by editor or date. The date filters accept the `__gte` and `__lte` suffixes |

Use `search` to match part of a name. The `name` parameter matches the whole name, so a partial value returns nothing.

### List objects

```bash
curl --request GET \
  --url 'https://api.azion.com/v4/workspace/storage/buckets/my-bucket-ro/objects' \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

```json
{
  "continuation_token": null,
  "results": [
    {
      "key": "src/assets/logo.svg",
      "last_modified": "2026-01-01T12:00:47.054000Z",
      "size": 12,
      "is_folder": false
    }
  ]
}
```

| Query parameter      | Default | Effect                                                                                                                                |
| -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `prefix`             | empty   | List only the keys under a prefix                                                                                                     |
| `all_levels`         | `true`  | List every key. With `false`, a prefix is returned as one entry with `is_folder` set to `true`, `size` of `0`, and no `last_modified` |
| `max_object_count`   | —       | Number of keys per response, capped at 1,000                                                                                          |
| `continuation_token` | —       | Return the next page, using the token the previous response carried                                                                   |

A response with more keys than `max_object_count` carries a `continuation_token`. Send it back in the next request to read the rest.

### Upload an object

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/storage/buckets/my-bucket-ro/objects/src/assets/logo.svg \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: image/svg+xml' \
  --data-binary '@./src/assets/logo.svg'
```

```json
{
  "state": "executed",
  "data": {
    "object_key": "src/assets/logo.svg"
  }
}
```

### Delete an object

```bash
curl --request DELETE \
  --url https://api.azion.com/v4/workspace/storage/buckets/my-bucket-ro/objects/src/assets/logo.svg \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

The response carries `202` and `{"state": "pending"}`. The key stops being listed and stops being served immediately, and the object is removed permanently after a 24-hour grace period.

### Delete a bucket

A bucket is deleted only while it holds no objects, and not within 24 hours of the last object being removed, because of that grace period. Both cases return `17006`. A bucket that never held an object is deleted at once.

---

## Authentication

Every request carries a [personal token](/en/documentation/guides/platform/account-and-billing/personal-tokens/):

```http
Authorization: Token [TOKEN VALUE]
```

The account also needs the storage permissions for the operation. The six permissions are View, Edit, and Delete for a Storage Bucket, and View, Edit, and Delete for a Storage Object. For more information, refer to [Teams permissions](/en/documentation/fundamentals/teams-permissions/).

---

## Errors

The response body carries one `errors` array. Each entry names the `code`, the `title`, a `detail`, the `status`, and the field it applies to under `source.pointer`.

```json
{
  "errors": [
    {
      "code": "17000",
      "title": "Bucket Already Exists",
      "detail": "Bucket name 'my-bucket-ro' is already in use.",
      "status": "400",
      "source": {
        "pointer": "/data/name"
      },
      "meta": {
        "name": "my-bucket-ro"
      }
    }
  ]
}
```

| Code    | Title                            | Status | Cause                                                                               |
| ------- | -------------------------------- | ------ | ----------------------------------------------------------------------------------- |
| `10039` | `Invalid Choice`                 | 400    | `workloads_access` carries a value outside the three the field accepts              |
| `10048` | `Min Length`                     | 400    | The bucket name is shorter than 6 characters                                        |
| `10059` | `Required Field`                 | 400    | `name` or `workloads_access` is missing from a create request                       |
| `17000` | `Bucket Already Exists`          | 400    | The bucket name is in use, in your account or another                               |
| `17001` | `Bucket Name Not Available`      | 400    | The bucket name begins with `azion`                                                 |
| `17004` | `Name Cannot Be Changed`         | 400    | A `PATCH` request carries `name`                                                    |
| `17005` | `Bucket Does Not Exist`          | 404    | The bucket named in the path does not exist                                         |
| `17006` | `Cannot Delete Non Empty Bucket` | 400    | The bucket holds objects, or an object was removed from it within the last 24 hours |
| `17013` | `Object Does Not Exist`          | 404    | The object key does not exist, on a download, a `PUT`, or a delete                  |

---

## The runtime API

The operations above are HTTP calls, addressed to `api.azion.com` and authenticated with a personal token. A function running in Azion Runtime reaches the same buckets a second way: it imports the `azion:storage` module and calls `put`, `get`, `delete`, and `list` on a bucket it names, without a token: the constructor takes the bucket name and nothing else.

That module belongs to the runtime rather than to Object Storage, so its methods, its `StorageObject` shape, and the runtime versions it ships in are documented with the other runtime bindings, in [Storage runtime API](/en/documentation/devtools/runtime/api-reference/storage/).

---

## Related resources

- [How Object Storage works](/en/documentation/platform/object-storage/how-it-works.md): How a request reaches an object, and what each access level changes about it.
- [S3 compatibility](/en/documentation/platform/object-storage/s3-compatibility.md): The credential, the endpoint, and the S3 operations that reach the same buckets.
- [Object Storage limits](/en/documentation/platform/object-storage/limits.md): Every bound on this page in one table, with the usage each plan includes.
- [Create a bucket](/en/documentation/guides/application-development/data/create-and-modify-bucket.md): The procedure behind the bucket operations, from Azion Console, the API, and the Azion CLI.
- [Upload and download objects](/en/documentation/guides/application-development/data/upload-and-download-objects-from-bucket.md): The procedure behind the object operations, with the output each one returns.
- [Storage runtime API](/en/documentation/devtools/runtime/api-reference/storage.md): Reading and writing the same objects from a function, with `azion:storage`.
