# Files

**Page:** kit/files

[Download Raw Markdown](./kit/files.md)

---

# Files

**Every file is a URL.** Read, download, hash, and browse files across local storage and 60+ cloud providers—Google Drive, Dropbox, S3, OneDrive, and more—through one consistent HTTP interface.

Every Hoody container includes **hoody-files**, providing unified access to files wherever they live.

---

## What You Can Do

**hoody-files** transforms storage into HTTP endpoints:

- **🌐 Web File Manager** - Visual file browser with built-in code editor—main entry point for interactive file management
- **📖 Read Files** - Stream content via HTTP from any mounted storage
- **⬇️ Download Files** - With progress tracking and integrity verification
- **ℹ️ Get Metadata** - Size, type, modification time without downloading
- **🔐 Verify Hashes** - SHA256, MD5 integrity checking
- **📁 List Directories** - Browse with sorting, filtering, multiple formats
- **🔗 Mount 60+ Providers** - Google Drive, S3, Dropbox, SFTP, WebDAV, and more
- **🌐 Multiple Formats** - HTML browser, JSON API, simple text for scripts
- **📦 Archive Preview** - Inspect .tar.gz/.zip contents without extracting
- **🗜️ Quick Archive Download** - Download any directory as .zip with `?zip` parameter
- **🔄 Base64 Encoding** - Embed files in JSON or data URLs


**Related Storage Features:**
- **[Cloud Storage →](/foundation/storage/cloud/)** - Connect 60+ providers to your container
- **[Shared Storage →](/foundation/storage/sharing-files/)** - Access files across multiple containers via shared directories
- **[Mount Locally →](/foundation/storage/mount-locally/)** - Access container files from your desktop via SSHFS/WebDAV
- **[Proxy Permissions →](/foundation/proxy/permissions/)** - Control who can access files (IP whitelist, passwords, JWT)

**Cross-container file access:** Use Shared Storage to create directories accessible from multiple containers. Each container's hoody-files service can then read/write the shared directory as if it were local storage.


---

## API Endpoints Summary

**Official Technical Reference:**

For complete endpoint documentation with all parameters, responses, and examples:

**File Reading & Downloading:**
- **[GET /api/v1/files/\{path\}](/api/files/reading/)** - Read/download file content
  - Query params: `backend`, `base64`
- **[GET /\{path\}](/api/files/reading/)** - Alternative endpoint with HTML/JSON/simple formats
  - Query params: `json`, `simple`, `backend`, `content-type`
- **[HEAD /\{path\}](/api/files/metadata/)** - Get metadata without downloading
  - Returns: Content-Length, Content-Type, Last-Modified, ETag, Accept-Ranges

**File Integrity:**
- **[GET /api/v1/files/\{path\}?hash](/api/files/hashing/)** - Get SHA256 hash
- **[GET /api/v1/files/\{path\}?sha256](/api/files/hashing/)** - Alias for hash
- **[GET /\{path\}?preview](/api/files/reading/)** - Preview archive contents (tar.gz, zip)

**Archive Operations:**
- **[GET /\{path\}?zip](/api/files/directories/)** - Download directory as .zip archive
  - Recursively archives entire directory tree
  - Perfect for quick backups or file transfers

**Directory Listing:**
- **[GET /api/v1/files/\{path\}](/api/files/directories/)** - List directory as JSON
- **[GET /\{path\}?json](/api/files/directories/)** - Directory listing with metadata
- **[GET /\{path\}?simple](/api/files/directories/)** - Plain text listing for scripts
  - Query params: `sort` (name|size|mtime), `order` (asc|desc)

**Backend Management:**
- **[POST /api/v1/backends/\{type\}](/api/files/mount/cloud/)** - Mount storage backend
  - Supported: drive, dropbox, onedrive, s3, azure, gcs, b2, sftp, ftp, webdav, +50 more
- **[GET /api/v1/backends](/api/files/managing-backends/)** - List all mounted backends
- **[GET /api/v1/backends/\{id\}](/api/files/managing-backends/)** - Get backend details
- **[GET /api/v1/backends/\{id\}/test](/api/files/managing-backends/)** - Test backend connection
- **[DELETE /api/v1/backends/\{id\}](/api/files/managing-backends/)** - Disconnect backend

