# Upload, download and delete objects

> Browse a bucket in the dashboard, upload and download files, create folders, and delete objects, or do the same with presigned URLs.

Source: https://www.coritan.com/docs/object-storage/objects/

In the dashboard:

- /dashboard/storage/…/buckets: https://www.coritan.com/dashboard/storage

An *object* is a file stored in a bucket under a *key*, its full name, such as `photos/2026/beach.jpg`. The **Buckets** tab has an object browser where you upload, download and delete objects. For large files, many files or whole folder trees, use an S3 client ([Connect an S3 client](/docs/object-storage/connect-an-s3-client/)).

The object browser does not use your access keys. We sign a short-lived link for each upload, download and folder, and your browser sends the data straight to storage over that link. You can use the browser before you create a key.

## Before you begin

- Sign in to the [dashboard](https://www.coritan.com/dashboard/storage) and open the service.
- The bucket must exist ([Create a bucket](/docs/object-storage/buckets/#create-a-bucket)).
- To upload, create folders or delete objects, the service must be `active`. You can browse and download in any status.

## Open a bucket

1. Open the service and select the **Buckets** tab.
2. Select the bucket's name, or **Browse objects** in its menu.

The header shows the bucket's name, its address to copy, and the number of objects and their size from the last hourly measurement. The refresh button beside it lists the folder again.

S3 has no real folders. The browser treats the part of a key before each `/` as a *folder*, so `photos/beach.jpg` shows as `beach.jpg` inside the folder `photos`. The list shows folders first, then objects with their **Size** and the time they were **Modified**.

- Select a folder to open it. The path above the list starts at **Buckets** and ends at the folder you are in. Select any part of it to go back up. The folder is part of the page address, so the back button and bookmarks work.
- To find objects, type the start of their name in the search box, which reads `Keys starting with…`. The list narrows to the keys in the current folder that start with what you typed.
- The list shows 200 entries at a time. Select **Load more** for the next 200.

## Upload files

1. Open the folder you want the files in.
2. Select **Upload…** and choose one or more files. You can also drag files from your computer and drop them on the list.
3. Follow each upload in the **Transfers** panel at the bottom right of the page. Select **Cancel** to stop an upload that is running, or **Dismiss** to clear one that has ended.

Each file becomes an object whose key is the folder path and the file name, such as `photos/beach.jpg`.

> [!WARNING]
> An upload replaces an object that has the same key, without asking. We keep no earlier version of it.

The browser sends each file in a single request, and it cannot upload a folder with its contents. For a folder tree, or a file of several gigabytes, use an S3 client: `aws s3 sync` and `rclone copy` upload whole folders and send large files in parts.

## Create a folder

1. Open the folder to create the new folder in.
2. Select **New folder…**.
3. Type a name in **Folder name**, such as `photos`, and select **Create folder**.

A message confirms `Folder created.` The browser writes an empty object named after the folder with a `/` at the end, such as `photos/`, so the folder shows before it holds anything. A `/` inside the name creates a folder within a folder, such as `2026/09`. We remove a `/` at the start or the end of the name, and a backslash is refused.

Folders also appear on their own. When an S3 client uploads `photos/beach.jpg`, the browser shows a `photos` folder even though nobody created it.

## Download an object

Select the object's name, or **Download** in its menu. Your browser saves the file under the last part of its key, such as `beach.jpg`.

The object browser downloads one object at a time. To download a folder or many objects, use an S3 client, for example `aws --profile coritan s3 cp s3://u7-assets/photos/ ./photos/ --recursive`.

## Delete objects and folders

> [!CAUTION]
> Deleting an object destroys it at once. There is no undo, and we keep no earlier version to restore.

To delete one object:

1. Open the object's menu and select **Delete object…**.
2. Select **Delete object** to confirm.

To delete several objects, or a folder with everything in it:

1. Tick the box beside each object or folder. The box in the heading selects every entry in the list. For one folder, you can also select **Delete folder…** in its menu.
2. Select the button that gives the number of entries, such as `Delete 3 items…`.
3. Type `delete` and confirm.

The **Transfers** panel follows the deletion. A message then says what was deleted, such as `1,284 objects deleted.` Deleting a folder deletes every object under it, including its folders.

The browser deletes up to 10,000 objects under each folder in one run. When a folder holds more, the message `A folder had more than the browser deletes at once; run the delete again for the rest.` appears. Repeat the delete until the folder is gone. An S3 client deletes a large folder in one command, such as `aws --profile coritan s3 rm s3://u7-assets/photos/ --recursive`.

## Share a file with a presigned URL

A *presigned URL* is a link that carries its own signature. It lets anyone who has it download, upload or delete one object, whichever it was signed for, without an access key. It works as many times as they like until it expires. The dashboard has no button for it. Create one through the API ([Presign an object](#presign-an-object)), or with an S3 client and one of your keys:

```bash
aws --profile coritan s3 presign s3://u7-assets/reports/2026-09.pdf --expires-in 3600
```

A link from the API lasts 15 minutes unless you ask for longer, and 1 hour at most. We sign it ourselves, so revoking an access key does not affect it. A link from an S3 client is signed with your key, so it stops working when it expires or when you revoke that key.

## Result

The browser shows each change as soon as it finishes. The object count and size in the header, on the **Buckets** tab and on the **Overview** tab follow at the next hourly measurement.

## Troubleshooting

`Could not reach the storage gateway`
: Your browser could not connect to the region's endpoint on port 7337. A firewall, proxy or VPN on your network may block that port. Try another network, or ask whoever runs yours to allow outgoing HTTPS on port 7337.

`Could not upload beach.jpg` with `The upload link expired or was refused`
: Storage refused the upload. Reload the page and upload the file again. If it keeps happening, [contact support](/docs/support/conversations/).

`Could not upload beach.jpg` with `Upload failed` and a number
: Storage answered the upload with that HTTP status. Upload the file again. For a large file, use an S3 client, which sends it in parts.

`Could not prepare the download`
: We could not sign the download link. The message beside it gives the reason. Try again.

`Bucket not found`
: The bucket was deleted, or the address belongs to another service. Select **All buckets** to go back to the list.

`Could not delete 2 objects.`
: Storage refused some of the deletions. The rest went through. Run the delete again.

**Upload…** and **New folder…** are missing
: The service is not `active`, so you cannot change its objects. You can still browse and download.

A folder is still there after you deleted everything in it
: The folder has an empty folder object, written by **New folder…** or by a client. Delete the folder itself with **Delete folder…**.

The size in the header did not change
: We measure each bucket once an hour. The header shows the last measurement.

## Related

- [Create and delete buckets](/docs/object-storage/buckets/)
- [Connect an S3 client](/docs/object-storage/connect-an-s3-client/)
- [Object Storage limits](/docs/object-storage/limits/)
- [Troubleshoot Object Storage](/docs/object-storage/troubleshooting/)

## With the API

Each request takes the service ID and the bucket's `id` from [List buckets](/docs/object-storage/buckets/#list-buckets). A bucket that is not on the service answers `404` with `Bucket not found`.

### List objects

[`GET /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/objects`](/docs/api/reference/client/object-storage/#op-get-api-v1-client-object-storage-service-id-buckets-bucket-id-objects) lists one page of a bucket. It takes these query parameters:

`prefix`
: Lists only keys that start with it, up to 1024 characters. Give a folder with its `/`, such as `photos/`.

`max_keys`
: How many entries a page holds, from 1 to 1000. The default is 200.

`token`
: The `next_token` of the previous page, to read the next one.

`flat`
: `true` lists every key under the prefix, with no folders. The default, `false`, groups keys into folders at each `/`.

```bash
curl "https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/objects?prefix=photos/&max_keys=100" \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

```json
{
  "items": [
    {"key": "photos/2026/", "size": null, "last_modified": null, "etag": null, "is_prefix": true},
    {"key": "photos/beach.jpg", "size": 2483027, "last_modified": "2026-09-20T14:02:11+00:00", "etag": "9b2cf535f27731c974343645a3985328", "is_prefix": false}
  ],
  "prefix": "photos/",
  "next_token": null
}
```

Each page lists its folders first, with `is_prefix` set to `true` and no size. `size` is in bytes. `next_token` is `null` on the last page.

### Presign an object

[`POST /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/objects/presign`](/docs/api/reference/client/object-storage/#op-post-api-v1-client-object-storage-service-id-buckets-bucket-id-objects-presign) returns a presigned URL for one object. The body takes:

`key`
: Required. The object's key, up to 1024 bytes. A key that ends in `/` works only with `put`, which is how the browser creates a folder.

`op`
: Required. `get` to download, `put` to upload, or `delete` to delete.

`expires`
: How long the link lasts, in seconds, from 60 to 86400. We shorten anything above 3600 to 3600. The default is 900.

`content_type`
: For `put`, the object's content type, such as `application/pdf`, up to 255 characters.

`download`
: For `get`, `true` makes browsers save the file under the last part of its key instead of opening it.

```bash
curl -X POST https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/objects/presign \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"key": "reports/2026-09.pdf", "op": "get", "expires": 3600, "download": true}'
```

```json
{
  "url": "https://s3.fra.coritan.com:7337/u7-assets/reports/2026-09.pdf?response-content-disposition=attachment%3B%20filename%3D%222026-09.pdf%22&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Date=20260926T100000Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=...",
  "method": "GET",
  "headers": {},
  "expires_in": 3600,
  "expires_at": "2026-09-26T11:00:00+00:00"
}
```

Send a request with `method` to `url` before `expires_at`, with every header in `headers`. `expires_in` is the lifetime you got, after any shortening. To upload, ask for `put` and send the file as the request body:

```bash
curl -X PUT --upload-file 2026-09.pdf \
  -H "Content-Type: application/pdf" \
  "https://s3.fra.coritan.com:7337/u7-assets/reports/2026-09.pdf?X-Amz-Algorithm=..."
```

When you send `content_type`, `headers` holds `Content-Type` with that value, and the upload must carry it unchanged.

The errors: `400` `An object key is required` for an empty key or a key that ends in `/` with `get` or `delete`, and `400` `Object keys are at most 1024 bytes`.

### Delete objects

[`DELETE /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/objects`](/docs/api/reference/client/object-storage/#op-delete-api-v1-client-object-storage-service-id-buckets-bucket-id-objects) deletes up to 1000 objects by key. It does not expand folders, so list the keys under a folder with `flat=true` first.

```bash
curl -X DELETE https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/objects \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keys": ["photos/beach.jpg", "photos/2026/"]}'
```

```json
{"deleted": 2, "errors": []}
```

`deleted` counts the keys that storage did not refuse, including keys that did not exist. `errors` lists each refused key with its `key`, `code` and `message`.

## API

- `GET /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/objects`: One page of the bucket under prefix, folders first (https://www.coritan.com/docs/api/reference/client/object-storage/#op-get-api-v1-client-object-storage-service-id-buckets-bucket-id-objects)
- `DELETE /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/objects`: Delete named objects (https://www.coritan.com/docs/api/reference/client/object-storage/#op-delete-api-v1-client-object-storage-service-id-buckets-bucket-id-objects)
- `POST /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/objects/presign`: A short-lived URL the browser uses directly for one GET, PUT or DELETE (https://www.coritan.com/docs/api/reference/client/object-storage/#op-post-api-v1-client-object-storage-service-id-buckets-bucket-id-objects-presign)
