> For the complete documentation index, see [llms.txt](https://docs.unitlab.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.unitlab.ai/api-sdk-cli/apis/cloud-storage-api.md).

# Cloud storage API

List approved integrations, browse provider content, and import selected paths into a Project.

Browse an existing cloud connection, import two selected images into a project, and check the resulting Batch Queue. Cloud credentials are configured in Unitlab and are never returned by these endpoints.

## Before you start

Create the connection in Workspace Settings, choose an existing project, and complete [API authentication](https://docs.unitlab.ai/api-sdk-cli/get-started/authentication-and-configuration). These examples use Bash and curl, with `UNITLAB_API_KEY` already loaded into the environment.

```bash
export UNITLAB_API_URL="https://api.unitlab.ai"
export PROJECT_ID="YOUR_PROJECT_UUID"
```

Replace `YOUR_PROJECT_UUID` with the project ID. Retrieve your connection ID:

```bash
curl --fail-with-body --silent --show-error \
  "$UNITLAB_API_URL/api/sdk/cloud-storages/" \
  -H "Authorization: Api-Key $UNITLAB_API_KEY"
```

Find the intended connection's `pk`, then set `STORAGE_ID`:

```bash
export STORAGE_ID="YOUR_STORAGE_UUID"
```

![Add Cloud Storage dialog](https://292810646-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGjVLUz4wthGkGlRKM6rM%2Fuploads%2FEceeKlJexxGEUrAINYfa%2Fcloud-storage-add.png?alt=media\&token=7f2c7aff-bb2a-476f-87cb-a8bd3a70540f)

*Create and validate the provider connection in Workspace Settings before using these endpoints.*

| Method | Endpoint                                                             | Purpose                        |
| ------ | -------------------------------------------------------------------- | ------------------------------ |
| GET    | `/api/sdk/cloud-storages/`                                           | List safe integration metadata |
| GET    | `/api/sdk/cloud-storages/{storage_id}/browse/`                       | Browse a provider prefix       |
| POST   | `/api/sdk/projects/{project_id}/cloud-storages/{storage_id}/import/` | Import selected paths          |

## Prepare the example selection

Assume the connection prefix is `datasets/` and these objects exist:

```
example-bucket/
└── datasets/
    └── incoming/
        ├── road.jpg
        ├── crossing.jpg
        └── later/
            └── tunnel.jpg
```

The example imports `road.jpg` and `crossing.jpg`. Use `incoming/` in requests because paths are relative to the connection's prefix. Do not repeat `datasets/` or send an `s3://` URL.

## Browse the directory

```bash
curl --fail-with-body --silent --show-error \
  "$UNITLAB_API_URL/api/sdk/cloud-storages/$STORAGE_ID/browse/?prefix=incoming%2F&page_size=500&project=$PROJECT_ID" \
  -H "Authorization: Api-Key $UNITLAB_API_KEY"
```

The response contains object metadata in `content` and a provider cursor in `next`. Repeat with that cursor as the URL-encoded `next_token` until empty. Each item includes `name`, `type` (`REG` or `DIR`), and applicable `size` and `is_extension_allowed` fields. `page_size` is capped at 1,000.

For this layout, expect two `REG` entries and a `DIR` entry for `incoming/later`. Browse the child directory separately to see `tunnel.jpg`.

A directory returned by browse can have a name without a trailing slash. Append `/` when selecting that directory for import. A bare prefix in browse can match names that start with that text; use a trailing slash when you intend a directory boundary.

## Import selected files or folders

Send JSON with `server_files`, a nonempty list of up to 10,000 relative file or directory paths. A directory path must end in `/`. Directory selection expands files at that level; select nested directories separately or enumerate their files. A single expanded directory is limited to 25,000 files.

| Field                     | Required | Meaning                                                                                                 |
| ------------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `server_files`            | Yes      | Relative paths returned by browse; append `/` for directory selections.                                 |
| `fps`                     | No       | Video sampling rate, at least `0.25`; defaults to `1.0`.                                                |
| `session_id`              | No       | An existing Batch Queue UUID belonging to the project. Omit to create a queue.                          |
| `generic_type`            | No       | `timeseries` or `tabular` to specify how CSV files are interpreted.                                     |
| `defer_csv_configuration` | No       | Set `true` to configure undeclared CSV files in the platform later. Ignored when `generic_type` is set. |

This JSON path list selects files already in the connected storage. It is different from uploading a JSON file containing local filenames to the media upload endpoint.

```bash
curl --fail-with-body --silent --show-error \
  -X POST "$UNITLAB_API_URL/api/sdk/projects/$PROJECT_ID/cloud-storages/$STORAGE_ID/import/" \
  -H "Authorization: Api-Key $UNITLAB_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"server_files":["incoming/"]}' \
  --output cloud-import.json
```

The server returns `202 Accepted` with `file_count`, `upload_session_id`, and a `media` list identifying imported media. The command saves this response in `cloud-import.json`. For the example selection, expect `file_count: 2`; the nested `tunnel.jpg` is not included. Preserve the response so label imports can target this import rather than older files with the same names.

## Check processing and filenames

Copy `upload_session_id` from `cloud-import.json` into `QUEUE_ID`, then poll that queue:

```bash
export QUEUE_ID="RETURNED_UPLOAD_SESSION_UUID"

curl --fail-with-body --silent --show-error \
  "$UNITLAB_API_URL/api/sdk/projects/$PROJECT_ID/upload-sessions/$QUEUE_ID/status/" \
  -H "Authorization: Api-Key $UNITLAB_API_KEY"
```

Wait until `processing` is `0`, then check `failed`. Inspect `/api/sdk/projects/{project_id}/upload-sessions/{queue_id}/data/` for item IDs and per-item results; follow all pagination links. For both valid images, expect final counts `total: 2`, `completed: 2`, `processing: 0`, and `failed: 0`. Verify `road.jpg` and `crossing.jpg` in the item results. Browse confirms the selection; the queue confirms processing. See [Project data and Batch Queues API](/api-sdk-cli/apis/project-data-and-batch-queues-api.md).

## Import labels for cloud images

Wait for the cloud media to finish processing, then use the [annotation import API](/api-sdk-cli/apis/annotations-and-workflow-api.md). Match labels to the existing project items using their IDs or unambiguous filenames. Importing label JSON does not fetch the media from URLs in that JSON.

For S3, the original objects remain in the connected bucket; preparation reads them and can write generated previews to the same storage. See [S3 permissions and storage behavior](https://docs.unitlab.ai/documentation/data/cloud-providers) before configuring the connection.

If a request times out, check the saved queue and item list before importing again. For a partial failure, correct and retry only the affected paths.

***

> **Explore related Unitlab capabilities:** [training-data curation workflows](https://unitlab.ai/en/data-curation)
