DEV Community

Mediavox
Mediavox

Posted on

Extracting structured data from invoices and contracts with one API call

Extracting structured data from invoices and contracts with one API call

I've been working on a document analysis API and wanted to share a pattern that saved me from writing custom parsers for every document type my clients throw at me.

The problem

If you work with LATAM businesses, you know the pain: invoices in PDF (sometimes scanned), contracts in Word, receipts as phone photos. Every client has a different format. Building regex parsers for each one is a nightmare that breaks every time the layout changes slightly.

The approach

Instead of building N parsers, I use a single multimodal AI endpoint that:

  1. Receives the file (PDF, image, DOCX — up to 20MB)
  2. Classifies the document type automatically
  3. Extracts named entities (vendor, amounts, dates, line items)
  4. Returns a structured JSON response
  5. Keeps a session open for follow-up questions

Code (Python)

import requests

# Upload and analyze in one call
with open("invoice.pdf", "rb") as f:
    response = requests.post(
        "https://mediavox.co/mvai/api/v1/documents/analyze",
        files={"file": f},
        data={
            "api_key": "your_key_here",
            "question": "Extract: vendor name, tax ID, invoice number, date, line items with quantities and prices, subtotal, tax, total."
        },
        timeout=60
    )

result = response.json()

print(result["answer"])       # Human-readable summary
print(result["entities"])     # Structured: [{type: "vendor", value: "..."}]
print(result["document_type"]) # "factura", "contrato", "recibo"...
print(result["session_id"])   # For follow-up questions
Enter fullscreen mode Exit fullscreen mode

Follow-up questions (same session)

The session persists the document context, so you can ask clarifying questions without re-uploading:

follow_up = requests.post(
    "https://mediavox.co/mvai/api/v1/chat",
    json={
        "api_key": "your_key_here",
        "question": "What are the payment terms?",
        "session_id": result["session_id"]
    }
)

print(follow_up.json()["answer"])
# "Payment terms: 30 days net. Due date: August 15, 2026."
Enter fullscreen mode Exit fullscreen mode

The AI answers from the document only — no hallucinations from external knowledge.

What I got from a real scanned receipt

Input: a crumpled photo of a Colombian restaurant receipt (low light, tilted)

{
  "document_type": "recibo",
  "entities": [
    {"type": "vendor", "value": "Restaurante El Portal", "confidence": 0.94},
    {"type": "tax_id", "value": "901234567-8", "confidence": 0.91},
    {"type": "total", "value": "98700", "confidence": 0.97},
    {"type": "tax", "value": "15800", "confidence": 0.89},
    {"type": "date", "value": "2026-06-28", "confidence": 0.95}
  ],
  "integrity": {
    "subtotal_matches_items": true,
    "tax_calculation_correct": true
  }
}
Enter fullscreen mode Exit fullscreen mode

The integrity check catches arithmetic mismatches automatically — useful for expense auditing.

n8n integration

If you use n8n, there's a community node (n8n-nodes-mediavox) that wraps all of this. Or use HTTP Request nodes directly — the API is straightforward REST.

I published a ready-to-use workflow template: Extract invoice details and ask follow-ups — import it and replace the file path.

When this works well

  • Invoices (any format from any LATAM country)
  • Contracts (extract parties, dates, clauses, amounts)
  • Medical documents (procedures, diagnoses, patient IDs)
  • Receipts and expense reports
  • Any document where you need structured data but can't predict the exact layout

Limitations (being honest)

  • Handwritten documents: accuracy drops to ~70%
  • Documents >50 pages: works but slower (20-30s)
  • Tables with merged cells: sometimes misaligns rows
  • Non-Spanish/English documents: not optimized yet

Try it

Free tier: 100 requests/month. Enough to test with real documents.


Built this for LATAM businesses dealing with messy paperwork. If you're processing documents in Spanish/Portuguese and tired of custom parsers, this might save you time.

Top comments (0)