> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scoutos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Drive API Reference: Upload, Download, and Manage Files

> Full API reference for Scout Drive. Upload files, download by path, list folder contents, create folders, and delete files using REST endpoints or the SDK.

Scout Drive exposes a REST API for all file and folder operations. Every endpoint requires authentication and returns consistent JSON responses. This reference covers each endpoint in full — parameters, response shapes, curl examples, and SDK equivalents — so you can integrate Drive into any application or automate file management in your agents and workflows.

## Authentication

All Drive API endpoints require a Bearer token in the `Authorization` header:

```text theme={null}
Authorization: Bearer YOUR_API_KEY
```

You can generate and manage API keys under **Settings → API Keys** in the Scout dashboard.

## Base URL

```text theme={null}
https://api.scoutos.com
```

## Rate Limits

| Endpoint                | Limit                   |
| ----------------------- | ----------------------- |
| `POST /drive/upload`    | 100 requests per minute |
| `GET /drive/download`   | 500 requests per minute |
| `GET /drive/list`       | 300 requests per minute |
| `POST /drive/folders`   | 100 requests per minute |
| `DELETE /drive/folders` | 50 requests per minute  |

When you exceed a rate limit, the API returns `429 Too Many Requests`. Check the `Retry-After` response header for the number of seconds to wait before retrying.

## Endpoint Summary

| Action               | Method   | Endpoint          |
| -------------------- | -------- | ----------------- |
| Upload files         | `POST`   | `/drive/upload`   |
| Download a file      | `GET`    | `/drive/download` |
| List folder contents | `GET`    | `/drive/list`     |
| Create a folder      | `POST`   | `/drive/folders`  |
| Delete a folder      | `DELETE` | `/drive/folders`  |

***

## POST /drive/upload

Upload one or more files to Drive. Each file can be placed at a specific path using the `metadata` array.

### Request

```text theme={null}
POST https://api.scoutos.com/drive/upload
Content-Type: multipart/form-data
Authorization: Bearer YOUR_API_KEY
```

### Parameters

<ParamField body="files" type="file[]" required>
  One or more files sent as multipart form data fields. Each file corresponds by index to an entry in the `metadata` array.
</ParamField>

<ParamField body="metadata" type="JSON string">
  A JSON array of metadata objects, one per file, controlling where each file is stored. If omitted, files are stored at the root using their original filenames.
</ParamField>

### Metadata Object Fields

<ParamField body="path" type="string">
  Fully qualified destination path, for example `/reports/2024/q1.pdf`. Takes the highest priority when resolving the file location.
</ParamField>

<ParamField body="folder" type="string">
  Destination folder path, for example `/reports/2024`. Combined with `name` if both are provided.
</ParamField>

<ParamField body="name" type="string">
  Destination filename, for example `q1-report.pdf`. Combined with `folder` if provided, otherwise stored at the root.
</ParamField>

### Path Resolution Priority

For each file at index `i`, the destination path is resolved in this order:

| Priority | Condition                  | Result                                     |
| -------- | -------------------------- | ------------------------------------------ |
| 1        | `path` is set              | Use `path` as the fully qualified location |
| 2        | `folder` + `name` both set | `{folder}/{name}`                          |
| 3        | `folder` only              | `{folder}/{original_filename}`             |
| 4        | `name` only                | `/{name}` (root)                           |
| 5        | Neither set                | `/{original_filename}` (root)              |

### Response

`200 OK`

```json theme={null}
{
  "data": [
    {
      "id": "file_abc123",
      "name": "q1-report.pdf",
      "path": "/reports/2024/q1-report.pdf",
      "url": "https://cdn.scoutos.com/files/file_abc123",
      "size": 204800,
      "created_at": "2024-01-15T10:30:00Z"
    }
  ]
}
```

<ResponseField name="data[].id" type="string">
  Unique identifier for the uploaded file.
</ResponseField>

<ResponseField name="data[].name" type="string">
  Stored filename.
</ResponseField>

<ResponseField name="data[].path" type="string">
  Full path where the file was stored in Drive.
