Skip to content

Document Intelligence API

Extract text, structured tables, form fields, key-value pairs, invoices, receipts, and PII from documents and images using AI-powered OCR, AWS Textract, and vision language models.

All operations are billed directly in USD from your prepaid wallet. No credits, no token packs, no PLN.

Base URL: https://apis.fotohub.app

Supported formats: PDF, JPEG, PNG, TIFF, WEBP, DOCX (max 20MB per document, multi-page PDFs supported)


Endpoint Overview

MethodEndpointCostDescription
POST/v1/ai/document/detect-text$0.005/pageFast OCR — plain text extraction
POST/v1/ai/document/analyze$0.015/pageTables + forms + key-value + signatures
POST/v1/ai/document/analyze-expense$0.012/documentInvoice/receipt structured extraction
POST/v1/documents/extract$0.005/pageURL-based OCR with structured JSON output
POST/v1/documents/redact$0.008/pagePII redaction (names, emails, SSNs, cards)
POST/v1/documents/classify$0.003/documentDocument type classification
POST/v1/documents/batch$0.004/documentAsync bulk processing of multiple documents
GET/v1/documents/batch/{batch_id}FreePoll batch job status
POST/v1/textract/analyze$0.015/pageAWS Textract: complex forms, tables, handwriting

Detect Text (OCR)

Simple, fast text extraction from images and single-page documents.

Cost: $0.005 per page

Request

POST /v1/ai/document/detect-text
Authorization: Bearer fh_live_your_api_key
Content-Type: application/json

Parameters

ParameterTypeRequiredDefaultDescription
documentstringYesBase64-encoded document (PDF/image), max 20MB
document_urlstringConditionalPublic URL alternative to base64 upload
language_hintsstring[]No["en"]ISO 639-1 language codes to improve accuracy
output_formatstringNo"json"Response format: "json" or "text"

Response

json
{
  "text": "FOTOhub Invoice #2026-07-001\nDate: 2026-07-19\nCustomer: Acme Corporation\nTotal: $142.50 USD",
  "lines": [
    { "text": "FOTOhub Invoice #2026-07-001", "confidence": 99.8, "page": 1 },
    { "text": "Date: 2026-07-19", "confidence": 99.5, "page": 1 },
    { "text": "Customer: Acme Corporation", "confidence": 99.1, "page": 1 }
  ],
  "total_lines": 12,
  "pages_processed": 1,
  "usd_charged": 0.005,
  "processing_ms": 420
}

Code Examples

python
import base64
import httpx

api_key = "fh_live_your_api_key"

with open("invoice.png", "rb") as f:
    doc_b64 = base64.b64encode(f.read()).decode()

response = httpx.post(
    "https://apis.fotohub.app/v1/ai/document/detect-text",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"document": doc_b64, "language_hints": ["en"]}
)

result = response.json()
print(result["text"])
print(f"Cost: ${result['usd_charged']:.4f}")
typescript
import fs from 'fs';

const doc = fs.readFileSync('invoice.png').toString('base64');

const response = await fetch('https://apis.fotohub.app/v1/ai/document/detect-text', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer fh_live_your_api_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    document: doc,
    language_hints: ['en'],
  }),
});

const result = await response.json();
console.log(result.text);
console.log(`Cost: $${result.usd_charged}`);
go
package main

import (
    "bytes"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    fileBytes, _ := os.ReadFile("invoice.png")
    docB64 := base64.StdEncoding.EncodeToString(fileBytes)

    body, _ := json.Marshal(map[string]interface{}{
        "document":       docB64,
        "language_hints": []string{"en"},
    })

    req, _ := http.NewRequest("POST", "https://apis.fotohub.app/v1/ai/document/detect-text", bytes.NewBuffer(body))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("FOTOHUB_API_KEY"))
    req.Header.Set("Content-Type", "application/json")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    result, _ := io.ReadAll(resp.Body)
    fmt.Println(string(result))
}
bash
# Base64 encode the document then submit
DOC_B64=$(base64 -w 0 invoice.png)
curl -X POST "https://apis.fotohub.app/v1/ai/document/detect-text" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d "{\"document\": \"$DOC_B64\"}" | jq '{text, usd_charged}'

