Documentation
Uploading Images
Upload images with automatic AI description generation — via Python SDK or REST API
Upload
The SDK and REST API use a single request that handles upload and AI description queueing. Supports files up to 100MB. For larger files, compress or resize before uploading.
Supported File Types
.jpg, .jpeg, .png, .webp, and .gif. Unsupported file types are automatically filtered when uploading directories.
File types are auto-detected from content — you don't need to set the correct Content-Type header. If omitted or mismatched, the API detects the actual type from the file's contents and processes it accordingly.
Quick Start
Upload a Single Image
Upload an image and get an AI-generated description
async with Scopix(api_key="scopix_...") as client: # Upload a single file - returns UploadResult directly result = await client.files.upload("photo.jpg")
print(f"Image ID: {result.image_id}") print(f"Description: {result.description}") print(f"Tags: {result.tags}") print(f"Visible Text: {result.visible_text}")Upload
Single request for files up to 100MB — use this for almost all uploads
Single and Batch
The SDK handles method selection automatically. The REST API has separate single and batch endpoints.
# Single upload — returns UploadResult directlyresult = await client.files.upload("photo.jpg")print(f"Image ID: {result.image_id}")print(f"Description: {result.description}")Batch Upload
Up to 10,000 Files (SDK)
The SDK supports uploading up to 10,000 files in a single call. Large batches are automatically chunked into 1,000-file batches. The REST API supports 10–200 files per batch request, depending on your plan tier. Total request payload must not exceed 2 GB. Individual files are limited to 100 MB (images) or 50 MB (documents).
Upload Multiple Files
# Just pass a list - server-managed concurrencyresults = await client.files.upload_batch( ["img1.jpg", "img2.jpg", "img3.jpg"])
for result in results: print(f"{result.filename}: {result.description[:50]}...")Directory Upload
SDK only — no REST equivalent
Upload Entire Directory
Pass a directory path to upload all supported images inside it
# Upload all images in a directory (recursive by default)results = await client.files.upload_batch("/path/to/photos")
print(f"Uploaded {len(results)} images")for result in results: print(f" {result.filename}: {result.description[:50]}...")Directory Options
# Non-recursive (only top-level files)results = await client.files.upload_batch( "/path/to/photos", recursive=False # Don't include subdirectories)
# Include hidden files and directoriesresults = await client.files.upload_batch( "/path/to/photos", include_hidden=True # Include .hidden files and .cache/ dirs)
# Mix files and directoriesresults = await client.files.upload_batch([ "/path/to/folder1", # All images in folder1 "/path/to/folder2", # All images in folder2 "/path/to/specific_image.jpg" # Plus this specific file])Automatic Filtering
When uploading directories, only supported image files (.jpg, .jpeg, .png, .webp, .gif) are included. Hidden files and directories (starting with .) are excluded by default. Other file types like .pdf, .txt, or .mp4 are silently skipped.
Content Categories
Specify a content category to get AI descriptions tailored to the type of content being uploaded.
Using Content Categories
from scopix import Scopix, ContentCategory
async with Scopix(api_key="scopix_...") as client: # Upload a blueprint with tailored analysis result = await client.files.upload( "blueprint.jpg", content_category=ContentCategory.BLUEPRINT ) print(result.description) # Blueprint-specific description
# Also works with string values result = await client.files.upload( "living-room.jpg", content_category="architectural_design" )Available Categories
- •
GENERAL— Default, no specialization - •
BLUEPRINT— Architectural / engineering blueprints - •
CE_PLAN— Civil engineering plans (extracts sheet type, standards, jurisdiction) - •
TECHNICAL_DIAGRAM— Technical diagrams and schematics - •
ARCHITECTURAL_DESIGN— Architectural design photos and renders (extracts style, room type, materials) - •
PRODUCT_PHOTO— Product photography - •
REAL_ESTATE— Real estate and property photos - •
MINING— Mining operations and geological surveys - •
ROBOTICS— Robotics scenes for ML dataset curation (extracts object affordances, grasp strategies, spatial relationships, perception challenges) - •
ARTWORK— Art, paintings, illustrations - •
SCREENSHOT— Screenshots and UI captures - •
DOCUMENT— Scanned documents and forms - •
MAP— Maps, diagrams, and charts (extracts legend data) - •
CONSTRUCTION— Construction sites and active building projects (extracts safety, equipment, materials, structural elements)
Progress Callbacks
SDK only
Track Upload Progress
Callbacks are silent no-ops in v2.0.0
on_progress and on_file_complete are accepted for signature compatibility but are not invoked in v2.0.0. For batched progress, poll session status via client.files.wait_for_session(session_id, on_progress=...) instead.
from scopix import Scopix
# NOTE: on_progress / on_file_complete are silent no-ops in v2.0.0.# Use client.files.wait_for_session(session_id, on_progress=...) for# batched progress tracking.
async with Scopix(api_key="scopix_...") as client: results = await client.files.upload_batch( ["img1.jpg", "img2.jpg", "img3.jpg"], ) for r in results: print(f"{r.filename}: {r.image_id}")Custom Storage (BYOB)
Upload to your own storage bucket instead of Scopix's default storage
# First, configure your storage bucket (one-time setup)await client.settings.configure_custom_s3( access_key_id="AKIAIOSFODNN7EXAMPLE", secret_access_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", bucket_name="my-company-uploads", region="us-east-1")
# Upload to your custom bucketresult = await client.files.upload_batch( "photo.jpg", storage_target="custom" # Use your configured bucket)Error Handling
Handle Upload Errors
from scopix import Scopix, DescriptionStatus
results = await client.files.upload_batch(files)
# Check status using enumfor r in results: if r.description_status == DescriptionStatus.FAILED: print(f"Failed: {r.image_id}")
# Use convenience methodsif results.has_failures: print(f"Summary: {results.summary()}") for r in results.retryable(): print(f"Can retry: {r.image_id}")UploadResult Type
Fields available on the SDK upload result
@dataclass(frozen=True)class UploadResult: # Core fields image_id: str # Unique identifier filename: str # Original filename
# AI description fields description: Optional[str] # AI-generated description tags: Optional[list[str]] # Extracted tags visible_text: Optional[str] # OCR extracted text text_regions: Optional[list[dict[str, Any]]] # Structured text regions (normalized 0-1 bboxes) confidence_score: Optional[float] # Always null for descriptions; populated for extractions/rules description_status: DescriptionStatus # PENDING | QUEUED | PROCESSING | COMPLETED | FAILED | SKIPPED
# Media fields thumbnail_url: Optional[str] created_at: Optional[datetime]
# Error fields (when description_status == DescriptionStatus.FAILED) description_error: Optional[str] description_error_type: Optional[str] description_is_retryable: Optional[bool]
# Presigned / multipart fields (None on streaming uploads) deduplicated: Optional[bool] # True if server matched an existing hash media_type: Optional[str] # 'image' | 'document' | 'video' | 'link' status: Optional[str] # 'processing' | 'completed' — upload status
# Properties @property def is_failed(self) -> bool @property def is_completed(self) -> bool @property def is_pending(self) -> bool
# Serialization def to_dict(self, exclude_none: bool = True) -> dict[str, Any]