**System Monitoring:**
- **[GET /api/v1/files/health](/api/files/monitoring/)** - Service health status
- **[GET /api/v1/downloads](/api/files/monitoring/)** - List active downloads
- **[GET /api/v1/extractions](/api/files/monitoring/)** - List active extractions

---

## Core Capabilities

### 1. Web File Manager (Main Entry Point)

**Open the container files URL in your browser for visual file management:**

```
https://{project}-{container}-files.{server}.containers.hoody.icu
```

**Interactive web interface with:**
- 📁 **Visual folder navigation** - Click folders to browse
- 🔍 **Built-in search** - Find files quickly
- ↕️ **Sortable columns** - Sort by name, size, date
- ✏️ **Code editor** - Edit text files directly in browser with syntax highlighting
- 📤 **Upload interface** - Drag-and-drop file uploads (if permitted)
- 📥 **Download manager** - Click to download files
- 🗜️ **Archive creation** - Create .zip/.tar.gz directly
- 👁️ **File preview** - View images, PDFs, text files inline

**Perfect for:** Daily file management, quick edits, browsing cloud storage, reviewing logs, editing config files—all without leaving the browser.

**Works on any device:** Phone, tablet, laptop—same interface everywhere.

### 2. Universal File Access via API

**One API for all your storage:**

```bash
# Container files URL: https://{project}-{container}-files.{server}.containers.hoody.icu

# Local container files
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/documents/report.pdf"

# Google Drive
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/files/Work/report.pdf?backend=backend_drive_abc"

# Amazon S3
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/files/backups/data.zip?backend=backend_s3_xyz"

# Dropbox
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/files/Photos/vacation.jpg?backend=backend_dropbox_123"
```

**Same URL pattern. Different storage. No complexity.**

### 3. Mount Once, Access Forever

**Connect storage providers once:**



**Response:**
```json
{
  "id": "backend_drive_abc123",
  "type": "drive"
}
```

**Now access all Drive files:**
```bash
# List Drive root
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/?backend=backend_drive_abc123&json"

# Download Drive file
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/Documents/report.pdf?backend=backend_drive_abc123" \
  --output report.pdf
```

**Mount persists across container restarts.** Connect once, use forever.

### 4. Multiple Response Formats

**Choose format for your use case:**


  
  
  ```bash
  # Interactive file browser
  open "https://{project}-{container}-files.{server}.containers.hoody.icu/documents/"
  ```
  
  Interactive file browser with visual navigation, search, sortable columns, and upload interface (if permitted).
  
    
    
    
  
  ```bash
  # Structured data
  curl "https://{project}-{container}-files.{server}.containers.hoody.icu/documents/?json"
  ```

```json
{
  "kind": "Index",
  "paths": [
    {
      "name": "report.pdf",
      "path_type": "File",
      "size": 524288,
      "mtime": 1699564800000
    }
  ]
}
```
  
  
  
  ```bash
  # Clean text for scripts
  curl "https://{project}-{container}-files.{server}.containers.hoody.icu/images/?simple"
  ```

```
photo1.jpg
photo2.jpg
vacation/
```

One item per line. Directories end with `/`.
  


### 5. Integrity Verification

**Ensure downloads are complete and uncorrupted:**

```bash
# Container files URL
FILES_URL="https://{project}-{container}-files.{server}.containers.hoody.icu"

# 1. Get expected hash
expected=$(curl -s "$FILES_URL/api/v1/files/large-file.bin?hash")

# 2. Download file
curl "$FILES_URL/api/v1/files/large-file.bin" -o large-file.bin

# 3. Verify
actual=$(sha256sum large-file.bin | awk '{print $1}')

if [ "$expected" = "$actual" ]; then
  echo "✓ Download verified"
else
  echo "✗ Download corrupted"
fi
```

**Critical for:**
- Production deployments
- Backup verification
- Large file transfers
- Compliance requirements

### 6. Advanced Features

**Archive preview without extraction:**
```bash
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/backup.tar.gz?preview"
# Lists contents without downloading full archive
```

**Base64 encoding for embedding:**
```bash
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/config.json?base64"
# Returns: eyJrZXkiOiJ2YWx1ZSJ9
```

**Custom content types:**
```bash
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/data.txt?content-type=text/csv"
# Forces download as CSV
```