# Or use a public URL directly
curl -X POST "https://apis.fotohub.app/v1/ai/document/detect-text" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"document_url": "https://storage.fotohub.app/docs/invoice.pdf"}'

Analyze Document (Tables + Forms)

Advanced analysis with table extraction, form key-value pairs, signature detection, and structural layout mapping.

Cost: $0.015 per page

Parameters

ParameterTypeRequiredDefaultDescription
documentstringYesBase64-encoded document (PDF/image), max 20MB
document_urlstringConditionalPublic URL alternative
featuresstring[]No["TABLES", "FORMS"]Features: "TABLES", "FORMS", "SIGNATURES", "LAYOUT", "CHECKBOXES"
pagesinteger[]NoallSpecific page numbers to analyze (1-indexed)
output_formatstringNo"json"Response format

Response

json
{
  "text": "Full text content of the document...",
  "lines": [
    { "text": "Invoice Number: FH-2026-1001", "confidence": 99.2, "page": 1 }
  ],
  "tables": [
    {
      "page": 1,
      "rows": [
        ["Item", "Quantity", "Unit Price", "Total"],
        ["Seedream Image Generation (1000 images)", "1", "$45.00", "$45.00"],
        ["Seedance Video Generation (50 clips)", "1", "$12.00", "$12.00"],
        ["Cloud Storage (50 GB/month)", "1", "$1.23", "$1.23"]
      ],
      "confidence": 98.7
    }
  ],
  "key_values": [
    { "key": "Invoice Number", "value": "FH-2026-1001", "confidence": 99.1 },
    { "key": "Date", "value": "2026-07-19", "confidence": 99.5 },
    { "key": "Customer", "value": "Acme Corporation", "confidence": 98.8 },
    { "key": "Due Date", "value": "2026-08-19", "confidence": 97.3 }
  ],
  "signatures": [],
  "checkboxes": [
    { "label": "I agree to Terms & Conditions", "checked": true, "confidence": 95.0 }
  ],
  "total_blocks": 142,
  "pages_processed": 1,
  "usd_charged": 0.015,
  "processing_ms": 1240
}

Code Examples

python
import base64
import httpx

api_key = "fh_live_your_api_key"

with open("form.pdf", "rb") as f:
    doc_b64 = base64.b64encode(f.read()).decode()

result = httpx.post(
    "https://apis.fotohub.app/v1/ai/document/analyze",
    headers={"Authorization": f"Bearer {api_key}"},
    json={
        "document": doc_b64,
        "features": ["TABLES", "FORMS", "SIGNATURES", "CHECKBOXES"]
    }
).json()

# Print extracted tables
for table in result["tables"]:
    print(f"Table on page {table['page']}:")
    for row in table["rows"]:
        print("  " + " | ".join(row))

# Print form fields
for kv in result["key_values"]:
    print(f"  {kv['key']}: {kv['value']} (confidence: {kv['confidence']:.1f}%)")

print(f"\nCost: ${result['usd_charged']:.4f}")
typescript
import fs from 'fs';

const doc = fs.readFileSync('form.pdf').toString('base64');

const result = await fetch('https://apis.fotohub.app/v1/ai/document/analyze', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer fh_live_your_api_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    document: doc,
    features: ['TABLES', 'FORMS', 'CHECKBOXES'],
  }),
}).then(r => r.json());

// Export tables as CSV-like structure
for (const table of result.tables) {
  console.log(`Table (page ${table.page}):`);
  for (const row of table.rows) {
    console.log(row.join('\t'));
  }
}
bash
DOC_B64=$(base64 -w 0 form.pdf)
curl -X POST "https://apis.fotohub.app/v1/ai/document/analyze" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d "{
    \"document\": \"$DOC_B64\",
    \"features\": [\"TABLES\", \"FORMS\", \"SIGNATURES\"]
  }" | jq '.key_values'

