Multi-File Upload API Documentation

Version: 2.0 Last Updated: November 28, 2025 Status: Production Ready


Overview

The Multi-File Upload API enables uploading multiple documents (up to 50 PDFs) in a single request with intelligent auto-categorization and selective analysis. This feature dramatically reduces API calls and speeds up document processing.

Key Benefits

  • Batch Upload: Upload up to 50 PDFs in one request
  • Instant Categorization: Automatic document type detection using 60+ filename patterns
  • Smart Analysis: Only critical/important documents are auto-analyzed (saves 74% of API calls)
  • On-Demand Analysis: Optional documents analyzed only when user asks about them
  • 6-9x Faster: Parallel processing vs sequential uploads

Endpoint

POST /v1/properties/{property_id}/upload

Upload multiple PDF documents to a property for analysis.

Authentication: Required (Bearer token)

Content-Type: multipart/form-data

Rate Limits:

  • Maximum 50 files per request
  • Files must be PDF format
  • Recommended max file size: 50 MB per file

Request

Path Parameters

ParameterTypeRequiredDescription
property_idstring (UUID)YesThe property ID to upload documents to

Form Data

FieldTypeRequiredDescription
filesFile[]YesArray of PDF files (1-50 files)

cURL Example

Shell
curl -X POST "https://api.homeinsightai.com/v1/properties/{property_id}/upload" \
  -H "Authorization: Bearer hi_live_abc123xyz..." \
  -F "files=@Home_Inspection_Report.pdf" \
  -F "files=@Loan_Estimate_2024.pdf" \
  -F "files=@Seller_Disclosure.pdf" \
  -F "files=@Purchase_Agreement.pdf"

Python Example

Python
import requests

url = "https://api.homeinsightai.com/v1/properties/{property_id}/upload"
headers = {
    "Authorization": "Bearer hi_live_abc123xyz..."
}

files = [
    ("files", ("Home_Inspection_Report.pdf", open("inspection.pdf", "rb"), "application/pdf")),
    ("files", ("Loan_Estimate_2024.pdf", open("loan.pdf", "rb"), "application/pdf")),
    ("files", ("Seller_Disclosure.pdf", open("disclosure.pdf", "rb"), "application/pdf")),
]

response = requests.post(url, headers=headers, files=files)
print(response.json())

JavaScript Example

JavaScript
const formData = new FormData();
formData.append('files', inspectionFile);
formData.append('files', loanFile);
formData.append('files', disclosureFile);

const response = await fetch(
  `https://api.homeinsightai.com/v1/properties/${propertyId}/upload`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
    },
    body: formData,
  }
);

const result = await response.json();
console.log(result);

Response

Success Response (200 OK)

JSON
{
  "property_id": "550e8400-e29b-41d4-a716-446655440000",
  "documents_uploaded": 4,
  "documents_categorized": 4,
  "auto_analyzed": 0,
  "queued_for_analysis": 2,
  "documents": [
    {
      "id": "ana_1a2b3c4d5e6f",
      "filename": "Home_Inspection_Report.pdf",
      "category": "critical",
      "is_analyzed": false,
      "file_size_bytes": 2458923,
      "confidence": 0.95,
      "categorization_method": "filename_pattern",
      "reasoning": "Filename matches critical patterns: (?i)inspection.*report, (?i)home.*inspection"
    },
    {
      "id": "ana_2b3c4d5e6f7g",
      "filename": "Loan_Estimate_2024.pdf",
      "category": "important",
      "is_analyzed": false,
      "file_size_bytes": 845672,
      "confidence": 0.90,
      "categorization_method": "filename_pattern",
      "reasoning": "Filename matches important patterns: (?i)loan.*estimate"
    },
    {
      "id": "ana_3c4d5e6f7g8h",
      "filename": "Seller_Disclosure.pdf",
      "category": "critical",
      "is_analyzed": false,
      "file_size_bytes": 1234567,
      "confidence": 0.95,
      "categorization_method": "filename_pattern",
      "reasoning": "Filename matches critical patterns: (?i)seller.*disclosure"
    },
    {
      "id": "ana_4d5e6f7g8h9i",
      "filename": "Purchase_Agreement.pdf",
      "category": "optional",
      "is_analyzed": false,
      "file_size_bytes": 987654,
      "confidence": 0.80,
      "categorization_method": "filename_pattern",
      "reasoning": "Filename matches optional patterns: (?i)purchase.*agreement"
    }
  ],
  "failed_documents": []
}

Response Fields

FieldTypeDescription
property_idstringProperty UUID
documents_uploadedintegerNumber of successfully uploaded documents
documents_categorizedintegerNumber of documents successfully categorized
auto_analyzedintegerNumber of documents analyzed immediately (always 0 on upload, updated by background tasks)
queued_for_analysisintegerNumber of critical/important documents queued for background analysis
documentsarrayList of uploaded document details
failed_documentsarrayList of failed uploads with error messages