**Quick directory download as zip:**
```bash
# Download entire directory as .zip archive
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/documents/?zip" \
  -o documents.zip

# Download remote directory from cloud storage
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/Work/?zip&backend=backend_drive" \
  -o work-files.zip
```

---

## Ownership of Created Files

The file service runs as `root` inside the container, but the files and folders it
creates are **owned by your container user (`user`), not root** — so the interactive
shell and your processes can read, edit, and delete everything the file manager makes.

This applies to every operation that creates a *new* inode — uploads, new folders
(`?mkdir`), `touch`, appends to a new file, archive extraction (every extracted entry),
copies, downloads (`?download_from`), and any parent directories created along the way.
**Existing files keep their owner**: overwriting, appending to, or moving an existing
file never changes who owns it.


By default new inodes are owned by `user`. When the service is started with
`--allow-chown`, a request may set a different owner with the `owner` query parameter
(`?owner=user`, `?owner=user:group`, or `?owner=uid:gid`) on create endpoints
(upload, `?append`, `?mkdir`/dir creation, `?copy_to`, `?move_to`, `?download_from`,
`?extract`). The requested owner must be one of the operator-configured
`--allowed-create-owners` (the default owner is always allowed) and can never be
`root` (uid/gid `0`) — those requests are rejected with `400`/`403`.


**Operator configuration** (CLI flags / env on the file service):

| Flag | Env | Default | Meaning |
|------|-----|---------|---------|
| `--default-create-owner <spec>` | `HOODY_FILE_MANAGER_DEFAULT_CREATE_OWNER` | `user` | Owner for newly-created inodes. `spec` is `user`, `user:group`, `uid`, `uid:gid`, or `none`/`off` to disable (inherit the process owner = root). |
| `--allowed-create-owners <csv>` | `HOODY_FILE_MANAGER_ALLOWED_CREATE_OWNERS` | *(empty)* | Owners a client `owner=` override may request (the default owner is always allowed). Resolved per request. |

Ownership is **fail-closed**: when the feature is active the service verifies it can
change ownership at startup, and if a per-operation ownership change unexpectedly fails
the request returns `500` and the partially-created file/dir is rolled back — a created
file is never silently left owned by root.

---

## Journal & File History

**Every mutation is recorded.** Every time a file is created, written, appended, deleted, moved, copied, or has its permissions changed, the journal captures it -- along with a content-addressable blob snapshot of the file at that moment. This means you can read any file as it existed at any past revision, at any point in time, or compute diffs between any two versions.

The journal is best-effort: file operations always succeed even if journaling encounters an error. But under normal conditions, every mutation is captured, giving you a complete audit trail of your container's filesystem.

### Browse File History

See every revision of a file:


  

  ```bash
  hoody files get src/app.ts --history --limit 50
  ```

  

  

  ```typescript
  import { HoodyClient } from '@hoody-ai/hoody-sdk';

  const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: process.env.HOODY_TOKEN });
  const containerClient = await client.withContainer({ id: CONTAINER_ID, project_id: PROJECT_ID, server: SERVER });

  const history = await containerClient.files.get('src/app.ts', { history: '', limit: 50 });

  for (const rev of history.data.revisions) {
    console.log(`#${rev.seq} [${rev.op}] ${rev.ts}`);
  }
  ```

  

  

  ```bash
  curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/files/src/app.ts?history&limit=50"
  ```

  


### Read at a Past Revision or Timestamp

Retrieve the exact content of a file at any point in its history:


  

  ```bash
  # By revision number
  hoody files get src/app.ts --revision 3

  # By timestamp
  hoody files get src/app.ts --at "2026-03-19T14:30:00Z"
  ```

  

  

  ```typescript
  // By revision
  const v3 = await containerClient.files.get('src/app.ts', { revision: 3 });

  // By timestamp
  const yesterday = await containerClient.files.get('src/app.ts', { at: '2026-03-19T14:30:00Z' });
  ```

  

  

  ```bash
  # By revision
  curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/files/src/app.ts?revision=3"

  # By timestamp
  curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/files/src/app.ts?at=2026-03-19T14:30:00Z"
  ```

  


### Diff Between Versions

Compute a unified diff between any two versions of a file:


  

  ```bash
  hoody files get src/app.ts --diff --from-seq 1 --to-seq 3
  ```

  

  

  ```typescript
  const diff = await containerClient.files.get('src/app.ts', { diff: '', from_seq: 1, to_seq: 3 });
  console.log(diff);
  ```

  

  

  ```bash
  curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/files/src/app.ts?diff&from_seq=1&to_seq=3"
  ```

  


### Query the Journal & View Stats

Search across all mutations in your container and monitor journal health:


  

  ```bash
  # Query recent writes under src/
  hoody files journal query --path src/ --op write --limit 20

  # View journal storage statistics
  hoody files journal stats
  ```

  

  

  ```typescript
  // Query journal entries
  const entries = await containerClient.files.journal.query({ path: 'src/', op: 'write', limit: 20 });

  // Get journal stats
  const stats = await containerClient.files.journal.getStats();
  console.log(`${stats.data.total_entries} entries, ${stats.data.total_blobs} blobs`);
  ```

  

  

  ```bash
  # Query journal
  curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/journal?path=src/&op=write&limit=20"

  # Journal stats
  curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/journal/stats"
  ```

  



For complete API reference with all parameters, response schemas, and pagination details, see **[File Journal & History API Reference](/api/files/journal/)**.


---

## Why This Changes Everything

### Traditional File Access

```
Different tools for different storage:
- AWS CLI for S3
- Google Drive SDK  
- Dropbox API
- SFTP client
- WebDAV client

