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"
import requests
job_id = "47c536aa-9fab-48ca-b27c-2fd74d30490a"
url = f"https://prod.visionapi.unsiloed.ai/classify/{job_id}"
headers = {
"api-key": "your-api-key",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
result = response.json()
print(f"Job ID: {result['job_id']}")
print(f"Status: {result['status']}")
print(f"Progress: {result.get('progress', 'N/A')}")
if result['status'] == 'completed':
classification_result = result['result']
print(f"Classification: {classification_result['classification']}")
print(f"Confidence: {classification_result['confidence']:.2f}")
print(f"Total pages: {classification_result['total_pages']}")
# Page-by-page results
for page_result in classification_result['page_results']:
print(f"Page {page_result['page']}: {page_result['classification']} (confidence: {page_result['confidence']:.2f})")
elif result['status'] == 'failed':
print(f"Error: {result.get('error', 'Unknown error')}")
else:
print("Job is still processing...")
else:
print("Error:", response.status_code, response.text)
const jobId = '47c536aa-9fab-48ca-b27c-2fd74d30490a';
const response = await fetch(`https://prod.visionapi.unsiloed.ai/classify/${jobId}`, {
method: 'GET',
headers: {
'api-key': 'your-api-key',
'Content-Type': 'application/json'
}
});
if (response.ok) {
const result = await response.json();
console.log('Job ID:', result.job_id);
console.log('Status:', result.status);
console.log('Progress:', result.progress || 'N/A');
if (result.status === 'completed') {
const classificationResult = result.result;
console.log('Classification:', classificationResult.classification);
console.log('Confidence:', classificationResult.confidence);
console.log('Total pages:', classificationResult.total_pages);
// Display page-by-page results
classificationResult.page_results.forEach(pageResult => {
console.log(`Page ${pageResult.page}: ${pageResult.classification} (${pageResult.confidence.toFixed(2)})`);
});
} else if (result.status === 'failed') {
console.error('Error:', result.error || 'Unknown error');
} else {
console.log('Job is still processing...');
}
} else {
console.error('Request failed:', response.status, await response.text());
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "processing",
"progress": "Starting classification...",
"error": null,
"result": null
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "completed",
"progress": "Classification completed",
"error": null,
"result": {
"success": true,
"classification": "invoice",
"confidence": 0.9999996871837232,
"categories": [
{"category": "invoice", "pages": [1], "page_count": 1, "confidence": 0.9999996871837232}
],
"page_results": [
{
"page": 1,
"success": true,
"confidence": 0.9999996871837232,
"raw_result": "invoice",
"classification": "invoice"
}
],
"total_pages": 1,
"processed_pages": 1
}
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "completed",
"progress": "Classification completed",
"error": null,
"result": {
"success": true,
"classification": "contract",
"confidence": 0.89,
"categories": [
{"category": "contract", "pages": [1, 2], "page_count": 2, "confidence": 0.89}
],
"page_results": [
{
"page": 1,
"success": true,
"confidence": 0.92,
"raw_result": "contract",
"classification": "contract"
},
{
"page": 2,
"success": true,
"confidence": 0.86,
"raw_result": "contract",
"classification": "contract"
}
],
"total_pages": 2,
"processed_pages": 2
}
}
// 3 pages classify as academic_paper, 1 as presentation_slide.
// Top-level classification: "academic_paper" (most pages).
// Top-level confidence: 0.96 = mean of the 3 academic_paper page confidences.
// (NOT the fraction of pages agreeing; NOT 3/4.)
// categories[] surfaces both categories present — use it for mixed documents
// instead of relying on `classification` alone.
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "completed",
"progress": "Classification completed",
"error": null,
"result": {
"success": true,
"classification": "academic_paper",
"confidence": 0.96,
"categories": [
{"category": "academic_paper", "pages": [1, 2, 3], "page_count": 3, "confidence": 0.96},
{"category": "presentation_slide", "pages": [4], "page_count": 1, "confidence": 0.91}
],
"page_results": [
{"page": 1, "success": true, "confidence": 0.98, "raw_result": "academic_paper", "classification": "academic_paper"},
{"page": 2, "success": true, "confidence": 0.96, "raw_result": "academic_paper", "classification": "academic_paper"},
{"page": 3, "success": true, "confidence": 0.94, "raw_result": "academic_paper", "classification": "academic_paper"},
{"page": 4, "success": true, "confidence": 0.91, "raw_result": "presentation_slide", "classification": "presentation_slide"}
],
"total_pages": 4,
"processed_pages": 4
}
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "failed",
"progress": "Classification failed",
"error": "This PDF could not be opened — the file may be corrupt or in an unsupported format.",
"result": null
}
{
"detail": "Job not found"
}
Classification
Get Classification Result
Check the status and progress of classification jobs and retrieve results
GET
/
classify
/
{job_id}
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"
import requests
job_id = "47c536aa-9fab-48ca-b27c-2fd74d30490a"
url = f"https://prod.visionapi.unsiloed.ai/classify/{job_id}"
headers = {
"api-key": "your-api-key",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
result = response.json()
print(f"Job ID: {result['job_id']}")
print(f"Status: {result['status']}")
print(f"Progress: {result.get('progress', 'N/A')}")
if result['status'] == 'completed':
classification_result = result['result']
print(f"Classification: {classification_result['classification']}")
print(f"Confidence: {classification_result['confidence']:.2f}")
print(f"Total pages: {classification_result['total_pages']}")
# Page-by-page results
for page_result in classification_result['page_results']:
print(f"Page {page_result['page']}: {page_result['classification']} (confidence: {page_result['confidence']:.2f})")
elif result['status'] == 'failed':
print(f"Error: {result.get('error', 'Unknown error')}")
else:
print("Job is still processing...")
else:
print("Error:", response.status_code, response.text)
const jobId = '47c536aa-9fab-48ca-b27c-2fd74d30490a';
const response = await fetch(`https://prod.visionapi.unsiloed.ai/classify/${jobId}`, {
method: 'GET',
headers: {
'api-key': 'your-api-key',
'Content-Type': 'application/json'
}
});
if (response.ok) {
const result = await response.json();
console.log('Job ID:', result.job_id);
console.log('Status:', result.status);
console.log('Progress:', result.progress || 'N/A');
if (result.status === 'completed') {
const classificationResult = result.result;
console.log('Classification:', classificationResult.classification);
console.log('Confidence:', classificationResult.confidence);
console.log('Total pages:', classificationResult.total_pages);
// Display page-by-page results
classificationResult.page_results.forEach(pageResult => {
console.log(`Page ${pageResult.page}: ${pageResult.classification} (${pageResult.confidence.toFixed(2)})`);
});
} else if (result.status === 'failed') {
console.error('Error:', result.error || 'Unknown error');
} else {
console.log('Job is still processing...');
}
} else {
console.error('Request failed:', response.status, await response.text());
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "processing",
"progress": "Starting classification...",
"error": null,
"result": null
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "completed",
"progress": "Classification completed",
"error": null,
"result": {
"success": true,
"classification": "invoice",
"confidence": 0.9999996871837232,
"categories": [
{"category": "invoice", "pages": [1], "page_count": 1, "confidence": 0.9999996871837232}
],
"page_results": [
{
"page": 1,
"success": true,
"confidence": 0.9999996871837232,
"raw_result": "invoice",
"classification": "invoice"
}
],
"total_pages": 1,
"processed_pages": 1
}
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "completed",
"progress": "Classification completed",
"error": null,
"result": {
"success": true,
"classification": "contract",
"confidence": 0.89,
"categories": [
{"category": "contract", "pages": [1, 2], "page_count": 2, "confidence": 0.89}
],
"page_results": [
{
"page": 1,
"success": true,
"confidence": 0.92,
"raw_result": "contract",
"classification": "contract"
},
{
"page": 2,
"success": true,
"confidence": 0.86,
"raw_result": "contract",
"classification": "contract"
}
],
"total_pages": 2,
"processed_pages": 2
}
}
// 3 pages classify as academic_paper, 1 as presentation_slide.
// Top-level classification: "academic_paper" (most pages).
// Top-level confidence: 0.96 = mean of the 3 academic_paper page confidences.
// (NOT the fraction of pages agreeing; NOT 3/4.)
// categories[] surfaces both categories present — use it for mixed documents
// instead of relying on `classification` alone.
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "completed",
"progress": "Classification completed",
"error": null,
"result": {
"success": true,
"classification": "academic_paper",
"confidence": 0.96,
"categories": [
{"category": "academic_paper", "pages": [1, 2, 3], "page_count": 3, "confidence": 0.96},
{"category": "presentation_slide", "pages": [4], "page_count": 1, "confidence": 0.91}
],
"page_results": [
{"page": 1, "success": true, "confidence": 0.98, "raw_result": "academic_paper", "classification": "academic_paper"},
{"page": 2, "success": true, "confidence": 0.96, "raw_result": "academic_paper", "classification": "academic_paper"},
{"page": 3, "success": true, "confidence": 0.94, "raw_result": "academic_paper", "classification": "academic_paper"},
{"page": 4, "success": true, "confidence": 0.91, "raw_result": "presentation_slide", "classification": "presentation_slide"}
],
"total_pages": 4,
"processed_pages": 4
}
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "failed",
"progress": "Classification failed",
"error": "This PDF could not be opened — the file may be corrupt or in an unsupported format.",
"result": null
}
{
"detail": "Job not found"
}
Overview
The Get Classification Job Status endpoint allows you to check the current status of classification jobs and retrieve the final results once processing is complete. Classification jobs process documents asynchronously, uploading files to cloud storage and analyzing them in the background.Status checks are lightweight and can be polled frequently to monitor progress.
Path Parameters
string
required
The unique identifier of the classification job
Response
string
Unique identifier for the classification job
string
Current job status: “queued” while the job waits to be picked up, “processing” while it runs, then “completed” or “failed”
string
Human-readable progress message describing current processing stage
string
Error message (if job failed, otherwise null)
object
Classification results (only present when status is “completed”)
Show result_structure
Show result_structure
boolean
Whether the classification operation succeeded
string
Dominant document-level classification. For single-page inputs this is the page’s category. For multi-page inputs it is the category that appears on the most pages; ties are broken by mean per-page confidence. Pages whose individual confidence is below the internal threshold are ignored when picking the dominant category. For mixed-category documents, read
categories[] to see every category present rather than relying on classification alone.number
Confidence of the dominant classification (0.0–1.0). For single-page inputs this matches the page’s confidence. For multi-page inputs it is the mean confidence of the pages that voted for
classification — not the fraction of pages that agreed, and not a document-wide certainty score. A document where 3 pages classify as academic_paper at ~0.96 each yields confidence ≈ 0.96, regardless of how the remaining pages classified. For per-page confidence, read page_results[].confidence; for the full multi-category breakdown, read categories[].array
Every category present in the document, sorted by prominence (page count, then mean confidence). Use this — not
classification — when you need the full picture of a mixed-category document.Show category_structure
Show category_structure
string
The category label (one of the inputs from
categories in the request).array
Page numbers (1-indexed, ascending) where this category was the per-page classification with confidence above the threshold.
number
Length of
pages — how many pages voted for this category.number
Mean per-page confidence across
pages for this category (0.0–1.0).number
Number of pages classified. At most 4: documents longer than 4 pages are classified from their first 4 pages.
number
Number of pages attempted (equals total_pages, at most 4); per-page success is reported in page_results
For image inputs the result has neither
page_results nor categories; it carries classification, confidence, and raw_result at the top level with total_pages: 1. When an individual PDF page fails, its page_results entry has success: false, an error message, no raw_result, and the classification defaults to the first category.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"
import requests
job_id = "47c536aa-9fab-48ca-b27c-2fd74d30490a"
url = f"https://prod.visionapi.unsiloed.ai/classify/{job_id}"
headers = {
"api-key": "your-api-key",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
result = response.json()
print(f"Job ID: {result['job_id']}")
print(f"Status: {result['status']}")
print(f"Progress: {result.get('progress', 'N/A')}")
if result['status'] == 'completed':
classification_result = result['result']
print(f"Classification: {classification_result['classification']}")
print(f"Confidence: {classification_result['confidence']:.2f}")
print(f"Total pages: {classification_result['total_pages']}")
# Page-by-page results
for page_result in classification_result['page_results']:
print(f"Page {page_result['page']}: {page_result['classification']} (confidence: {page_result['confidence']:.2f})")
elif result['status'] == 'failed':
print(f"Error: {result.get('error', 'Unknown error')}")
else:
print("Job is still processing...")
else:
print("Error:", response.status_code, response.text)
const jobId = '47c536aa-9fab-48ca-b27c-2fd74d30490a';
const response = await fetch(`https://prod.visionapi.unsiloed.ai/classify/${jobId}`, {
method: 'GET',
headers: {
'api-key': 'your-api-key',
'Content-Type': 'application/json'
}
});
if (response.ok) {
const result = await response.json();
console.log('Job ID:', result.job_id);
console.log('Status:', result.status);
console.log('Progress:', result.progress || 'N/A');
if (result.status === 'completed') {
const classificationResult = result.result;
console.log('Classification:', classificationResult.classification);
console.log('Confidence:', classificationResult.confidence);
console.log('Total pages:', classificationResult.total_pages);
// Display page-by-page results
classificationResult.page_results.forEach(pageResult => {
console.log(`Page ${pageResult.page}: ${pageResult.classification} (${pageResult.confidence.toFixed(2)})`);
});
} else if (result.status === 'failed') {
console.error('Error:', result.error || 'Unknown error');
} else {
console.log('Job is still processing...');
}
} else {
console.error('Request failed:', response.status, await response.text());
}
Response Examples
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "processing",
"progress": "Starting classification...",
"error": null,
"result": null
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "completed",
"progress": "Classification completed",
"error": null,
"result": {
"success": true,
"classification": "invoice",
"confidence": 0.9999996871837232,
"categories": [
{"category": "invoice", "pages": [1], "page_count": 1, "confidence": 0.9999996871837232}
],
"page_results": [
{
"page": 1,
"success": true,
"confidence": 0.9999996871837232,
"raw_result": "invoice",
"classification": "invoice"
}
],
"total_pages": 1,
"processed_pages": 1
}
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "completed",
"progress": "Classification completed",
"error": null,
"result": {
"success": true,
"classification": "contract",
"confidence": 0.89,
"categories": [
{"category": "contract", "pages": [1, 2], "page_count": 2, "confidence": 0.89}
],
"page_results": [
{
"page": 1,
"success": true,
"confidence": 0.92,
"raw_result": "contract",
"classification": "contract"
},
{
"page": 2,
"success": true,
"confidence": 0.86,
"raw_result": "contract",
"classification": "contract"
}
],
"total_pages": 2,
"processed_pages": 2
}
}
// 3 pages classify as academic_paper, 1 as presentation_slide.
// Top-level classification: "academic_paper" (most pages).
// Top-level confidence: 0.96 = mean of the 3 academic_paper page confidences.
// (NOT the fraction of pages agreeing; NOT 3/4.)
// categories[] surfaces both categories present — use it for mixed documents
// instead of relying on `classification` alone.
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "completed",
"progress": "Classification completed",
"error": null,
"result": {
"success": true,
"classification": "academic_paper",
"confidence": 0.96,
"categories": [
{"category": "academic_paper", "pages": [1, 2, 3], "page_count": 3, "confidence": 0.96},
{"category": "presentation_slide", "pages": [4], "page_count": 1, "confidence": 0.91}
],
"page_results": [
{"page": 1, "success": true, "confidence": 0.98, "raw_result": "academic_paper", "classification": "academic_paper"},
{"page": 2, "success": true, "confidence": 0.96, "raw_result": "academic_paper", "classification": "academic_paper"},
{"page": 3, "success": true, "confidence": 0.94, "raw_result": "academic_paper", "classification": "academic_paper"},
{"page": 4, "success": true, "confidence": 0.91, "raw_result": "presentation_slide", "classification": "presentation_slide"}
],
"total_pages": 4,
"processed_pages": 4
}
}
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "failed",
"progress": "Classification failed",
"error": "This PDF could not be opened — the file may be corrupt or in an unsupported format.",
"result": null
}
{
"detail": "Job not found"
}
Job Status Values
queued
queued
Job has been created and is waiting to be picked up for processing. Jobs move to processing as soon as a worker is available.
processing
processing
Job is currently being processed. This includes file upload to storage, document analysis, and classification processing. Progress messages will indicate the current stage.
completed
completed
Job has completed successfully. The result field contains the classification results with confidence scores and page-by-page details.
failed
failed
Job failed during processing. The error field contains details about what went wrong. Common causes include file corruption, invalid conditions, or processing errors.
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")
Progress Messages
The progress field carries one of three messages:- “Starting classification…” - Job has been picked up and is being processed
- “Classification completed” - Job finished successfully
- “Classification failed” - Job encountered an error (jobs that fail before classification starts may retain “Starting classification…”)
Error Handling
Common Error Scenarios
- File Processing Errors: PDF corruption, password protection, or unreadable content (job fails with the reason in
error) - Model Errors: Vision model failures or timeouts during page classification
- Job Not Found: Invalid job ID or job has been deleted (HTTP 404)
POST /classify with a 400/413 response, so they never appear as failed jobs here.
Error Response Example
File Processing Error
{
"job_id": "47c536aa-9fab-48ca-b27c-2fd74d30490a",
"status": "failed",
"progress": "Classification failed",
"error": "This PDF could not be opened — the file may be corrupt or in an unsupported format.",
"result": null
}
Authorizations
Path Parameters
The unique identifier of the classification job
Response
200 - application/json
Classification job status retrieved successfully
⌘I

