# S3 compatibility

[Object Storage](/en/documentation/platform/object-storage/) answers S3 requests on its own endpoint, so a tool, an SDK, or a library that speaks the S3 protocol reaches the same buckets and the same objects the Azion API v4 reaches. What changes is the credential: the API v4 carries a personal token, and the S3 endpoint carries a request signed with Signature Version 4 (SigV4) using an access key and a secret key. This page lists the credential that holds that key pair, the capabilities it grants, the connection settings, and the S3 operations Azion supports. For the steps that configure a client, refer to [Use S3-compatible tools with Object Storage](/en/documentation/guides/application-development/data/use-s3-compatible-tools-with-object-storage/).

---

## Connection settings

An S3 client needs the endpoint, the region, and the key pair of a credential.

| Setting    | Value                                   |
| ---------- | --------------------------------------- |
| Endpoint   | `s3.us-east-005.azionstorage.net`       |
| Region     | `us-east-005`                           |
| Access key | The `access_key` the credential returns |
| Secret key | The `secret_key` the credential returns |

A client that builds its own host names takes the DNS-style template `%(bucket).s3.us-east-005.azionstorage.net`.

Both address forms reach the same object. Virtual-host style carries the bucket in the host name, and path style carries it in the first path segment:

```text
my-bucket-ro.s3.us-east-005.azionstorage.net/file.txt
s3.us-east-005.azionstorage.net/my-bucket-ro/file.txt
```

The endpoint manages objects; it does not deliver them to end users. A bucket reaches the public through a [Connector](/en/documentation/platform/connectors/) that points at it and a rule that sends requests to the connector, in front of an [application](/en/documentation/platform/applications/).

---

## Credentials

A credential holds the key pair an S3 client signs with, the operations that key pair may run, and the buckets it may reach. Create one in Azion Console, under **Create Credential**, or through the Azion API v4 at `https://api.azion.com/v4/workspace/storage/credentials`. This page documents the API; the Console presents the same capabilities as checkboxes, labelled **List Files**, **Read Files**, **Write Files**, **Delete Files**, **List All Bucket Names**, and **List Buckets**.

A credential is independent of the bucket's access level: `workloads_access` governs what the Azion platform may do with a bucket, and a credential that carries `writeFiles` writes to a bucket set to `read_only`. For the access levels, refer to [Buckets and objects](/en/documentation/platform/object-storage/buckets-and-objects/).

| Field             | Type                    | Required | Default                     | Description                                                                                    |
| ----------------- | ----------------------- | -------- | --------------------------- | ---------------------------------------------------------------------------------------------- |
| `name`            | string                  | Yes      | —                           | The name of the credential                                                                     |
| `capabilities`    | array of strings        | Yes      | —                           | The operations the credential may run, from the six values under [Capabilities](#capabilities) |
| `buckets`         | array of bucket names   | No       | Every bucket in the account | The buckets the credential reaches                                                             |
| `expiration_date` | date-time, UTC ISO 8601 | No       | `null`                      | When the credential expires. The field returns `null` when the request omits it                |

> **Caution**
>
> `buckets` is plural, it takes an array, and it is the field that scopes a credential. A create request that omits it produces a credential that reaches every bucket in the account.

### Create a credential

Create the credential with the personal token of the account that owns the buckets:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/storage/credentials \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "my-credential",
  "capabilities": ["listFiles", "readFiles", "writeFiles", "deleteFiles", "listAllBucketNames", "listBuckets"],
  "buckets": ["my-bucket-ro"],
  "expiration_date": "2026-12-31T23:59:59Z"
}'
```

The response carries `201` and the credential, with both keys:

```json
{
  "state": "executed",
  "data": {
    "id": 1236,
    "name": "my-credential",
    "access_key": "[ACCESS KEY]",
    "secret_key": "[SECRET KEY]",
    "capabilities": [
      "listAllBucketNames",
      "listBuckets",
      "listFiles",
      "readFiles",
      "writeFiles",
      "deleteFiles"
    ],
    "buckets": ["my-bucket-ro"],
    "expiration_date": "2026-12-31T23:59:59Z",
    "last_editor": "user@example.com",
    "created_at": "2026-01-01T12:03:16.829681Z",
    "last_modified": "2026-01-01T12:03:16.829695Z"
  }
}
```

`secret_key` is returned by this response and by no other call. Store it when the credential is created; to replace a secret key that was not stored, create another credential.

### List credentials

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

The response is paginated and carries every field of each credential except the secret key:

```json
{
  "count": 1,
  "total_pages": 1,
  "page": 1,
  "page_size": 10,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": 1236,
      "name": "ci-upload",
      "access_key": "[ACCESS KEY]",
      "capabilities": ["listFiles", "readFiles", "writeFiles"],
      "buckets": ["my-bucket-ro"],
      "expiration_date": "2027-01-31T23:59:59Z",
      "created_at": "2026-01-01T12:03:16.829681Z",
      "last_modified": "2026-01-01T12:03:16.829695Z",
      "last_editor": "user@example.com"
    }
  ]
}
```

A credential is never returned with its `secret_key`, and the value cannot be recovered after the create request. Replace a lost secret key by creating another credential and deleting the old one.

### Delete a credential

Delete a credential by the `id` the create response returned:

```bash
curl --request DELETE \
  --url https://api.azion.com/v4/workspace/storage/credentials/<credential-id> \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