</ResponseField>

<ResponseField name="data[].url" type="string">
  Direct URL to access the file content.
</ResponseField>

<ResponseField name="data[].size" type="integer">
  File size in bytes.
</ResponseField>

<ResponseField name="data[].created_at" type="string">
  ISO 8601 timestamp of when the file was created.
</ResponseField>

### Examples

<CodeGroup>
  ```bash cURL theme={null}
  # Simple upload — stored at root with original filename
  curl -X POST https://api.scoutos.com/drive/upload \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -F "files=@report.pdf"

  # Upload to a specific folder
  curl -X POST https://api.scoutos.com/drive/upload \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -F "files=@report.pdf" \
    -F 'metadata=[{"folder": "/reports/2024"}]'

  # Upload to a specific path
  curl -X POST https://api.scoutos.com/drive/upload \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -F "files=@report.pdf" \
    -F 'metadata=[{"path": "/reports/2024/q1-summary.pdf"}]'

  # Upload multiple files to different locations
  curl -X POST https://api.scoutos.com/drive/upload \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -F "files=@report.pdf" \
    -F "files=@data.csv" \
    -F 'metadata=[{"path": "/reports/2024/q1-report.pdf"}, {"folder": "/data/exports", "name": "sales-data.csv"}]'
  ```

  ```python Python theme={null}
  from scoutos import Scout

  client = Scout(api_key="YOUR_API_KEY")

  # Simple upload — stored at root with original filename
  result = client.drive.upload(files=["report.pdf"])

  # Upload to a specific folder
  result = client.drive.upload(
      files=["report.pdf"],
      metadata=[{"folder": "/reports/2024"}]
  )

  # Upload to a specific path
  result = client.drive.upload(
      files=["report.pdf"],
      metadata=[{"path": "/reports/2024/q1-summary.pdf"}]
  )

  # Upload multiple files to different locations
  result = client.drive.upload(
      files=["report.pdf", "data.csv", "notes.txt"],
      metadata=[
          {"path": "/reports/2024/q1-report.pdf"},
          {"folder": "/data/exports", "name": "sales-data.csv"},
          {"folder": "/notes"}
      ]
  )

  print(result["data"][0]["path"])  # /reports/2024/q1-report.pdf
  ```

  ```typescript TypeScript theme={null}
  import { ScoutClient } from "scoutos";
  import * as fs from "fs";

  const client = new ScoutClient({ apiKey: "YOUR_API_KEY" });

  // Simple upload — stored at root with original filename
  const result = await client.drive.upload({
    files: [fs.createReadStream("report.pdf")]
  });

  // Upload to a specific folder
  const folderResult = await client.drive.upload({
    files: [fs.createReadStream("report.pdf")],
    metadata: [{ folder: "/reports/2024" }]
  });

  // Upload to a specific path
  const pathResult = await client.drive.upload({
    files: [fs.createReadStream("report.pdf")],
    metadata: [{ path: "/reports/2024/q1-summary.pdf" }]
  });

  console.log(pathResult.data[0].path); // /reports/2024/q1-summary.pdf
  ```
</CodeGroup>

***

## GET /drive/download

Download a single file from Drive. Returns the raw file content as a binary stream.

### Request

```text theme={null}
GET https://api.scoutos.com/drive/download
Authorization: Bearer YOUR_API_KEY
```

### Query Parameters

<ParamField query="path" type="string">
  Fully qualified file path, for example `/reports/report.pdf`. Use this **or** `name` + `folder` — not both.
</ParamField>

<ParamField query="name" type="string">
  Filename to retrieve, for example `report.pdf`. Must be used together with `folder`.
</ParamField>

<ParamField query="folder" type="string">
  Folder to search within, for example `/reports`. Must be used together with `name`.
</ParamField>

<Note>
  Provide either `path` alone, or both `name` and `folder` together. The request returns `400 Bad Request` if neither combination is supplied.
</Note>

### Response

`200 OK` — Returns the file content as a binary stream. Response headers include:

```text theme={null}
Content-Type: application/pdf
Content-Disposition: attachment; filename="report.pdf"
```

### Examples

<CodeGroup>
  ```bash cURL theme={null}
  # Download by full path
  curl -X GET "https://api.scoutos.com/drive/download?path=/reports/2024/q1-report.pdf" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    --output q1-report.pdf

  # Download by folder + name
  curl -X GET "https://api.scoutos.com/drive/download?name=q1-report.pdf&folder=/reports/2024" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    --output q1-report.pdf
  ```

  ```python Python theme={null}
  from scoutos import Scout

  client = Scout(api_key="YOUR_API_KEY")

  # Download by full path
  content = client.drive.download(path="/reports/2024/q1-report.pdf")
  with open("q1-report.pdf", "wb") as f:
      f.write(content)

  # Download by folder + name
  content = client.drive.download(
      name="q1-report.pdf",
      folder="/reports/2024"
  )
  with open("q1-report.pdf", "wb") as f:
      f.write(content)
  ```

  ```typescript TypeScript theme={null}
  import { ScoutClient } from "scoutos";
  import * as fs from "fs";

  const client = new ScoutClient({ apiKey: "YOUR_API_KEY" });

  // Download by full path
  const content = await client.drive.download({
    path: "/reports/2024/q1-report.pdf"
  });
  fs.writeFileSync("q1-report.pdf", Buffer.from(content));

  // Download by folder + name
  const contentByName = await client.drive.download({
    name: "q1-report.pdf",
    folder: "/reports/2024"
  });
  fs.writeFileSync("q1-report.pdf", Buffer.from(contentByName));
  ```
</CodeGroup>

***

## GET /drive/list

List the files and subfolders within a Drive folder. Defaults to the root folder if no `folder` is specified.

### Request

```text theme={null}
GET https://api.scoutos.com/drive/list
Authorization: Bearer YOUR_API_KEY
```

### Query Parameters

<ParamField query="folder" default="/" type="string">
  Folder path to list, for example `/reports`. Defaults to root (`/`) if omitted.
</ParamField>

<ParamField query="recursive" default="false" type="boolean">
  When `true`, returns all nested files and folders at every depth within the target folder.
</ParamField>

### Response

`200 OK`

```json theme={null}
{
  "data": {
    "folder": "/reports",
    "files": [
      {
        "id": "file_abc123",
        "name": "q1-report.pdf",
        "path": "/reports/q1-report.pdf",
        "size": 102400,
        "created_at": "2024-01-15T10:30:00Z"
      }
    ],
    "folders": [
      {
        "id": "folder_xyz789",
        "name": "2024",
        "path": "/reports/2024"
      }
    ]
  }
}
```

<ResponseField name="data.folder" type="string">
  The folder path that was listed.
</ResponseField>

<ResponseField name="data.files" type="array">
  Files directly inside the folder. Includes all nested files when `recursive: true`.
</ResponseField>

<ResponseField name="data.files[].id" type="string">
  Unique file identifier.
</ResponseField>

<ResponseField name="data.files[].name" type="string">
  Filename.
</ResponseField>

<ResponseField name="data.files[].path" type="string">
  Full path to the file in Drive.
</ResponseField>

<ResponseField name="data.files[].size" type="integer">
  File size in bytes.
</ResponseField>

<ResponseField name="data.files[].created_at" type="string">
  ISO 8601 creation timestamp.
</ResponseField>

<ResponseField name="data.folders" type="array">
  Immediate subfolders within the listed folder.
</ResponseField>

<ResponseField name="data.folders[].id" type="string">
  Unique folder identifier.
</ResponseField>

<ResponseField name="data.folders[].name" type="string">
  Folder name.
</ResponseField>

<ResponseField name="data.folders[].path" type="string">
  Full folder path in Drive.
</ResponseField>

### Examples