Analyze Expense (Invoice & Receipt Extraction)

Specialized extraction for invoices, receipts, and expense documents. Returns vendor info, line items, totals, tax, and dates in a richly structured format optimized for accounting workflows.

Cost: $0.012 per document

Parameters

ParameterTypeRequiredDescription
documentstringYesBase64-encoded invoice/receipt. Max 20MB.
document_urlstringConditionalPublic URL alternative to base64 upload
currency_hintstringNoISO 4217 currency code hint (e.g. "USD", "EUR")

Response

json
{
  "expenses": [
    {
      "summary": {
        "VENDOR_NAME": { "value": "Acme Cloud Services Inc.", "confidence": 98.7 },
        "VENDOR_ADDRESS": { "value": "123 Tech Drive, San Francisco, CA 94105", "confidence": 95.2 },
        "INVOICE_RECEIPT_DATE": { "value": "2026-07-19", "confidence": 99.1 },
        "DUE_DATE": { "value": "2026-08-19", "confidence": 97.5 },
        "INVOICE_RECEIPT_ID": { "value": "INV-2026-4821", "confidence": 99.3 },
        "TOTAL": { "value": "$142.50", "confidence": 99.5 },
        "TAX": { "value": "$12.50", "confidence": 98.2 },
        "SUBTOTAL": { "value": "$130.00", "confidence": 99.0 },
        "PAYMENT_TERMS": { "value": "Net 30", "confidence": 94.1 }
      },
      "line_items": [
        { "ITEM": "GPU Compute Hours (A10G, 4 hours)", "QUANTITY": "4", "UNIT_PRICE": "$2.50", "PRICE": "$10.00" },
        { "ITEM": "Image Generation API (2,000 images)", "QUANTITY": "1", "UNIT_PRICE": "$90.00", "PRICE": "$90.00" },
        { "ITEM": "S3 Storage (100 GB/month)", "QUANTITY": "1", "UNIT_PRICE": "$2.45", "PRICE": "$2.45" },
        { "ITEM": "Data Transfer (500 GB)", "QUANTITY": "1", "UNIT_PRICE": "$27.55", "PRICE": "$27.55" }
      ]
    }
  ],
  "document_count": 1,
  "usd_charged": 0.012,
  "processing_ms": 890
}

Code Examples

python
import base64
import httpx

api_key = "fh_live_your_api_key"

with open("invoice.jpg", "rb") as f:
    doc_b64 = base64.b64encode(f.read()).decode()

result = httpx.post(
    "https://apis.fotohub.app/v1/ai/document/analyze-expense",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"document": doc_b64, "currency_hint": "USD"}
).json()

for expense in result["expenses"]:
    summary = expense["summary"]
    print(f"Vendor: {summary['VENDOR_NAME']['value']}")
    print(f"Invoice: {summary['INVOICE_RECEIPT_ID']['value']}")
    print(f"Total: {summary['TOTAL']['value']}")
    print(f"Date: {summary['INVOICE_RECEIPT_DATE']['value']}")
    print("\nLine Items:")
    for item in expense["line_items"]:
        print(f"  {item.get('ITEM', '?')} × {item.get('QUANTITY', '1')} = {item.get('PRICE', '?')}")

print(f"\nExtraction cost: ${result['usd_charged']:.4f}")
typescript
import fs from 'fs';

const doc = fs.readFileSync('invoice.jpg').toString('base64');

const result = await fetch('https://apis.fotohub.app/v1/ai/document/analyze-expense', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer fh_live_your_api_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ document: doc, currency_hint: 'USD' }),
}).then(r => r.json());

// Map to a flat invoice object for ERP ingestion
const invoice = {
  vendor: result.expenses[0].summary.VENDOR_NAME.value,
  invoiceId: result.expenses[0].summary.INVOICE_RECEIPT_ID.value,
  date: result.expenses[0].summary.INVOICE_RECEIPT_DATE.value,
  total: result.expenses[0].summary.TOTAL.value,
  lineItems: result.expenses[0].line_items,
};

