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
The PDF file to classify. Maximum file size: 50MB
JSON string containing list of classification categories (e.g., [“invoice”, “contract”, “report”])
Response
Unique identifier for the classification job
Current status of the job (“processing”)
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
Success Response
Error Response - Invalid Conditions
Error Response - File Upload Failed
{
"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
Processing Status
Completed Status
Failed Status
Job Not Found
{
"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:
Page-by-Page Analysis : Each page is analyzed using OpenAI’s Vision API
Weighted Scoring : Earlier pages receive higher weights (first page: 3x, second page: 2x, third page: 1.5x, others: 1x)
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
File Processing Errors : PDF corruption, password protection, or unreadable content
Invalid Conditions : Empty conditions list or malformed JSON
API Limits : Rate limiting or quota exceeded
Vision API Errors : OpenAI API failures or timeouts
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()
JSON string list of categories e.g. ['category1', 'category2']