<CodeGroup>
  ```bash cURL theme={null}
  # List root folder
  curl -X GET "https://api.scoutos.com/drive/list" \
    -H "Authorization: Bearer YOUR_API_KEY"

  # List a specific folder
  curl -X GET "https://api.scoutos.com/drive/list?folder=/reports" \
    -H "Authorization: Bearer YOUR_API_KEY"

  # List recursively
  curl -X GET "https://api.scoutos.com/drive/list?folder=/reports&recursive=true" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```python Python theme={null}
  from scoutos import Scout

  client = Scout(api_key="YOUR_API_KEY")

  # List root folder
  contents = client.drive.list()

  # List a specific folder
  contents = client.drive.list(folder="/reports")

  # List all files recursively
  contents = client.drive.list(folder="/reports", recursive=True)

  for file in contents["data"]["files"]:
      print(f"{file['path']}  ({file['size']} bytes)")
  ```

  ```typescript TypeScript theme={null}
  import { ScoutClient } from "scoutos";

  const client = new ScoutClient({ apiKey: "YOUR_API_KEY" });

  // List a specific folder
  const contents = await client.drive.list({ folder: "/reports" });

  // List recursively
  const allFiles = await client.drive.list({
    folder: "/reports",
    recursive: true
  });

  for (const file of allFiles.data.files) {
    console.log(`${file.path}  (${file.size} bytes)`);
  }
  ```
</CodeGroup>

***

## POST /drive/folders

Create a new folder in Drive. Intermediate parent folders are created automatically if they do not already exist.

### Request

```text theme={null}
POST https://api.scoutos.com/drive/folders
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
```

### Request Body

<ParamField body="path" type="string" required>
  Full path for the new folder, for example `/reports/2024/q1`. Intermediate folders are created automatically.
</ParamField>

### Response

`200 OK`

```json theme={null}
{
  "data": {
    "id": "folder_abc123",
    "path": "/reports/2024",
    "created_at": "2024-01-15T10:30:00Z"
  }
}
```

<ResponseField name="data.id" type="string">
  Unique identifier for the created folder.
</ResponseField>

<ResponseField name="data.path" type="string">
  Full path of the created folder.
</ResponseField>

<ResponseField name="data.created_at" type="string">
  ISO 8601 creation timestamp.
</ResponseField>

### Examples

<CodeGroup>
  ```bash cURL theme={null}
  # Create a folder
  curl -X POST https://api.scoutos.com/drive/folders \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"path": "/reports/2024"}'

  # Create nested folders — intermediate paths are created automatically
  curl -X POST https://api.scoutos.com/drive/folders \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"path": "/projects/research/analysis"}'
  ```

  ```python Python theme={null}
  from scoutos import Scout

  client = Scout(api_key="YOUR_API_KEY")

  # Create a single folder
  result = client.drive.create_folder(path="/reports/2024")
  print(result["data"]["id"])  # folder_abc123

  # Create nested folders — intermediate paths are created automatically
  result = client.drive.create_folder(path="/projects/research/analysis")
  ```

  ```typescript TypeScript theme={null}
  import { ScoutClient } from "scoutos";

  const client = new ScoutClient({ apiKey: "YOUR_API_KEY" });

  // Create a folder
  const result = await client.drive.createFolder({ path: "/reports/2024" });
  console.log(result.data.id); // folder_abc123

  // Nested folders are created automatically
  const nested = await client.drive.createFolder({
    path: "/projects/research/analysis"
  });
  ```
</CodeGroup>

***

## DELETE /drive/folders

Delete a folder from Drive. By default, deletion fails if the folder contains files or subfolders. Set `recursive: true` to force deletion of all contents.

<Warning>
  Deletion is permanent. Files and folders removed with this endpoint cannot be recovered. Use the archive pattern — move files to `/archive/...` — if you want to preserve history.
</Warning>

### Request

```text theme={null}
DELETE https://api.scoutos.com/drive/folders
Authorization: Bearer YOUR_API_KEY
```

### Query Parameters

<ParamField query="path" type="string" required>
  Full path of the folder to delete, for example `/reports/archived`.
</ParamField>

<ParamField query="recursive" default="false" type="boolean">
  When `true`, deletes all files and subfolders within the target folder. When `false` and the folder is non-empty, the request returns `409 Conflict`.
</ParamField>

### Response

`200 OK`

```json theme={null}
{
  "data": {
    "deleted": true,
    "path": "/reports/archived",
    "files_deleted": 5
  }
}
```

<ResponseField name="data.deleted" type="boolean">
  `true` if deletion succeeded.
</ResponseField>

<ResponseField name="data.path" type="string">
  Path of the deleted folder.
</ResponseField>

<ResponseField name="data.files_deleted" type="integer">
  Number of files deleted, including files in subfolders when `recursive: true`.
</ResponseField>

### Examples

<CodeGroup>
  ```bash cURL theme={null}
  # Delete an empty folder
  curl -X DELETE "https://api.scoutos.com/drive/folders?path=/reports/archived" \
    -H "Authorization: Bearer YOUR_API_KEY"

  # Delete a folder and all its contents
  curl -X DELETE "https://api.scoutos.com/drive/folders?path=/reports/old&recursive=true" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```python Python theme={null}
  from scoutos import Scout

  client = Scout(api_key="YOUR_API_KEY")

  # Delete an empty folder
  result = client.drive.delete_folder(path="/reports/archived")

  # Delete a folder and all its contents
  result = client.drive.delete_folder(path="/reports/old", recursive=True)
  print(result["data"]["files_deleted"])  # e.g. 12
  ```

  ```typescript TypeScript theme={null}
  import { ScoutClient } from "scoutos";

  const client = new ScoutClient({ apiKey: "YOUR_API_KEY" });

  // Delete an empty folder
  const result = await client.drive.deleteFolder({ path: "/reports/archived" });

  // Delete a folder and all its contents
  const recursive = await client.drive.deleteFolder({
    path: "/reports/old",
    recursive: true
  });
  console.log(recursive.data.files_deleted); // e.g. 12
  ```