The response carries `200`. The key pair stops signing valid requests.

---

## Capabilities

A capability names the S3 operations a credential may run. The `capabilities` array accepts these six values and no others.

| Capability           | S3 operations                                                                     |
| -------------------- | --------------------------------------------------------------------------------- |
| `listFiles`          | ListObjects, ListObjectsV2                                                        |
| `readFiles`          | GetObject, HeadObject                                                             |
| `writeFiles`         | PutObject, CreateMultipartUpload, UploadPart, CompleteMultipartUpload, CopyObject |
| `deleteFiles`        | DeleteObject, DeleteObjects, AbortMultipartUpload                                 |
| `listAllBucketNames` | ListBuckets                                                                       |
| `listBuckets`        | HeadBucket, ListMultipartUploads, ListParts                                       |

`deleteFiles` requires `writeFiles` on the same credential. A value outside the six returns `17008`, and `listBuckets` also changes the status a request for a missing object receives, as described under [Errors](#errors).

---

## Supported operations

Azion supports the sixteen S3 operations below. Each one belongs to a billing class the [Terms of Service](/en/documentation/agreements/tos/) defines: Class A, Class B, or Class C. Class C operations are included on every plan. For the usage each plan includes, refer to [Object Storage limits](/en/documentation/platform/object-storage/limits/), and for rates, refer to [Pricing](/en/documentation/fundamentals/pricing/#object-storage).

The last column carries the [s3cmd](https://s3tools.org/s3cmd) form of each operation, as an example of how a client expresses it.

| Operation               | Class | What it does                                                                                          | s3cmd command                                        |
| ----------------------- | ----- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| ListBuckets             | A     | Lists the buckets in the account                                                                      | `s3cmd ls`                                           |
| HeadBucket              | A     | Checks that a bucket exists and that the credential reaches it, returning `200 OK` or `404 Not Found` | `s3cmd info s3://BUCKET`                             |
| ListMultipartUploads    | A     | Lists the multipart uploads in progress in a bucket                                                   | `s3cmd multipart s3://BUCKET`                        |
| ListObjects             | A     | Lists up to 1,000 objects in a bucket, sorted by key                                                  | `s3cmd ls s3://BUCKET`                               |
| ListObjectsV2           | A     | Lists up to 1,000 objects in a bucket and pages past that with a continuation token                   | `s3cmd ls s3://BUCKET`                               |
| CopyObject              | A     | Copies an object that is already stored                                                               | `s3cmd cp s3://BUCKET1/OBJECT1 s3://BUCKET2/OBJECT2` |
| GetObject               | B     | Returns an object                                                                                     | `s3cmd get s3://BUCKET/OBJECT LOCAL_FILE`            |
| HeadObject              | B     | Returns the metadata of an object without the object itself                                           | `s3cmd info s3://BUCKET/OBJECT`                      |
| DeleteObject            | C     | Removes one object from a bucket                                                                      | `s3cmd del s3://BUCKET/OBJECT`                       |
| DeleteObjects           | C     | Removes several objects in one request, with the keys in the XML body                                 | `s3cmd del s3://BUCKET/PREFIX --recursive`           |
| AbortMultipartUpload    | C     | Ends a multipart upload without assembling it                                                         | `s3cmd abortmp s3://BUCKET/OBJECT Id`                |
| CompleteMultipartUpload | C     | Assembles the uploaded parts into the object                                                          | Called by `s3cmd put`                                |
| CreateMultipartUpload   | C     | Starts a multipart upload and returns the `uploadId` that groups its parts                            | Called by `s3cmd put`                                |
| ListParts               | A     | Lists the parts uploaded for one multipart upload                                                     | `s3cmd listmp s3://BUCKET/OBJECT Id`                 |
| PutObject               | C     | Uploads an object                                                                                     | `s3cmd put FILE s3://BUCKET/OBJECT`                  |
| UploadPart              | C     | Uploads one part of a multipart upload                                                                | Called by `s3cmd put`                                |

`ListObjectsV2` is the listing operation to use past 1,000 objects: it sets `IsTruncated` to true and returns a `NextContinuationToken`, which the next request sends as the `continuation-token` query parameter. `ListParts` pages the same way, with `NextPartNumberMarker` and the `part-number-marker` parameter.

The six multipart operations carry one large upload in parts. `CreateMultipartUpload` opens the upload, `UploadPart` sends each part, `CompleteMultipartUpload` assembles them, and `AbortMultipartUpload` ends an upload that is not finished; `ListParts` and `ListMultipartUploads` report what is in progress. A client that splits large files calls them from its own upload command, so they are rarely called directly.

### Response status

A signed request to the endpoint returns these statuses:

| Operation     | Signed request              | Status |
| ------------- | --------------------------- | ------ |
| ListBuckets   | `GET /`                     | `200`  |
| ListObjectsV2 | `GET /<bucket>?list-type=2` | `200`  |
| PutObject     | `PUT /<bucket>/<key>`       | `200`  |
| GetObject     | `GET /<bucket>/<key>`       | `200`  |
| HeadObject    | `HEAD /<bucket>/<key>`      | `200`  |
| DeleteObject  | `DELETE /<bucket>/<key>`    | `204`  |

The two listing operations answer in XML: `ListBuckets` returns a `ListAllMyBucketsResult` document, and `ListObjectsV2` returns a `ListBucketResult` document carrying a `Key` and an `ETag` for each object.

---

## Authentication

A request to `s3.us-east-005.azionstorage.net` is signed with Signature Version 4. The signature is computed from the credential's `access_key`, its `secret_key`, and the region `us-east-005`. An S3 client signs each request once it holds the connection settings.

This is not the authentication the Azion API v4 uses. A call to `https://api.azion.com/v4/workspace/storage` carries a [personal token](/en/documentation/guides/platform/account-and-billing/personal-tokens/) in an `Authorization` header, and what the call may do comes from the account's permissions. A signed S3 request carries no token, and what it may do comes from the credential's `capabilities` and its `buckets` scope.

The two meet in one place: creating, listing, and deleting a credential are API v4 calls, so they carry the personal token. Everything the S3 endpoint answers is signed with the key pair that the create call returned.

---

## Errors

A credential request that is rejected returns the error envelope every Object Storage API response uses. For the other codes it can return, refer to [Buckets and objects](/en/documentation/platform/object-storage/buckets-and-objects/#errors).

| Code    | Title                      | Status | Cause                                                                                                                                           |
| ------- | -------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `17008` | `Not Allowed Capabilities` | 400    | The `capabilities` array carries a value outside the six the platform accepts. The `meta.allowed_capabilities` field of the response lists them |

The `listBuckets` capability changes what the endpoint answers for an object that is not in the bucket. A credential without `listBuckets` returns `403 Forbidden`; a credential with it returns `404 Not Found`, which reports the real cause.

---

## Related resources

- [Use S3-compatible tools with Object Storage](/en/documentation/guides/application-development/data/use-s3-compatible-tools-with-object-storage.md): The steps that configure a client against the endpoint on this page.
- [Buckets and objects](/en/documentation/platform/object-storage/buckets-and-objects.md): The same buckets and objects through the Azion API v4, with every field and every error.
- [How Object Storage works](/en/documentation/platform/object-storage/how-it-works.md): What an access level changes, and why it does not restrict a credential.
- [Object Storage limits](/en/documentation/platform/object-storage/limits.md): The bounds on buckets, keys, and access keys, with the usage each plan includes.
- [Connectors](/en/documentation/platform/connectors.md): The object that puts a bucket behind an application, which is how objects reach end users.