Each with different authentication, different SDKs, different patterns.
```

**Problems:**
- Multiple tools to learn
- Different APIs per provider
- Complex authentication flows
- No unified interface
- AI can't easily access (provider-specific SDKs)

### Hoody Files

```
One HTTP API for everything:
https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/files/{path}?backend={provider}
```

**Advantages:**
- ✅ One interface for 60+ providers
- ✅ Consistent authentication (mount once)
- ✅ Same HTTP patterns everywhere
- ✅ AI-native (standard HTTP requests)
- ✅ Observable (all file access logged)
- ✅ Embeddable (file browsers in iframes)
- ✅ Script-friendly (simple text format)

### Files Accessible from Anywhere

**Your phone can now access:**

```javascript
// From mobile browser
await fetch('https://{project}-{container}-files.{server}.containers.hoody.icu/documents/contract.pdf?backend=backend_drive')
  .then(r => r.blob())
  .then(blob => {
    // View PDF on phone
  });
```

**No Google Drive app needed.** No Dropbox app. No S3 client. Just HTTP.

---

## Common Workflows

### Multi-Cloud Access

**Access files from multiple providers simultaneously:**

```javascript
// List all mounted backends
const filesUrl = 'https://{project}-{container}-files.{server}.containers.hoody.icu';

const backends = await fetch(filesUrl + '/api/v1/backends').then(r => r.json());

// Access files from each
for (const backend of backends.backends) {
  const files = await fetch(filesUrl + `/?backend=${backend.id}&json`)
    .then(r => r.json());
  
  console.log(`${backend.type}: ${files.paths.length} files`);
}
```

### Verified Downloads

**Production-grade file downloads:**

```javascript
async function verifiedDownload(path, backend) {
  // 1. Get expected hash
  const hashResponse = await fetch(
    `/api/v1/files${path}?backend=${backend}&hash`
  );
  const expectedHash = await hashResponse.text();
  
  // 2. Download file
  const fileResponse = await fetch(
    `/api/v1/files${path}?backend=${backend}`
  );
  const blob = await fileResponse.blob();
  
  // 3. Verify hash (browser)
  const arrayBuffer = await blob.arrayBuffer();
  const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
  const actualHash = Array.from(new Uint8Array(hashBuffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
  
  if (actualHash === expectedHash) {
    console.log('✓ Download verified');
    return blob;
  } else {
    throw new Error('Download corrupted - hash mismatch');
  }
}
```

### Backup Verification

**Ensure all local files exist in cloud backup:**

```python
import requests

files_url = 'https://{project}-{container}-files.{server}.containers.hoody.icu'

def verify_backup(local_path, backup_backend):
    # Get local listing
    local = requests.get(f'{files_url}{local_path}?json').json()
    
    # Get backup listing
    backup = requests.get(
        f'{files_url}/api/v1/files{local_path}',
        params={'backend': backup_backend, 'json': ''}
    ).json()
    
    local_files = {p['name']: p['size'] for p in local['paths'] if p['path_type'] == 'File'}
    backup_files = {p['name']: p['size'] for p in backup['paths'] if p['path_type'] == 'File'}
    
    missing = set(local_files.keys()) - set(backup_files.keys())
    size_mismatch = [
        name for name in local_files
        if name in backup_files and local_files[name] != backup_files[name]
    ]
    
    if not missing and not size_mismatch:
        print(f'✓ Backup complete: {len(local_files)} files verified')
    else:
        print(f'✗ Missing {len(missing)} files, {len(size_mismatch)} size mismatches')
```

### AI File Analysis

**AI accesses files via HTTP:**

```javascript
// AI agent reads code file
const filesUrl = 'https://{project}-{container}-files.{server}.containers.hoody.icu';

const code = await fetch(
  filesUrl + '/app/main.js?backend=backend_drive'
).then(r => r.text());

// AI analyzes
const analysis = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [{
    role: 'user',
    content: `Review this code:\n\n${code}`
  }]
});

