POST
/
classify
curl -X POST "https://prod.visionapi.unsiloed.ai/classify" \
  -H "api-key: your-api-key" \
  -H "Content-Type: multipart/form-data" \
  -F "pdf_file=@document.pdf" \
  -F "conditions=[\"invoice\", \"contract\", \"report\", \"letter\"]"
{
  "job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
  "status": "processing",
  "message": "Classification started"
}

Overview

The Classify Document endpoint analyzes PDF documents and assigns them to predefined categories based on their content, structure, and visual characteristics. This endpoint uses job-based processing where files are uploaded to cloud storage and processed asynchronously.
The endpoint supports both single-page and multi-page classification with detailed confidence scoring for each page. Files are uploaded to Supabase storage and processed in the background.

Request

pdf_file
file
required
The PDF file to classify. Maximum file size: 50MB
conditions
string
required
JSON string containing list of classification categories (e.g., [“invoice”, “contract”, “report”])

Response

job_id
string
Unique identifier for the classification job
status
string
Current status of the job (“processing”)
message
string
Human-readable status message

Request Examples

curl -X POST "https://prod.visionapi.unsiloed.ai/classify" \
  -H "api-key: your-api-key" \
  -H "Content-Type: multipart/form-data" \
  -F "pdf_file=@document.pdf" \
  -F "conditions=[\"invoice\", \"contract\", \"report\", \"letter\"]"

Response Examples

{
  "job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
  "status": "processing",
  "message": "Classification started"
}

Job Status Checking

After starting a classification job, you can check its status using the job ID.

Status Endpoint

Status Request Examples

curl -X GET "https://prod.visionapi.unsiloed.ai/classify/47c536aa-9fab-48ca-b27c-2fd74d30490a" \
  -H "api-key: your-api-key" \
  -H "Content-Type: application/json"

Status Response Examples

{
  "job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
  "status": "processing",
  "progress": "Processing page 1 of 2",
  "error": null,
  "result": null
}

Job Status Values

  • processing: Job is currently being processed
  • completed: Job completed successfully with results available
  • failed: Job failed with error details

Polling Strategy

For long-running classification jobs, implement polling with exponential backoff:
import time
import asyncio

async def poll_classification_status(job_id, max_wait_time=300):
    """Poll classification job status with exponential backoff"""
    
    base_delay = 1  # Start with 1 second
    max_delay = 30  # Maximum delay between polls
    current_delay = base_delay
    total_wait_time = 0
    
    while total_wait_time < max_wait_time:
        try:
            response = requests.get(
                f"https://prod.visionapi.unsiloed.ai/classify/{job_id}",
                headers={"api-key": "your-api-key", "Content-Type": "application/json"}
            )
            
            if response.status_code == 200:
                result = response.json()
                
                if result['status'] == 'completed':
                    return result['result']
                elif result['status'] == 'failed':
                    raise Exception(f"Classification failed: {result.get('error', 'Unknown error')}")
                else:
                    print(f"Status: {result['status']}, Progress: {result.get('progress', 'N/A')}")
            
            # Wait before next poll
            await asyncio.sleep(current_delay)
            total_wait_time += current_delay
            
            # Exponential backoff
            current_delay = min(current_delay * 2, max_delay)
            
        except Exception as e:
            print(f"Error polling status: {e}")
            await asyncio.sleep(current_delay)
            total_wait_time += current_delay
    
    raise Exception("Classification job timed out")

Classification Logic

Multi-Page Processing

The classification system processes each page individually and then determines the overall document classification using weighted scoring:
  1. Page-by-Page Analysis: Each page is analyzed using OpenAI’s Vision API
  2. Weighted Scoring: Earlier pages receive higher weights (first page: 3x, second page: 2x, third page: 1.5x, others: 1x)
  3. Confidence Aggregation: Final confidence is calculated based on consistency across pages and individual page confidence scores

Confidence Calculation

  • High Confidence (0.8-1.0): Strong match with clear visual and textual indicators
  • Medium Confidence (0.5-0.8): Good match but with some ambiguity
  • Low Confidence (0.3-0.5): Weak match, may require human review
  • Very Low Confidence (0.0-0.3): Poor match, likely incorrect classification

Advanced Usage

Custom Categories with Descriptions

For better accuracy, provide detailed category descriptions:
conditions = [
    "invoice - Business invoices with itemized charges, payment terms, and vendor information",
    "contract - Legal agreements including terms of service, NDAs, and binding documents",
    "report - Analytical reports, financial statements, and data presentations",
    "letter - Correspondence, memos, and communication documents"
]

Batch Processing

Process multiple documents efficiently:
import asyncio
import aiohttp

async def classify_documents(file_paths, conditions):
    """Classify multiple documents concurrently"""
    
    async def classify_single(session, file_path):
        data = aiohttp.FormData()
        data.add_field('pdf_file', open(file_path, 'rb'), filename=file_path)
        data.add_field('conditions', json.dumps(conditions))
        
        async with session.post(
            'https://prod.visionapi.unsiloed.ai/classify',
            headers={'api-key': 'your-api-key'},
            data=data
        ) as response:
            return await response.json()
    
    async with aiohttp.ClientSession() as session:
        tasks = [classify_single(session, path) for path in file_paths]
        results = await asyncio.gather(*tasks)
        return results

# Usage
file_paths = ['doc1.pdf', 'doc2.pdf', 'doc3.pdf']
conditions = ['invoice', 'contract', 'report']
results = asyncio.run(classify_documents(file_paths, conditions))

Error Handling

Common Error Scenarios

  1. File Processing Errors: PDF corruption, password protection, or unreadable content
  2. Invalid Conditions: Empty conditions list or malformed JSON
  3. API Limits: Rate limiting or quota exceeded
  4. Vision API Errors: OpenAI API failures or timeouts
  5. Storage Errors: File upload failures to Supabase storage

Retry Logic

Implement retry logic for robust processing:
import time
import random

async def classify_with_retry(pdf_path, conditions, max_retries=3):
    """Classify document with exponential backoff retry"""
    
    for attempt in range(max_retries + 1):
        try:
            files = {"pdf_file": open(pdf_path, "rb")}
            data = {"conditions": json.dumps(conditions)}
            
            response = requests.post(
                "https://prod.visionapi.unsiloed.ai/classify",
                headers={"api-key": "your-api-key"},
                files=files,
                data=data
            )
            
            if response.status_code == 202:
                result = response.json()
                job_id = result["job_id"]
                
                # Poll for completion
                return await poll_classification_status(job_id)
            else:
                response.raise_for_status()
                
        except Exception as e:
            if attempt < max_retries:
                # Exponential backoff with jitter
                wait_time = (2 ** attempt) + random.uniform(0, 1)
                time.sleep(wait_time)
                continue
            else:
                raise e
        finally:
            if 'files' in locals():
                files["pdf_file"].close()

Authorizations

api-key
string
header
required

Body

multipart/form-data

Response

202 - application/json

Accepted - job started

The response is of type object.