console.log(JSON.stringify(invoice, null, 2));
bash
DOC_B64=$(base64 -w 0 invoice.jpg)
curl -X POST "https://apis.fotohub.app/v1/ai/document/analyze-expense" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d "{\"document\": \"$DOC_B64\"}" | jq '.expenses[0].summary'

URL-Based Document Extraction

Extract text from a publicly accessible document URL without base64 encoding. Ideal for processing documents already stored in S3, Google Drive, or CDN.

Cost: $0.005 per page

POST /v1/documents/extract
Authorization: Bearer fh_live_your_api_key
Content-Type: application/json
json
{
  "url": "https://storage.fotohub.app/docs/contract.pdf",
  "output_format": "json",
  "include_layout": true,
  "pages": [1, 2, 3]
}
python
import httpx

result = httpx.post(
    "https://apis.fotohub.app/v1/documents/extract",
    headers={"Authorization": "Bearer fh_live_your_api_key"},
    json={
        "url": "https://storage.fotohub.app/docs/contract.pdf",
        "output_format": "json",
        "include_layout": True
    }
).json()

print(f"Extracted {result['pages_processed']} pages, ${result['usd_charged']:.4f} charged")
bash
curl -X POST "https://apis.fotohub.app/v1/documents/extract" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://storage.fotohub.app/docs/contract.pdf",
    "include_layout": true
  }' | jq '.text'

PII Redaction

Automatically detect and redact personally identifiable information from documents before storage or sharing.

Cost: $0.008 per page

PII Entity Types Supported

Entity TypeExamples
PERSONNames, titles
EMAIL[email protected]
PHONE+1-555-123-4567
SSN123-45-6789
CREDIT_CARD4111 1111 1111 1111
IBANDE89370400440532013000
DATE_OF_BIRTH15/03/1985
PASSPORTAB1234567
DRIVER_LICENSED1234567
IP_ADDRESS192.168.1.1
MEDICAL_IDPatient record numbers

Request

POST /v1/documents/redact
Authorization: Bearer fh_live_your_api_key
Content-Type: application/json
json
{
  "document_url": "https://storage.fotohub.app/docs/patient_record.pdf",
  "redact_entities": ["PERSON", "EMAIL", "PHONE", "SSN", "DATE_OF_BIRTH"],
  "redaction_style": "black_box",
  "output_format": "pdf"
}
ParameterTypeDefaultDescription
document_urlstringURL of document to redact
documentstringBase64-encoded alternative
redact_entitiesstring[]allEntity types to redact
redaction_stylestring"black_box""black_box", "white_box", "asterisks", "lorem"
output_formatstring"pdf"Output format: "pdf", "png", "json" (returns redacted text)
python
import httpx

result = httpx.post(
    "https://apis.fotohub.app/v1/documents/redact",
    headers={"Authorization": "Bearer fh_live_your_api_key"},
    json={
        "document_url": "https://storage.fotohub.app/docs/patient_record.pdf",
        "redact_entities": ["PERSON", "EMAIL", "SSN", "DATE_OF_BIRTH"],
        "redaction_style": "black_box",
        "output_format": "pdf"
    }
).json()

print(f"Redacted document URL: {result['redacted_url']}")
print(f"Entities found: {result['entities_found']}")
print(f"Cost: ${result['usd_charged']:.4f}")
bash
curl -X POST "https://apis.fotohub.app/v1/documents/redact" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "document_url": "https://storage.fotohub.app/docs/employee_form.pdf",
    "redact_entities": ["PERSON", "SSN", "EMAIL"],
    "redaction_style": "black_box"
  }' | jq '{redacted_url, entities_found, usd_charged}'

Document Classification

Automatically classify document type for routing and workflow automation.

Cost: $0.003 per document

Supported Document Categories