// AI can directly access your files from cloud storage
// No downloading to local machine needed
```

### Directory Synchronization

**Compare local vs remote, sync differences:**

```bash
#!/bin/bash

FILES_URL="https://{project}-{container}-files.{server}.containers.hoody.icu"

# Get local directory
local=$(curl -s "$FILES_URL/documents/?json")

# Get remote directory
remote=$(curl -s "$FILES_URL/api/v1/files/documents/?backend=backend_s3&json")

# Compare and download missing files
echo "$remote" | jq -r '.paths[] | select(.path_type == "File") | .name' | \
while read filename; do
  if ! echo "$local" | jq -e ".paths[] | select(.name == \"$filename\")" > /dev/null; then
    echo "Downloading: $filename"
    curl "$FILES_URL/documents/$filename?backend=backend_s3" \
      -o "documents/$filename"
  fi
done
```

---

## Use Cases

### Unified Cloud Access

**Stop installing provider-specific tools:**

```bash
# Traditional: Different CLI for each provider
aws s3 cp s3://bucket/file.pdf ./          # AWS CLI
gcloud storage cp gs://bucket/file.pdf ./  # Google CLI  
az storage blob download ...               # Azure CLI
rclone copy dropbox:file.pdf ./            # Rclone

# Hoody: One HTTP interface
FILES_URL="https://{project}-{container}-files.{server}.containers.hoody.icu"

curl "$FILES_URL/file.pdf?backend=backend_s3" -o file.pdf
curl "$FILES_URL/file.pdf?backend=backend_gcs" -o file.pdf
curl "$FILES_URL/file.pdf?backend=backend_azure" -o file.pdf
curl "$FILES_URL/file.pdf?backend=backend_dropbox" -o file.pdf
```

### Mobile File Access

**Your phone accesses ALL your storage:**

```javascript
// Phone browser
const filesUrl = 'https://{project}-{container}-files.{server}.containers.hoody.icu';

const file = await fetch(
  filesUrl + '/documents/contract.pdf?backend=backend_drive'
);
const blob = await file.blob();

// View PDF directly in mobile browser
// No app installation needed
```

**Access Google Drive, S3, Dropbox—all from mobile browser.** Because files are HTTP.

### Documentation with Live Files

**Embed file browsers in docs:**

```html
<!-- Live file browser in documentation -->
<iframe src="https://demo-files.hoody.icu/examples/?backend=backend_demo&readonly=true" 
        height="400" />
```

Users see actual files, not just descriptions.

### Backup Automation

**Verify backups via HTTP:**

```bash
#!/bin/bash
# Nightly backup verification
FILES_URL="https://{project}-{container}-files.{server}.containers.hoody.icu"

for file in $(curl -s "$FILES_URL/critical/?simple"); do
  # Get hash from local
  local_hash=$(curl -s "$FILES_URL/critical/$file?hash")
  
  # Get hash from S3 backup
  backup_hash=$(curl -s "$FILES_URL/api/v1/files/critical/$file?backend=backend_s3&hash")
  
  if [ "$local_hash" != "$backup_hash" ]; then
    echo "⚠️ Backup mismatch: $file"
    # Re-upload to S3 via other tools or trigger alert
  fi
