Push to HITL from API Deployments
This feature is available in Unstract Cloud Edition and Unstract On-Premise Edition.
Push API deployment execution results directly to the HITL (Human-in-the-Loop) review queue for manual verification before final processing. This enables quality control, audit workflows, and selective human review of API-processed documents.
Overview
When executing an API deployment, you can optionally specify a hitl_queue_name parameter to route the execution results to a HITL review queue instead of returning them immediately. This allows:
- Quality Assurance: Manual verification of extraction results before downstream processing
- Audit Workflows: Human review of sensitive or high-value documents
- Selective Review: Send only specific documents to HITL based on business logic
- Exception Handling: Route problematic extractions for manual correction
How It Works
API Request → Document Processing → HITL Queue → Manual Review → Approval → Retrieve Results
↓ ↓ ↓ ↓ ↓ ↓
Send file Extract data Queue for review Reviewer edits Supervisor OK Get from queue
Normal API Flow:
POST /api → Process → Return Results
HITL-Enabled API Flow:
POST /api (with hitl_queue_name) → Process → Push to HITL Queue → Manual Review → Retrieve from Queue
API Usage
Endpoint
POST /deployment/api/{org_name}/{api_name}/
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
files | file(s) | Yes | Document file(s) to process |
timeout | integer | No | Execution timeout in seconds |
include_metadata | boolean | No | Include processing metadata in response |
hitl_queue_name | string | No | HITL queue identifier for routing to review queue |
The hitl_queue_name acts as a custom identifier for your HITL queue. It's appended to the standard queue name format:
review_queue_{organization_id}_{workflow_id}:{hitl_queue_name}
Example Requests
Standard API Request (Without HITL)
curl --location 'https://us-central.unstract.com/deployment/api/myorg/invoice-api/' \
--header 'Authorization: Bearer <api_key>' \
--form 'files=@"invoice.pdf"' \
--form 'timeout="300"' \
--form 'include_metadata="true"'
API Request with HITL Queue
curl --location 'https://us-central.unstract.com/deployment/api/myorg/invoice-api/' \
--header 'Authorization: Bearer <api_key>' \
--form 'files=@"invoice.pdf"' \
--form 'timeout="300"' \
--form 'include_metadata="true"' \
--form 'hitl_queue_name="high-value-invoices"'
Multiple Files with HITL
curl --location 'https://us-central.unstract.com/deployment/api/myorg/invoice-api/' \
--header 'Authorization: Bearer <api_key>' \
--form 'files=@"invoice1.pdf"' \
--form 'files=@"invoice2.pdf"' \
--form 'files=@"invoice3.pdf"' \
--form 'hitl_queue_name="batch-review-001"'
Response Format
Success Response
{
"message": {
"status": "QUEUED",
"execution_id": "660e8400-e29b-41d4-a716-446655440001"
}
}
Response Fields:
| Field | Description |
|---|---|
status | Execution status (QUEUED when using HITL) |
execution_id | Unique identifier for tracking this execution |
When hitl_queue_name is provided, the API returns immediately with QUEUED status. Documents are processed and pushed to the HITL review queue. Results are available after manual review and approval via the Retrieve Approved Results API.
Error Responses
422 Unprocessable Entity
{
"error": "Invalid hitl_queue_name format"
}
Cause: Queue name doesn't meet validation requirements
403 Forbidden
{
"error": "HITL feature not available"
}
Cause: Enterprise license not active or HITL plugin not installed
406 Not Acceptable
{
"error": "Result already acknowledged"
}
Cause: Execution result has already been processed
Integration Examples
Python Example
import requests
import os
API_BASE_URL = "https://us-central.unstract.com"
ORG_NAME = "myorg"
API_NAME = "invoice-api"
API_KEY = os.environ.get("UNSTRACT_API_KEY")
def execute_with_hitl(file_path, hitl_queue_name):
"""Execute API deployment with HITL routing"""
url = f"{API_BASE_URL}/deployment/api/{ORG_NAME}/{API_NAME}/"
headers = {
"Authorization": f"Bearer {API_KEY}"
}
data = {
"timeout": 300,
"include_metadata": "true",
"hitl_queue_name": hitl_queue_name
}
with open(file_path, "rb") as f:
files = {"files": f}
response = requests.post(url, headers=headers, files=files, data=data)
response.raise_for_status()
result = response.json()
execution_id = result["message"]["execution_id"]
print(f"Document sent to HITL queue: {hitl_queue_name}")
print(f"Execution ID: {execution_id}")
return execution_id
# Execute with HITL
execution_id = execute_with_hitl("invoice.pdf", "high-value-invoices")
# Later, retrieve approved results using the Retrieve Approved Results API
# See: retrieve_approved_results.md
Python with Conditional HITL
def execute_api_with_conditional_hitl(file_path, amount):
"""Send to HITL only if amount exceeds threshold"""
url = f"{API_BASE_URL}/deployment/api/{ORG_NAME}/{API_NAME}/"
headers = {"Authorization": f"Bearer {API_KEY}"}
data = {
"timeout": 300,
"include_metadata": "true"
}
# Conditional HITL routing based on business logic
if amount > 10000:
data["hitl_queue_name"] = "high-value-invoices"
print(f"Amount ${amount} exceeds threshold, routing to HITL")
else:
print(f"Amount ${amount} below threshold, processing directly")
with open(file_path, "rb") as f:
response = requests.post(url, headers=headers, files={"files": f}, data=data)
return response.json()
# Usage
result = execute_api_with_conditional_hitl("invoice.pdf", amount=15000)
Node.js Example
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');
const API_BASE_URL = "https://us-central.unstract.com";
const ORG_NAME = "myorg";
const API_NAME = "invoice-api";
const API_KEY = process.env.UNSTRACT_API_KEY;
async function executeWithHITL(filePath, hitlQueueName) {
const url = `${API_BASE_URL}/deployment/api/${ORG_NAME}/${API_NAME}/`;
const formData = new FormData();
formData.append('files', fs.createReadStream(filePath));
formData.append('timeout', '300');
formData.append('include_metadata', 'true');
formData.append('hitl_queue_name', hitlQueueName);
try {
const response = await axios.post(url, formData, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
...formData.getHeaders()
}
});
const executionId = response.data.message.execution_id;
console.log(`Document sent to HITL queue: ${hitlQueueName}`);
console.log(`Execution ID: ${executionId}`);
return executionId;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
throw error;
}
}
// Execute with HITL
executeWithHITL('invoice.pdf', 'high-value-invoices')
.then(executionId => {
console.log('Success:', executionId);
});
Batch Processing with Selective HITL
import requests
import os
def batch_process_with_selective_hitl(file_list, selection_criteria):
"""Process batch of files with selective HITL routing"""
url = f"{API_BASE_URL}/deployment/api/{ORG_NAME}/{API_NAME}/"
headers = {"Authorization": f"Bearer {API_KEY}"}
results = []
for file_info in file_list:
file_path = file_info["path"]
should_review = selection_criteria(file_info)
data = {"timeout": 300, "include_metadata": "true"}
if should_review:
# Route to HITL for manual review
data["hitl_queue_name"] = file_info.get("queue", "standard-review")
print(f"Sending {file_path} to HITL for review")
else:
print(f"Processing {file_path} directly")
with open(file_path, "rb") as f:
response = requests.post(url, headers=headers, files={"files": f}, data=data)
response_json = response.json()
results.append({
"file": file_path,
"execution_id": response_json.get("message", {}).get("execution_id") if should_review else None,
"hitl_enabled": should_review
})
return results
# Example usage
files = [
{"path": "invoice1.pdf", "amount": 15000, "queue": "high-value"},
{"path": "invoice2.pdf", "amount": 500, "queue": "standard"},
{"path": "invoice3.pdf", "amount": 50000, "queue": "high-value"},
]
# Criteria: Send to HITL if amount > $10,000
results = batch_process_with_selective_hitl(
files,
selection_criteria=lambda f: f["amount"] > 10000
)
print(f"Processed {len(results)} files")
print(f"Sent to HITL: {sum(1 for r in results if r['hitl_enabled'])}")
Configuration Requirements
Prerequisites
-
Enterprise License: HITL queue management requires an active enterprise license
-
API Deployment Created:
- Create an API deployment from your Prompt Studio project
- See: Creating API Deployments
-
HITL Configuration:
- HITL plugin must be installed in the backend
- Manual review workers must be configured
- Redis connection for queue operations
-
User Roles:
- API execution requires valid API key
- Manual review requires Reviewer or Supervisor role
- See: User Roles and Permissions
Validation Requirements
The hitl_queue_name parameter undergoes enterprise validation to ensure:
- Valid format and characters
- Compliance with queue naming conventions
- No conflicts with system queue names
If validation fails, you'll receive a 422 Unprocessable Entity error.
Retrieving Results
Documents pushed to HITL queue follow this workflow:
- API Execution: Document processed and sent to HITL queue
- Manual Review: Reviewer examines and modifies extraction results
- Approval: Supervisor approves reviewed document (or auto-approved)
- Retrieval: Use Retrieve Approved Results API to get approved data
Retrieving Approved Results
After documents are approved, retrieve them using the approved results API:
import requests
# Retrieve approved results from HITL queue
def get_approved_results(org_name, class_id, hitl_queue_name):
"""Get approved results from HITL queue"""
url = f"{API_BASE_URL}/mr/api/{org_name}/approved/result/{class_id}/"
headers = {"Authorization": f"Bearer {API_KEY}"}
params = {"hitl_queue_name": hitl_queue_name}
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
return response.json()
# Get results
result = get_approved_results("myorg", "workflow-uuid", "high-value-invoices")
print(f"Approved result: {result['data']['result']}")
For complete details, see Retrieve Approved Results.
Best Practices
When to Use HITL from API
✅ Good Use Cases:
- High-Value Transactions: Invoices, contracts, or documents above a monetary threshold
- Regulatory Compliance: Documents requiring audit trails and human verification
- New Document Types: Testing extraction accuracy on unfamiliar formats
- Exception Handling: Low-confidence extractions flagged for review
- Quality Sampling: Random sampling for ongoing quality assurance
❌ Avoid HITL For:
- High-Volume Standard Docs: Well-tested, high-confidence extractions
- Real-Time Requirements: When immediate results are needed
- Fully Automated Workflows: Where human review adds no value
Queue Naming Conventions
- Use Descriptive Names:
high-value-invoices,contract-review,qa-sample - Avoid Special Characters: Use alphanumeric characters, hyphens, underscores
- Consistent Naming: Establish team conventions for queue names
- Purpose-Based Naming: Name queues by purpose, not by date/time
Error Handling
Python error handling example
def execute_with_error_handling(file_path, hitl_queue_name):
"""Execute API with comprehensive error handling"""
url = f"{API_BASE_URL}/deployment/api/{ORG_NAME}/{API_NAME}/"
headers = {"Authorization": f"Bearer {API_KEY}"}
data = {
"timeout": 300,
"hitl_queue_name": hitl_queue_name
}
try:
with open(file_path, "rb") as f:
response = requests.post(url, headers=headers, files={"files": f}, data=data)
response.raise_for_status()
result = response.json()
print(f"✓ Sent to HITL queue: {hitl_queue_name}")
return result["message"]["execution_id"]
except requests.exceptions.HTTPError as e:
if e.response.status_code == 422:
print(f"✗ Invalid queue name: {hitl_queue_name}")
elif e.response.status_code == 403:
print("✗ HITL feature not available (check enterprise license)")
else:
print(f"✗ HTTP error: {e}")
raise
except Exception as e:
print(f"✗ Unexpected error: {e}")
raise
Monitoring
- Track Queue Depth: Monitor how many documents are waiting for review
- Measure Review Time: Track time from API execution to approval
- Monitor Success Rate: Track approval vs. rejection rates
- Alert on Backlogs: Set up alerts when queue depth exceeds thresholds
Troubleshooting
Validation Error: Invalid hitl_queue_name
Error:
{
"error": "Invalid hitl_queue_name format"
}
Causes:
- Queue name contains invalid characters
- Queue name is too long
- Queue name conflicts with system naming
Solutions:
- Use only alphanumeric characters, hyphens, and underscores
- Keep queue names under 50 characters
- Avoid reserved system keywords
HITL Feature Not Available
Error:
{
"error": "HITL feature not available"
}
Causes:
- Enterprise license not active
- HITL plugin not installed
- Manual review backend not configured
Solutions:
- Verify enterprise license status
- Check that HITL plugin is installed in backend
- Ensure manual review workers are running
- Contact support if issue persists
Documents Not Appearing in Review Queue
Possible Causes:
- Queue name mismatch
- API execution failed
- Workflow configuration issues
- Redis connection problems
Solutions:
- Verify API execution completed successfully (check execution_id)
- Confirm queue name spelling matches exactly
- Check workflow logs for errors
- Verify Redis connection and queue status
Cannot Retrieve Approved Results
Possible Causes:
- Documents not yet approved
- Wrong class_id or org_name
- Queue name parameter missing in retrieval
- API key lacks permissions
Solutions:
- Check HITL review interface to confirm documents are approved
- Verify class_id matches your workflow
- Include
hitl_queue_nameparameter in retrieval request if used - Confirm API key has Human Review permissions
Workflow Combinations
HITL + Auto Approval
Combine API HITL routing with Auto Approval for trusted reviewers:
API (hitl_queue_name) → HITL Queue → Reviewer Review → Auto Approve → Retrieve Results
Benefit: Documents still get reviewed, but trusted reviewers' submissions skip supervisor approval.
HITL + Destination DB
Configure workflow to send approved results to destination database:
API (hitl_queue_name) → HITL Queue → Review → Approve → Destination DB
Benefit: Approved results automatically inserted into your database.
Related Documentation
- API Deployments - Create and manage API deployments
- Setting up HITL ETL - Configure HITL for ETL pipelines
- Retrieve Approved Results - Get approved documents from queue
- HITL Auto Approval - Configure automatic approval
- API Execution - API execution documentation
FAQ
Can I use different queue names for different document types?
Yes! Use different hitl_queue_name values to route different document types to separate queues for organized review.
What happens if I don't provide hitl_queue_name?
The API processes the document normally and returns results immediately without HITL routing.
Can I use HITL with batch API executions?
Yes, include hitl_queue_name in batch requests. All files in the batch will be routed to the specified HITL queue.
How do I know when documents are approved?
Poll the Retrieve Approved Results API or set up webhooks for approval notifications.
Can reviewers see the hitl_queue_name in the interface?
Yes, reviewers can see which queue they're working from in the Human Quality Review interface.
Is there a limit to queue name length?
Queue names should be kept concise (under 50 characters recommended) for optimal performance.
Can multiple APIs share the same hitl_queue_name?
Yes, but be cautious - reviewers will see mixed documents from different APIs in the same queue.