Document Object

FieldTypeDescription
idstringAnalysis ID (format: ana_xxxxx)
filenamestringOriginal filename
categorystringAuto-detected category: critical, important, optional, noise
is_analyzedbooleanWhether full analysis is complete (false on upload, updated by background task)
file_size_bytesintegerFile size in bytes
confidencefloatCategorization confidence (0.0-1.0)
categorization_methodstringHow it was categorized: filename_pattern or ai_scan
reasoningstringWhy this category was assigned

Failed Document Object

FieldTypeDescription
filenamestringOriginal filename
errorstringError message describing why upload failed

Error Responses

400 Bad Request

No files provided:

JSON
{
  "detail": "No files provided"
}

Too many files:

JSON
{
  "detail": "Maximum 50 files allowed per upload"
}

Invalid file type:

JSON
{
  "detail": "Only PDF files allowed. Invalid file: document.docx"
}

401 Unauthorized

JSON
{
  "detail": "Invalid or missing API key"
}

404 Not Found

JSON
{
  "detail": "Property not found"
}

500 Internal Server Error

JSON
{
  "detail": "Failed to create record for filename.pdf"
}

Document Categories

Documents are automatically categorized into four tiers:

Critical (Auto-Analyzed)

Documents that MUST be analyzed for user safety and legal compliance.

Examples:

  • Home inspection reports
  • Property inspection reports
  • Structural reports
  • Pest/termite inspections
  • Seller disclosures
  • Property disclosures
  • Natural hazard disclosures
  • Lead-based paint disclosures
  • Environmental disclosures

Auto-Analysis: ✅ Yes (queued immediately)


Important (Auto-Analyzed)

Documents that provide significant value but aren't safety-critical.

Examples:

  • Loan estimates
  • Closing disclosures
  • Mortgage applications
  • Pre-approvals
  • Appraisal reports
  • Property valuations
  • Title reports
  • Preliminary title documents

Auto-Analysis: ✅ Yes (queued immediately)


Optional (On-Demand)

Documents analyzed only when user asks about them.

Examples:

  • Purchase agreements
  • Sales contracts
  • Listing agreements
  • Addendums
  • Amendments
  • Buyer representation forms
  • Agency disclosures
  • Escrow instructions

Auto-Analysis: ❌ No (analyzed when user asks)


Noise (Skipped)

Administrative documents that don't require AI analysis.

Examples:

  • Receipts
  • Acknowledgements
  • Notices to perform
  • Contingency removals
  • HOA rules
  • CC&Rs (Covenants, Conditions & Restrictions)
  • Calendars
  • Schedules
  • Checklists

Auto-Analysis: ❌ No (metadata only)


Background Processing

How It Works

  1. Upload Phase (instant):

    • Files uploaded to server
    • Database records created with is_analyzed: false
    • Documents categorized using filename patterns (free, instant)
    • Response returned to client immediately
  2. Background Analysis Phase (15-30 seconds per document):

    • Critical/important documents queued for processing
    • PDF text and images extracted
    • Gemini Vision analysis runs in parallel
    • Embeddings generated and stored
    • Database updated with is_analyzed: true
  3. On-Demand Phase (triggered by user questions):

    • Chat endpoint detects questions about unanalyzed documents
    • Relevant optional documents queued for analysis
    • User notified analysis is in progress

Checking Analysis Status

Use the property documents endpoint to check which documents have completed analysis:

Shell
curl -X GET "https://api.homeinsightai.com/v1/properties/{property_id}/documents" \
  -H "Authorization: Bearer hi_live_abc123xyz..."

Response:

JSON
{
  "property_id": "550e8400-e29b-41d4-a716-446655440000",
  "documents": [
    {
      "id": "ana_1a2b3c4d5e6f",
      "document_type": "inspection_report",
      "status": "completed",
      "filename": "Home_Inspection_Report.pdf",
      "property_address": "123 Main St",
      "created_at": "2025-11-28T10:30:00Z"
    }
  ],
  "total": 1
}

Performance Benchmarks

Multi-File Upload Speed

ScenarioBefore (Sequential)After (Parallel)Improvement
3 PDFs (10 images each)90-204s15-23s6-9x faster
10 PDFs~300-600s~30-60s10x faster
50 PDFs~1500-3000s~150-300s10x faster

Resource Efficiency

ScenarioOld ApproachNew ApproachSavings
50 documents uploaded500 API calls130 API calls74% fewer calls
Analysis breakdownAll analyzed7 critical + 5 on-demand5x more efficient

Best Practices

1. Use Descriptive Filenames

The categorization system relies on filename patterns. Use clear, descriptive filenames:

Good:

  • Home_Inspection_Report_123_Main_St.pdf
  • Loan_Estimate_Wells_Fargo_2024.pdf
  • Seller_Property_Disclosure.pdf