done
```

### AI-Powered File Management

**AI organizes your files:**

```javascript
const filesUrl = 'https://{project}-{container}-files.{server}.containers.hoody.icu';

// AI agent lists files
const files = await fetch(filesUrl + '/?backend=backend_drive&json')
  .then(r => r.json());

// AI analyzes and categorizes
for (const file of files.paths) {
  if (file.path_type === 'File') {
    const content = await fetch(
      filesUrl + `/${file.name}?backend=backend_drive`
    ).then(r => r.text());
    
    // AI determines category
    const category = await ai.categorize(content);
    
    // AI can move files, create folders, organize automatically
  }
}
```

### Cross-Provider File Migration

**Move files between cloud providers:**

```javascript
// Read from Google Drive
const file = await fetch(
  '/api/v1/files/document.pdf?backend=backend_drive'
).then(r => r.blob());

// Upload to S3 (via other tools/APIs)
// Or use hoody-files to bridge providers
```

---

## Best Practices

### Mount All Storage Once

**Connect all providers at container creation:**

```javascript
const providers = [
  { type: 'drive', credentials: googleCreds },
  { type: 's3', credentials: awsCreds },
  { type: 'dropbox', credentials: dropboxCreds }
];

for (const provider of providers) {
  await fetch(`/api/v1/backends/${provider.type}`, {
    method: 'POST',
    body: JSON.stringify(provider.credentials)
  });
}

// Now all storage accessible through one interface
```

### Always Verify Critical Downloads

**For production data, system backups, or compliance:**

```bash
hash=$(curl -s "$URL?hash")
curl "$URL" -o file
echo "$hash  file" | sha256sum -c
```

### Use Appropriate Format

**Match format to use case:**

- **HTML** - Interactive browsing in browser
- **JSON** - API integration, processing
- **Simple** - Shell scripts, piping to other commands

### Cache Directory Listings

**Listings change infrequently:**

```javascript
const cache = new Map();

async function getDirectory(path, backend, ttl = 60000) {
  const key = `${path}:${backend}`;
  const cached = cache.get(key);
  
  if (cached && Date.now() - cached.time < ttl) {
    return cached.data;
  }
  
  const data = await fetch(`${path}?backend=${backend}&json`)
    .then(r => r.json());
  
  cache.set(key, { data, time: Date.now() });
  return data;
}
```

### Test Connections Before Operations

**Verify backends are healthy:**

```bash
# Test connection
curl "https://{project}-{container}-files.{server}.containers.hoody.icu/api/v1/backends/{backend_id}/test"

# Check if successful before bulk operations
```

### Handle Provider Rate Limits

**Cloud providers throttle API calls:**

```javascript
// Add delays between requests
for (const file of files) {
  await downloadFile(file);
  await new Promise(r => setTimeout(r, 100)); // 100ms delay
}