CategoryExamples
invoiceVendor invoices, purchase orders
receiptStore receipts, expense receipts
contractService agreements, NDAs, leases
id_cardDriver's license, passport, national ID
medical_recordLab results, prescriptions
bank_statementAccount statements, wire confirmations
tax_formW-2, 1099, VAT returns
shipping_labelFedEx, DHL, UPS labels
resumeCVs, resumes
otherUnrecognized document type
bash
curl -X POST "https://apis.fotohub.app/v1/documents/classify" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "document_url": "https://storage.fotohub.app/docs/unknown_doc.pdf"
  }'

Response:

json
{
  "category": "invoice",
  "confidence": 97.3,
  "subcategory": "vendor_invoice",
  "suggested_workflow": "accounts_payable",
  "usd_charged": 0.003
}

Batch Document Processing

Process multiple documents asynchronously. Returns a batch_id immediately; poll for completion.

Cost: $0.004 per document (base rate, operations add on top)

Submit Batch

POST /v1/documents/batch
Authorization: Bearer fh_live_your_api_key
Content-Type: application/json
json
{
  "documents": [
    { "url": "https://storage.fotohub.app/docs/invoice_001.pdf", "operation": "extract" },
    { "url": "https://storage.fotohub.app/docs/invoice_002.pdf", "operation": "extract" },
    { "url": "https://storage.fotohub.app/docs/contract.pdf", "operation": "analyze", "features": ["TABLES", "FORMS"] }
  ],
  "webhook_url": "https://api.yourapp.com/webhooks/fotohub",
  "webhook_secret": "whsec_your_secret",
  "output_destination": {
    "type": "s3",
    "bucket": "your-bucket",
    "prefix": "extracted-docs/",
    "region": "us-east-1"
  }
}

Response (202 Accepted):

json
{
  "batch_id": "batch_abc123xyz",
  "total_documents": 3,
  "estimated_completion_s": 45,
  "estimated_cost_usd": 0.037,
  "status": "queued"
}

Poll Batch Status

bash
curl "https://apis.fotohub.app/v1/documents/batch/batch_abc123xyz" \
  -H "Authorization: Bearer fh_live_your_api_key"
json
{
  "batch_id": "batch_abc123xyz",
  "status": "completed",
  "total": 3,
  "completed": 3,
  "failed": 0,
  "usd_charged": 0.037,
  "results": [
    {
      "document_url": "https://storage.fotohub.app/docs/invoice_001.pdf",
      "status": "success",
      "output_url": "s3://your-bucket/extracted-docs/invoice_001_result.json"
    },
    {
      "document_url": "https://storage.fotohub.app/docs/invoice_002.pdf",
      "status": "success",
      "output_url": "s3://your-bucket/extracted-docs/invoice_002_result.json"
    },
    {
      "document_url": "https://storage.fotohub.app/docs/contract.pdf",
      "status": "success",
      "output_url": "s3://your-bucket/extracted-docs/contract_result.json"
    }
  ]
}

Batch Processing in Python (50 Documents)

python
import asyncio
import httpx
import time

API_KEY = "fh_live_your_api_key"
BASE = "https://apis.fotohub.app"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

async def process_invoice_batch(invoice_urls: list[str]) -> dict:
    """Submit a batch of invoices and wait for completion."""
    async with httpx.AsyncClient() as client:
        # Submit batch
        batch_response = await client.post(
            f"{BASE}/v1/documents/batch",
            headers=HEADERS,
            json={
                "documents": [
                    {"url": url, "operation": "analyze-expense"}
                    for url in invoice_urls
                ],
                "webhook_url": "https://api.yourapp.com/webhooks/fotohub"
            }
        )
        batch = batch_response.json()
        batch_id = batch["batch_id"]
        print(f"Batch {batch_id} submitted: {len(invoice_urls)} documents, estimated ${batch['estimated_cost_usd']:.3f}")

        # Poll until complete
        while True:
            status_resp = await client.get(
                f"{BASE}/v1/documents/batch/{batch_id}",
                headers=HEADERS
            )
            status = status_resp.json()

            print(f"  Progress: {status['completed']}/{status['total']} ({status['status']})")

            if status["status"] in ("completed", "failed", "partial"):
                return status

            await asyncio.sleep(5)