Bad:

  • document1.pdf
  • scan.pdf
  • untitled.pdf

2. Group Related Documents

Upload all documents for a property in a single batch when possible:

JavaScript
// Good - Single batch upload
const allFiles = [
  inspectionReport,
  loanEstimate,
  disclosure,
  appraisal,
  purchaseAgreement
];
await uploadDocuments(propertyId, allFiles);

// Less efficient - Multiple uploads
await uploadDocuments(propertyId, [inspectionReport]);
await uploadDocuments(propertyId, [loanEstimate]);
await uploadDocuments(propertyId, [disclosure]);

3. Handle Partial Failures

Always check the failed_documents array and handle errors gracefully:

JavaScript
const result = await uploadDocuments(propertyId, files);

if (result.failed_documents.length > 0) {
  console.warn(`${result.failed_documents.length} documents failed to upload:`);
  result.failed_documents.forEach(failed => {
    console.error(`- ${failed.filename}: ${failed.error}`);
  });

  // Optionally retry failed uploads
  await retryFailedUploads(result.failed_documents);
}

4. Monitor Background Processing

For critical workflows, poll the documents endpoint to confirm analysis completion:

JavaScript
async function waitForAnalysis(propertyId, documentIds, timeout = 60000) {
  const startTime = Date.now();

  while (Date.now() - startTime < timeout) {
    const docs = await getPropertyDocuments(propertyId);
    const analyzed = docs.documents.filter(d =>
      documentIds.includes(d.id) && d.status === 'completed'
    );

    if (analyzed.length === documentIds.length) {
      return true; // All documents analyzed
    }

    await sleep(5000); // Check every 5 seconds
  }

  throw new Error('Analysis timeout');
}

5. Optimize File Sizes

Compress PDFs before upload to reduce bandwidth and processing time:

  • Use PDF compression tools (Ghostscript, Adobe Acrobat)
  • Target file sizes under 10 MB when possible
  • Downscale images to 1920x1080 or lower
  • Remove unnecessary pages

Migration Guide

Upgrading from Single-File Upload

Old API (still supported):

JavaScript
// POST /v1/analyses
const response = await fetch('/v1/analyses', {
  method: 'POST',
  body: formData, // Single file
});

New API (recommended):

JavaScript
// POST /v1/properties/{property_id}/upload
const response = await fetch(`/v1/properties/${propertyId}/upload`, {
  method: 'POST',
  body: formData, // Multiple files
});

Migration Checklist:

  1. ✅ Create a property first (if not already created)
  2. ✅ Update upload endpoint from /v1/analyses to /v1/properties/{id}/upload
  3. ✅ Support multiple file selection in UI
  4. ✅ Handle documents array in response (instead of single document)
  5. ✅ Handle failed_documents array for error reporting
  6. ✅ Update status checking to use /v1/properties/{id}/documents
  7. ✅ Test with batch uploads of 5-10 files

Backward Compatibility

The old single-file upload endpoint (POST /v1/analyses) remains available for backward compatibility. However, new integrations should use the multi-file endpoint for better performance.


Troubleshooting

Problem: Files Not Categorizing Correctly

Solution: Use more descriptive filenames that match the patterns:

Shell
# Check categorization patterns
# Critical: inspection, disclosure, structural, pest
# Important: loan, appraisal, title
# Optional: purchase, agreement, contract
# Noise: receipt, acknowledgement, hoa, rules

Problem: Analysis Taking Too Long

Causes:

  • Large files (>20 MB)
  • High image count (>50 images per PDF)
  • Server under heavy load

Solutions:

  • Compress PDFs before upload
  • Split large documents into smaller files
  • Check system status at status.homeinsightai.com

Problem: Some Documents Failed to Upload

Check failed_documents array:

JSON
{
  "failed_documents": [
    {
      "filename": "corrupted.pdf",
      "error": "Failed to create record for corrupted.pdf"
    }
  ]
}

Common Causes:

  • Corrupted PDF files
  • Password-protected PDFs
  • Invalid PDF structure
  • Network timeout

Solutions:

  • Re-save PDF from source application
  • Remove password protection
  • Use PDF repair tools
  • Retry upload

Rate Limits

PlanUpload LimitFiles Per RequestMax File Size
Free Trial1 property/month10 files50 MB
Pay-Per-Report ($29/property)1 property per purchase50 files50 MB
Pro ($99/mo)Unlimited properties/month75 files100 MB
Enterprise ($999/mo + usage)UnlimitedUnlimitedUnlimited

Support

  • Documentation: https://docs.homeinsightai.com
  • API Status: https://status.homeinsightai.com
  • Email: support@homeinsightai.com
  • Discord: https://discord.gg/homeinsightai
Home Insight AI - Developer Portal