// Or use Cache backend to reduce provider API calls
```

---

## Useful Questions

### How many cloud providers can I mount simultaneously?

Unlimited. Mount Google Drive, S3, Dropbox, OneDrive, Box, and 50+ others all in one container. Each gets a unique backend ID. Access files from any provider through the same HTTP interface.

### Do mounted backends persist across container restarts?

Yes! Backend configurations are stored in the container's filesystem. After restart, all previously mounted storage is automatically reconnected. No need to re-authenticate on every restart.

### Can I mount the same provider multiple times?

Yes! Mount different Google Drive accounts, different S3 buckets, or different Dropbox folders—each as a separate backend with unique ID. Perfect for multi-tenant scenarios or managing multiple client accounts.

### What's the performance difference between local and cloud files?

Local files: sub-millisecond access. Cloud files: 50-500ms depending on provider and distance. Use Cache backend to speed up frequently accessed remote files. Or sync important files locally.

### Can AI agents access my cloud storage?

Yes! AI makes standard HTTP requests to hoody-files endpoints. It can list directories, read files, verify hashes—all via HTTP. No provider-specific SDKs needed. AI understands HTTP natively.

### Does hoody-files support file uploads?

Yes, but limited to local container storage or specific backends that support writing. Most cloud providers require OAuth scopes for write access. Check backend documentation for write capabilities.

### How do I secure file access?

Use container proxy permissions to control who can access files. Configure IP whitelist, password auth, or JWT validation. Files are private by default through cryptographic container URLs.

### Can I access files from my phone?

Absolutely! Open the hoody-files URL in your mobile browser. HTML format gives you a visual file browser. JSON format works for custom mobile apps. Your phone can now access Google Drive, S3, local container files—all through one interface.

### What happens if backend credentials expire?

File operations return 401 Unauthorized. Re-authenticate the backend with fresh credentials using `POST /api/v1/backends/{type}` with same backend configuration. The backend ID remains the same.

---

## Troubleshooting

### Backend Connection Failed

**Problem:** Cannot mount storage provider

**Solutions:**

1. **Verify credentials are correct:**
   ```bash
   # Check OAuth tokens haven't expired
   # Verify API keys are valid
   # Ensure client_id/client_secret match
   ```

2. **Check network connectivity:**



3. **Review provider documentation:**
   - Google Drive requires OAuth with drive.readonly scope
   - S3 needs correct region and credentials
   - Dropbox tokens have app-specific permissions

### File Not Found (404)

**Problem:** File exists but getting 404 response

**Check:**

1. **Path is case-sensitive:**
   ```bash
   # ❌ Wrong: /Documents/file.pdf
   # ✅ Correct: /documents/file.pdf
   ```

2. **Verify file exists:**
   ```bash
   # List parent directory
   curl "https://{project}-{container}-files.{server}.containers.hoody.icu/documents/?json"
   ```

3. **Backend ID correct:**
   ```bash
   # List all backends
   GET /api/v1/backends
   # Use correct backend_id
   ```

### Hash Verification Fails

**Problem:** Downloaded file hash doesn't match expected

**Possible causes:**

1. **Incomplete download** - Re-download with resume support
2. **File modified during download** - Re-download to get latest
3. **Network corruption** - Use TCP retransmission, verify network
4. **Wrong hash algorithm** - Ensure using SHA256

**Solution:**
```bash
# Use curl resume support
curl -C - "$URL" -o file

# Verify again
echo "$expected_hash  file" | sha256sum -c
```

### Rate Limited (429)

**Problem:** Cloud provider returning too many requests error

**Solutions:**

1. **Add delays between requests:**
   ```javascript
   for (const file of files) {
     await fetch(fileUrl);
     await new Promise(r => setTimeout(r, 200)); // 200ms delay
   }
   ```

2. **Use Cache backend:**
   ```bash
   # Mount cache in front of provider
   POST /api/v1/backends/cache
   {
     "remote": "s3_backend:bucket",
     "chunk_size": "10M"
   }
   ```

3. **Batch operations when possible** - Download multiple files in one session

### Large File Download Fails

**Problem:** Timeout or incomplete download for large files

**Solutions:**

1. **Use curl with resume support:**
   ```bash
   curl -C - "https://{project}-{container}-files.{server}.containers.hoody.icu/large-file.bin" -o large-file.bin
   ```

2. **Check disk space before downloading:**
   ```bash
   size=$(curl -sI "$URL" | grep Content-Length | awk '{print $2}')
   available=$(df -P . | tail -1 | awk '{print $4}')
   # Ensure available > size before downloading
   ```

3. **Download in chunks if supported:**
   ```bash
   # Some backends support Range requests
   curl -r 0-104857600 "$URL" > part1  # First 100MB
   curl -r 104857601- "$URL" > part2   # Rest
   cat part1 part2 > complete-file
   ```

---

## What's Next

**Explore other data services:**


  
    Serverless databases via HTTP—query, KV store, time-travel, all through HTTP.
    
    [Explore SQLite →](./sqlite/)
  
  
  
    Transform scripts into HTTP endpoints—your code becomes an API automatically.
    
    [Explore Exec →](./exec/)
  
  
  
    Complex HTTP operations simplified—transform any REST API into a simple GET request.
    
    [Explore cURL →](./curl/)
  


**Master file operations:**
- **[Quick Start →](/api/files/quick-start/)** - Mount and access in minutes
- **[Reading Files →](/api/files/reading/)** - Stream content via HTTP
- **[Downloading →](/api/files/downloading/)** - Progress tracking and verification
- **[Mounting Storage →](/api/files/mount/cloud/)** - Connect 60+ providers

---

> **Every file is a URL.**  
> **Local and cloud unified.**  
> **Access from anywhere.**  
> **One HTTP interface for everything.**

**This is how files work in the HTTP era.**