TutorialCollect User Context

File Upload & Management

The Synvo API provides comprehensive file and directory management capabilities. All file operations support various formats including documents, images, videos, and web pages.

Authentication

All endpoints require authentication via:

  • API Key: X-API-Key: <api_key>

Base URL

https://api.synvo.ai

Create Directory

Creates a virtual directory in Azure Blob Storage by uploading a .keep marker file.

Endpoint: POST /file/create_dir

Content-Type: application/x-www-form-urlencoded

Parameters

ParameterTypeRequiredDescription
pathstringYesDirectory path (e.g., "/", "/docs")

Example Request

curl -X POST "https://api.synvo.ai/file/create_dir" \
  -H "X-API-Key: ${API-KEY}" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "path=/docs"
import requests

api_key = "<API_KEY>"
url = "https://api.synvo.ai/file/create_dir"
data = {"path": "/docs"}
headers = {"X-API-Key": api_key}

response = requests.post(url, data=data, headers=headers, timeout=30)
response.raise_for_status()
print(response.json())
const api_key = "<API_KEY>";
const params = new URLSearchParams({ path: "/docs" });

const response = await fetch("https://api.synvo.ai/file/create_dir", {
  method: "POST",
  headers: {
    "X-API-Key": apiKey,
  },
  body: params,
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

console.log(await response.json());

Example Response

{
  "message": "Directory created successfully at /docs"
}

Response Codes

  • 200 - Directory exists or created
  • 400 - Bad request
  • 401 - Unauthorized

List Directory Contents

Lists files and directories at a given path, optionally recursive with version tracking.

Endpoint: GET /file/list

Query Parameters

ParameterTypeDefaultDescription
pathstring"/"Directory path
recursivebooleantrueInclude nested items and return tree structure
versionstring-Optional file version to check if refresh is needed

Example Request

curl -X GET "https://api.synvo.ai/file/list?path=/project&recursive=true" \
  -H "X-API-Key: ${API-KEY}"
import requests

api_key = "<API_KEY>"
url = "https://api.synvo.ai/file/list"
params = {"path": "/project", "recursive": True}
headers = {"X-API-Key": api_key}

response = requests.get(url, params=params, headers=headers, timeout=30)
response.raise_for_status()
print(response.json())
const api_key = "<API_KEY>";
const params = new URLSearchParams({
  path: "/project",
  recursive: "true"
});

const response = await fetch(`https://api.synvo.ai/file/list?${params}`, {
  method: "GET",
  headers: {
    "X-API-Key": apiKey,
  },
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

console.log(await response.json());

Example Response

{
  "items": [
    {
      "is_dir": false,
      "name": "document.pdf",
      "path": "/project/document.pdf",
      "file_id": "abc123xyz",
      "size": 1024000,
      "status": "COMPLETED",
      "created_at": "2024-01-15T10:30:00Z"
    }
  ],
  "tree": {
    "/project": {
      "document.pdf": {
        "file_id": "abc123xyz",
        "is_dir": false
      }
    }
  },
  "version": "v1.2.3",
  "need_refresh_file": false
}

Response Codes

  • 200 - Directory listing
  • 400 - Bad request
  • 401 - Unauthorized
  • 404 - Directory not found

Upload File

Uploads a file to the specified path, builds memory index if requested, and stores in Azure Blob Storage.

Endpoint: POST /file/upload

Content-Type: multipart/form-data

Parameters

ParameterTypeRequiredDefaultDescription
filebinaryYes-File to upload
pathstringNo"/"Upload path

Example Request

curl -X POST "https://api.synvo.ai/file/upload" \
  -H "X-API-Key: ${API-KEY}" \
  -F "file=@/path/to/document.pdf" \
  -F "path=/"
import requests

api_key = "<API_KEY>"
url = "https://api.synvo.ai/file/upload"
headers = {"X-API-Key": api_key}

with open("/path/to/document.pdf", "rb") as f:
    files = {"file": f}
    data = {
        "path": "/",
    }
    response = requests.post(url, files=files, data=data, headers=headers, timeout=60)

response.raise_for_status()
print(response.json())
const api_key = "<API_KEY>";
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];

const formData = new FormData();
formData.append("file", file);
formData.append("path", "/");

const response = await fetch("https://api.synvo.ai/file/upload", {
  method: "POST",
  headers: {
    "X-API-Key": apiKey,
  },
  body: formData,
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

console.log(await response.json());

Example Response

{
  "filename": "document.pdf",
  "path": "/",
  "renamed": false,
  "file_id": "abc123xyz",
  "timestamp": "2024-01-15T10:30:00Z"
}

Response Codes

  • 200 - Upload accepted
  • 400 - Bad request
  • 401 - Unauthorized

Download File

Returns a signed URL for downloading the file from Azure Blob Storage.

Endpoint: GET /file/download

Query Parameters

ParameterTypeRequiredDescription
file_idstringYesFile identifier

Example Request

curl -X GET "https://api.synvo.ai/file/download?file_id=abc123xyz" \
  -H "X-API-Key: ${API-KEY}"
import requests

api_key = "<API_KEY>"
file_id = "abc123xyz"
url = "https://api.synvo.ai/file/download"
params = {"file_id": file_id}
headers = {"X-API-Key": api_key}

response = requests.get(url, params=params, headers=headers, timeout=30)
response.raise_for_status()

# Get the signed URL and download the file
data = response.json()
download_url = data["url"]
file_response = requests.get(download_url, timeout=60)

with open(data["name"], "wb") as f:
    f.write(file_response.content)
const api_key = "<API_KEY>";
const fileId = "abc123xyz";

const response = await fetch(`https://api.synvo.ai/file/download?file_id=${fileId}`, {
  method: "GET",
  headers: {
    "X-API-Key": apiKey,
  },
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const data = await response.json();
console.log("Download URL:", data.url);

// Open the download URL in a new window
window.open(data.url, "_blank");

Example Response

{
  "url": "https://storage.azure.com/signed-url-here",
  "name": "document.pdf",
  "file_type": "application/pdf",
  "file_id": "abc123xyz"
}

Response Codes

  • 200 - File download information
  • 401 - Unauthorized
  • 404 - File not found

Delete File

Deletes a file or directory and removes it from the vector database.

Endpoint: DELETE /file/delete/{file_id}

Path Parameters

ParameterTypeRequiredDescription
file_idstringYesFile identifier

Example Request

curl -X DELETE "https://api.synvo.ai/file/delete/abc123xyz" \
  -H "X-API-Key: ${API-KEY}"
import requests

api_key = "<API_KEY>"
file_id = "abc123xyz"
url = f"https://api.synvo.ai/file/delete/{file_id}"
headers = {"X-API-Key": api_key}

response = requests.delete(url, headers=headers, timeout=30)
response.raise_for_status()
print(response.json())
const api_key = "<API_KEY>";
const fileId = "abc123xyz";

const response = await fetch(`https://api.synvo.ai/file/delete/${fileId}`, {
  method: "DELETE",
  headers: {
    "X-API-Key": apiKey,
  },
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

console.log(await response.json());

Example Response

{
  "message": "File deleted successfully"
}

Response Codes

  • 200 - Deleted
  • 401 - Unauthorized
  • 404 - File not found

Move/Rename File

Moves a file or directory to a new location and updates all database references.

Endpoint: POST /file/move

Content-Type: application/x-www-form-urlencoded

Parameters

ParameterTypeRequiredDescription
srcstringYesSource path (e.g., "/project/report.pdf")
deststringYesDestination path (e.g., "/archive/report.pdf")

Example Request

curl -X POST "https://api.synvo.ai/file/move" \
  -H "X-API-Key: ${API-KEY}" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "src=/project/report.pdf" \
  --data-urlencode "dest=/archive/report.pdf"
import requests

api_key = "<API_KEY>"
url = "https://api.synvo.ai/file/move"
data = {
    "src": "/project/report.pdf",
    "dest": "/archive/report.pdf"
}
headers = {"X-API-Key": api_key}

response = requests.post(url, data=data, headers=headers, timeout=30)
response.raise_for_status()
print(response.json())
const api_key = "<API_KEY>";
const params = new URLSearchParams({
  src: "/project/report.pdf",
  dest: "/archive/report.pdf"
});

const response = await fetch("https://api.synvo.ai/file/move", {
  method: "POST",
  headers: {
    "X-API-Key": apiKey,
  },
  body: params,
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

console.log(await response.json());

Example Response

{
  "message": "File moved successfully",
  "file_moves": [
    ["/project/report.pdf", "/archive/report.pdf"]
  ]
}

Response Codes

  • 200 - Successfully moved
  • 401 - Unauthorized
  • 404 - Source not found
  • 409 - Destination already exists

Get File Thumbnail

Returns a thumbnail image for supported file types (images, PDFs, videos).

Endpoint: GET /file/thumbnail

Query Parameters

ParameterTypeDefaultDescription
file_idstring-File identifier
max_sizeinteger200Maximum thumbnail size (width or height)

Example Request

curl -X GET "https://api.synvo.ai/file/thumbnail?file_id=abc123xyz&max_size=200" \
  -H "X-API-Key: ${API-KEY}" \
  -o thumbnail.jpg
import requests

api_key = "<API_KEY>"
file_id = "abc123xyz"
url = "https://api.synvo.ai/file/thumbnail"
params = {"file_id": file_id, "max_size": 200}
headers = {"X-API-Key": api_key}

response = requests.get(url, params=params, headers=headers, timeout=30)
response.raise_for_status()

with open("thumbnail.jpg", "wb") as f:
    f.write(response.content)
const api_key = "<API_KEY>";
const fileId = "abc123xyz";
const params = new URLSearchParams({
  file_id: fileId,
  max_size: "200"
});

const response = await fetch(`https://api.synvo.ai/file/thumbnail?${params}`, {
  method: "GET",
  headers: {
    "X-API-Key": apiKey,
  },
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);

// Display thumbnail in an img element
const img = document.createElement("img");
img.src = imageUrl;
document.body.appendChild(img);

Response Codes

  • 200 - Thumbnail image (binary data)
  • 401 - Unauthorized
  • 404 - File not found

Get File Processing Status

Returns the current processing status of a file (PENDING, COMPLETED, FAILED).

Endpoint: GET /file/status/{file_id}

Path Parameters

ParameterTypeRequiredDescription
file_idstringYesFile identifier

Example Request

curl -X GET "https://api.synvo.ai/file/status/abc123xyz" \
  -H "X-API-Key: ${API-KEY}"
import requests

api_key = "<API_KEY>"
file_id = "abc123xyz"
url = f"https://api.synvo.ai/file/status/{file_id}"
headers = {"X-API-Key": api_key}

response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
print(response.json())
const apiKey = "<API_KEY>";
const fileId = "abc123xyz";

const response = await fetch(`https://api.synvo.ai/file/status/${fileId}`, {
  method: "GET",
  headers: {
    "X-API-Key": apiKey,
  },
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

console.log(await response.json());

Example Response

{
  "file_id": "abc123xyz",
  "status": "COMPLETED"
}

Status Values

  • PENDING - File is being processed
  • COMPLETED - File processing completed successfully
  • FAILED - File processing failed
  • UNKNOWN - Status cannot be determined

Response Codes

  • 200 - File status
  • 401 - Unauthorized

Verify Upload Completion

After uploading files, it's critical to verify that all files have been processed before querying them. Here's how to check the processing status:

import requests
import time

api_key = "<API_KEY>"
BASE_URL = "https://api.synvo.ai"

# Assume we have file_ids from previous uploads
# file_ids = {"document.pdf": "file_abc123", "report.docx": "file_def456"}

# Wait for all files to complete processing
print("\n⏳ Waiting for all files to process...")
for filename, file_id in file_ids.items():
    while True:
        status_response = requests.get(
            f"{BASE_URL}/file/status/{file_id}",
            headers={"X-API-Key": api_key}
        )
        status = status_response.json()["status"]
        
        if status == "COMPLETED":
            print(f"✅ {filename} processing complete!")
            break
        elif status == "FAILED":
            print(f"❌ {filename} processing failed!")
            break
        
        # Wait 5 seconds before checking again
        time.sleep(5)

print("\n🎉 All files ready for querying!")
print("\nFile IDs:")
for filename, file_id in file_ids.items():
    print(f"  {filename}: {file_id}")
const apiKey = "<API_KEY>";
const BASE_URL = "https://api.synvo.ai";

// Assume we have fileIds from previous uploads
// const fileIds = {"document.pdf": "file_abc123", "report.docx": "file_def456"}

// Wait for all files to complete processing
console.log("\n⏳ Waiting for all files to process...");

async function waitForFileProcessing(filename, fileId) {
  while (true) {
    const statusResponse = await fetch(
      `${BASE_URL}/file/status/${fileId}`,
      {
        headers: { "X-API-Key": apiKey }
      }
    );
    
    const data = await statusResponse.json();
    const status = data.status;
    
    if (status === "COMPLETED") {
      console.log(`✅ ${filename} processing complete!`);
      break;
    } else if (status === "FAILED") {
      console.log(`❌ ${filename} processing failed!`);
      break;
    }
    
    // Wait 5 seconds before checking again
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
}

// Process all files
for (const [filename, fileId] of Object.entries(fileIds)) {
  await waitForFileProcessing(filename, fileId);
}

console.log("\n🎉 All files ready for querying!");
console.log("\nFile IDs:");
for (const [filename, fileId] of Object.entries(fileIds)) {
  console.log(`  ${filename}: ${fileId}`);
}

Complete Upload Workflow with Status Verification

Here's a complete example that uploads multiple files and waits for processing to complete:

import requests
import time
from pathlib import Path

api_key = "<API_KEY>"
BASE_URL = "https://api.synvo.ai"

# List of files to upload
files_to_upload = [
    {"path": "/documents", "file": "/local/path/report.pdf"},
    {"path": "/documents", "file": "/local/path/summary.docx"},
    {"path": "/images", "file": "/local/path/chart.png"},
]

# Step 1: Upload all files
print("📤 Uploading files...")
file_ids = {}

for item in files_to_upload:
    file_path = item["file"]
    upload_path = item["path"]
    filename = Path(file_path).name
    
    try:
        with open(file_path, "rb") as f:
            files = {"file": f}
            data = {"path": upload_path}
            
            response = requests.post(
                f"{BASE_URL}/file/upload",
                files=files,
                data=data,
                headers={"X-API-Key": api_key},
                timeout=60
            )
            response.raise_for_status()
            result = response.json()
            
            file_id = result.get("file_id")
            file_ids[filename] = file_id
            print(f"✓ Uploaded: {filename} (ID: {file_id})")
            
            time.sleep(0.5)  # Rate limiting
            
    except Exception as e:
        print(f"✗ Failed to upload {filename}: {e}")

# Step 2: Wait for all files to complete processing
print("\n⏳ Waiting for all files to process...")
for filename, file_id in file_ids.items():
    max_retries = 60  # Maximum 5 minutes (60 * 5 seconds)
    retries = 0
    
    while retries < max_retries:
        try:
            status_response = requests.get(
                f"{BASE_URL}/file/status/{file_id}",
                headers={"X-API-Key": api_key},
                timeout=10
            )
            status_response.raise_for_status()
            status = status_response.json()["status"]
            
            if status == "COMPLETED":
                print(f"✅ {filename} - Processing complete!")
                break
            elif status == "FAILED":
                print(f"❌ {filename} - Processing failed!")
                break
            
            retries += 1
            time.sleep(5)
            
        except Exception as e:
            print(f"⚠️  Error checking status for {filename}: {e}")
            retries += 1
            time.sleep(5)
    
    if retries >= max_retries:
        print(f"⏱️  {filename} - Timeout waiting for processing")

# Step 3: Summary
print("\n🎉 Batch upload complete!")
print("\nProcessed File IDs:")
for filename, file_id in file_ids.items():
    print(f"  {filename}: {file_id}")
const apiKey = "<API_KEY>";
const BASE_URL = "https://api.synvo.ai";

// List of files to upload (assumes File objects from file input)
const filesToUpload = [
  { path: "/documents", file: documentFile },
  { path: "/documents", file: summaryFile },
  { path: "/images", file: chartFile },
];

async function batchUploadWithVerification() {
  // Step 1: Upload all files
  console.log("📤 Uploading files...");
  const fileIds = {};

  for (const item of filesToUpload) {
    const file = item.file;
    const uploadPath = item.path;
    const filename = file.name;
    
    try {
      const formData = new FormData();
      formData.append("file", file);
      formData.append("path", uploadPath);

      const response = await fetch(`${BASE_URL}/file/upload`, {
        method: "POST",
        headers: { "X-API-Key": apiKey },
        body: formData,
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }

      const result = await response.json();
      const fileId = result.file_id;
      fileIds[filename] = fileId;
      console.log(`✓ Uploaded: ${filename} (ID: ${fileId})`);

      await new Promise(resolve => setTimeout(resolve, 500)); // Rate limiting
    } catch (error) {
      console.log(`✗ Failed to upload ${filename}: ${error.message}`);
    }
  }

  // Step 2: Wait for all files to complete processing
  console.log("\n⏳ Waiting for all files to process...");
  
  for (const [filename, fileId] of Object.entries(fileIds)) {
    const maxRetries = 60; // Maximum 5 minutes (60 * 5 seconds)
    let retries = 0;

    while (retries < maxRetries) {
      try {
        const statusResponse = await fetch(
          `${BASE_URL}/file/status/${fileId}`,
          { headers: { "X-API-Key": apiKey } }
        );

        if (!statusResponse.ok) {
          throw new Error(`HTTP ${statusResponse.status}`);
        }

        const data = await statusResponse.json();
        const status = data.status;

        if (status === "COMPLETED") {
          console.log(`✅ ${filename} - Processing complete!`);
          break;
        } else if (status === "FAILED") {
          console.log(`❌ ${filename} - Processing failed!`);
          break;
        }

        retries++;
        await new Promise(resolve => setTimeout(resolve, 5000));
      } catch (error) {
        console.log(`⚠️  Error checking status for ${filename}: ${error.message}`);
        retries++;
        await new Promise(resolve => setTimeout(resolve, 5000));
      }
    }

    if (retries >= maxRetries) {
      console.log(`⏱️  ${filename} - Timeout waiting for processing`);
    }
  }

  // Step 3: Summary
  console.log("\n🎉 Batch upload complete!");
  console.log("\nProcessed File IDs:");
  for (const [filename, fileId] of Object.entries(fileIds)) {
    console.log(`  ${filename}: ${fileId}`);
  }
}

// Execute batch operation
batchUploadWithVerification();

Best Practices for File Upload

  • Status Verification: Always check file processing status before querying
  • Timeout Protection: Set maximum wait times to prevent infinite loops
  • Error Handling: Properly handle upload failures and processing errors
  • Rate Limiting: Add delays between uploads to avoid rate limits
  • Progress Tracking: Log upload and processing progress for monitoring

Error Handling

All endpoints return standard HTTP status codes. Error responses include a JSON object with error details:

{
  "error": "Error description",
  "code": "ERROR_CODE"
}

Common error codes:

  • 400 - Bad Request: Invalid parameters or malformed request
  • 401 - Unauthorized: Missing or invalid authentication
  • 404 - Not Found: Resource does not exist
  • 409 - Conflict: Resource already exists or operation conflicts
  • 500 - Internal Server Error: Server-side error