# Process 50 invoices
invoice_urls = [f"https://storage.fotohub.app/invoices/inv_{i:03d}.pdf" for i in range(1, 51)]
result = asyncio.run(process_invoice_batch(invoice_urls))
print(f"\nDone: {result['completed']} processed, ${result['usd_charged']:.4f} charged")

AWS Textract Wrapper

For complex handwritten forms, ID cards, and specialized document types, the Textract endpoint provides AWS Textract's advanced analysis capabilities.

Cost: $0.015 per page

POST /v1/textract/analyze
Authorization: Bearer fh_live_your_api_key
Content-Type: application/json
json
{
  "document_url": "https://storage.fotohub.app/docs/handwritten_form.jpg",
  "feature_types": ["TABLES", "FORMS", "SIGNATURES"],
  "queries": [
    { "text": "What is the patient's date of birth?" },
    { "text": "What medications are listed?" }
  ]
}
python
import httpx

result = httpx.post(
    "https://apis.fotohub.app/v1/textract/analyze",
    headers={"Authorization": "Bearer fh_live_your_api_key"},
    json={
        "document_url": "https://storage.fotohub.app/docs/tax_form_w2.jpg",
        "feature_types": ["FORMS", "TABLES"],
        "queries": [
            {"text": "What is the employer EIN?"},
            {"text": "What is the federal income tax withheld?"}
        ]
    }
).json()

# Key-value pairs extracted
for kv in result.get("key_values", []):
    if kv["confidence"] > 90:
        print(f"  {kv['key']}: {kv['value']}")

print(f"\nCost: ${result['usd_charged']:.4f}")
bash
curl -X POST "https://apis.fotohub.app/v1/textract/analyze" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "document_url": "https://storage.fotohub.app/docs/medical_intake_form.jpg",
    "feature_types": ["FORMS", "SIGNATURES"]
  }' | jq '.key_values | map(select(.confidence > 90))'

Pricing Summary

OperationCostProvider Backend
OCR (detect-text)$0.005/pageVision LLM
Analyze (tables + forms)$0.015/pageAWS Textract
Analyze Expense (invoices)$0.012/documentAWS Textract
URL Extraction$0.005/pageVision LLM
PII Redaction$0.008/pageAWS Comprehend + Vision
Classification$0.003/documentClaude + Vision
Batch (base fee)$0.004/documentAsync queue
Textract Advanced$0.015/pageAWS Textract

Cost-Efficient Patterns

  • For plain text only: use detect-text ($0.005) not analyze ($0.015)
  • For high-volume batches: use POST /v1/documents/batch — it includes BYOB S3 delivery, saving egress fees
  • For simple invoices: analyze-expense at $0.012 often gives better results than general analyze at $0.015

Error Responses

HTTP StatusCodeDescription
400unsupported_formatDocument format not supported. Use PDF, JPEG, PNG, TIFF, WEBP, or DOCX.
400document_too_largeFile exceeds 20MB limit. Compress or split the document.
400too_many_pagesPDF has more than 500 pages. Split into multiple requests.
402INSUFFICIENT_FUNDSWallet balance insufficient for this operation. Top up at fotohub.app/console/billing.
422unreadable_documentDocument is corrupted, password-protected, or too low resolution (min 150 DPI).
429RATE_LIMIT_EXCEEDEDToo many document requests per minute. Implement exponential backoff.
503service_unavailableTemporary backend outage. Retry after 30 seconds.

INSUFFICIENT_FUNDS

If you see a 402 INSUFFICIENT_FUNDS error, your prepaid USD wallet balance is too low for the requested operation. Top up at fotohub.app/console/billing. There are no credits or subscription plans that can substitute for wallet balance.