Skip to main content

Status API

Check the processing status of uploaded documents.

Client Isolation

Job status is scoped to the client that created the job. A job is only visible to the client whose API key was used to submit the /embed request. Querying a job ID that belongs to a different client returns 404 — the same as a non-existent job — to avoid leaking information across clients.

Endpoint

GET /status/{job_id}

Request

Headers

HeaderRequiredDescription
X-API-KeyYesValid API key from API_KEY_CLIENTS env var

Path Parameters

ParameterDescription
job_idJob ID returned from /embed endpoint

Response

Pending/Started

{
"job_id": "abc123-def456",
"document_id": "doc-001",
"status": "pending"
}

Processing

{
"job_id": "abc123-def456",
"document_id": "doc-001",
"status": "processing"
}

Completed

{
"job_id": "abc123-def456",
"document_id": "doc-001",
"status": "completed",
"chunks_created": 12,
"categories": ["financial reporting"],
"classification_status": "completed",
"entities_extracted": {
"persons": ["John Smith", "Jane Doe"],
"organizations": ["Acme Corp", "Tech Inc"],
"dates": ["January 15, 2024"],
"locations": ["New York", "San Francisco"]
},
"created_at": "2026-03-26T12:19:26.452416+00:00",
"completed_at": "2026-03-26T12:19:46.580322+00:00"
}

The indexing status and classification_status are independent. A document can be searchable with status: "completed" while classification is still "pending". Keep polling this endpoint until classification_status becomes "completed", "failed", or "disabled"; terminal classification and categories are refreshed from the stored document version even when entities_extracted is already present.

Failed

{
"job_id": "abc123-def456",
"document_id": "doc-001",
"status": "failed",
"error": "Error message describing what went wrong"
}

Partial Failed

Some embedding tasks failed while others succeeded:

{
"job_id": "abc123-def456",
"document_id": "doc-001",
"status": "partial_failed",
"chunks_created": 45,
"entities_extracted": {
"persons": ["John Smith"],
"organizations": ["Acme Corp"]
},
"error": "Task xyz failed: Connection timeout"
}
Partial Failure

When processing large documents, chunks are processed in parallel. If some chunks fail but others succeed, you get partial_failed status. The successful chunks are searchable; failed chunks are lost.

Retry

Task is scheduled for retry after a failure:

{
"job_id": "abc123-def456",
"document_id": "doc-001",
"status": "retrying",
"error": "Connection timeout to Qdrant",
"retry_count": 1,
"max_retries": 3,
"next_retry_in_seconds": 60
}

Status Values

StatusDescription
pendingJob queued, waiting for worker
startedWorker picked up the job
processingActively processing (parsing/chunking/embedding)
completedSuccessfully indexed
failedProcessing failed, see error field
partial_failedSome chunks succeeded, others failed
retryingWill be retried (up to 3 attempts)

Examples

Basic Status Check

curl http://localhost:8000/status/abc123-def456 \
-H "X-API-Key: super-secret-key"

Poll Until Complete

#!/bin/bash

JOB_ID="abc123-def456"
API_KEY="super-secret-key"

while true; do
response=$(curl -s "http://localhost:8000/status/$JOB_ID" \
-H "X-API-Key: $API_KEY")

status=$(echo "$response" | jq -r '.status')
echo "Status: $status"

if [ "$status" = "completed" ]; then
echo "Document indexed successfully!"
echo "$response" | jq '.'
break
elif [ "$status" = "failed" ]; then
echo "Processing failed!"
echo "$response" | jq '.'
break
fi

sleep 2
done

Python Polling

import time
import requests

def wait_for_completion(job_id: str, api_key: str, timeout: int = 300) -> dict:
"""Poll status until completed or failed."""
url = f"http://localhost:8000/status/{job_id}"
headers = {"X-API-Key": api_key}

start = time.time()
while time.time() - start < timeout:
response = requests.get(url, headers=headers)
data = response.json()

print(f"Status: {data['status']}")

if data['status'] == 'completed':
print(f"Created {data['chunks_created']} chunks")
return data
elif data['status'] == 'failed':
raise Exception(f"Processing failed: {data.get('error')}")

time.sleep(2)

raise TimeoutError("Processing took too long")

# Usage
result = wait_for_completion("abc123-def456", "super-secret-key")

Response Codes

CodeDescription
200Success - Returns status
401Unauthorized - Invalid API key
404Not Found - Job ID doesn't exist, or the job belongs to a different client
429Rate Limited - Too many requests

Error Responses

{
"detail": "Invalid API key",
"error_code": "auth_failed",
"request_id": "5d7f4c1a2b9e4b3e8f6f0d2a4c9b8a1e"
}
{
"detail": "Job not found",
"error_code": "not_found",
"request_id": "5d7f4c1a2b9e4b3e8f6f0d2a4c9b8a1e"
}

Best Practices

  1. Poll with backoff - Start with 1s intervals, increase to 5s for longer jobs
  2. Set timeouts - Large documents can take several minutes
  3. Handle failures - Check for failed status and log the error
  4. Store job IDs - Keep job IDs for later status checks or debugging

Typical Processing Times

Document TypeSizeApproximate Time
Text file< 100KB2-5 seconds
PDF1-5 pages5-15 seconds
PDF10-50 pages15-45 seconds
PDF100+ pages1-3 minutes
DOCXAnySimilar to PDF

Note: First document after startup takes longer due to model loading (~30s).