</CodeGroup>

***

## Error Handling

All Drive API errors follow a consistent JSON structure:

```json theme={null}
{
  "error": {
    "code": "not_found",
    "message": "No file found at path /reports/missing.pdf"
  }
}
```

### HTTP Status Codes

| Status | Code               | Description                                                                     |
| ------ | ------------------ | ------------------------------------------------------------------------------- |
| `200`  | —                  | Request succeeded                                                               |
| `400`  | `bad_request`      | Malformed request — missing required fields or invalid JSON                     |
| `401`  | `unauthorized`     | Missing or invalid API key                                                      |
| `404`  | `not_found`        | The specified file or folder does not exist                                     |
| `409`  | `conflict`         | Attempted to delete a non-empty folder without `recursive: true`                |
| `422`  | `validation_error` | Request parameters failed validation; `message` describes the invalid parameter |
| `429`  | `rate_limited`     | Too many requests; check `Retry-After` header                                   |
| `500`  | `internal_error`   | Unexpected server error; contact Scout support if it persists                   |

### Common Error Scenarios

**Missing required parameter (422)**

```json theme={null}
{
  "error": {
    "code": "validation_error",
    "message": "Parameter 'path' is required for folder deletion"
  }
}
```

**File not found (404)**

```json theme={null}
{
  "error": {
    "code": "not_found",
    "message": "No file found at path /reports/missing.pdf"
  }
}
```

**Non-empty folder without recursive flag (409)**

```json theme={null}
{
  "error": {
    "code": "conflict",
    "message": "Folder /reports/2024 is not empty. Set recursive=true to delete its contents."
  }
}
```

**Rate limit exceeded (429)**

```json theme={null}
{
  "error": {
    "code": "rate_limited",
    "message": "Upload rate limit exceeded. Retry after 15 seconds."
  }
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Drive Overview" icon="hard-drive" href="/drive/overview">
    Learn how Drive works, common use cases, and how to give agents file access.
  </Card>

  <Card title="Databases Overview" icon="layer-group" href="/databases/overview">
    Use Databases for structured data and semantic search across your agent's knowledge base.
  </Card>
</CardGroup>
