Language

Invoice Parsing in Python — Extract Invoice & Receipt Data with One Endpoint

Skip the OCR pipeline. Add invoice parsing to your Python app with ten lines of code.

By Othmane M., founder of DocuParse API · Last reviewed: 2026-10-20

The guide

  1. 1

    Install the requests library

    One dependency is all you need:

    pip install requests
  2. 2

    Set your API key as an environment variable

    Never hardcode the key in your source code:

    export DOCUPARSE_API_KEY="dex_your_key_here"
  3. 3

    Submit the file and fetch the result

    POST the file to /api/v1/extract, then fetch the result from GET /api/v1/documents/{id}. The fetched data object has every field already named. On Starter and Pro you can skip polling: add a webhook in Dashboard → Settings and DocuParse API will POST the finished result to your endpoint.

    import os, time, requests
    
    API = "https://docuparseapi.com/api/v1"
    HEADERS = {"Authorization": f"Bearer {os.environ['DOCUPARSE_API_KEY']}"}
    
    def parse_document(path: str) -> dict:
        # 1. Submit
        with open(path, "rb") as f:
            submit = requests.post(f"{API}/extract", headers=HEADERS,
                                   files={"file": (os.path.basename(path), f)}, timeout=30).json()
        if not submit.get("success"):
            raise RuntimeError(f"[{submit['error']['code']}] {submit['error']['message']}")
    
        # 2. Fetch the result
        for _ in range(40):
            doc = requests.get(f"{API}/documents/{submit['document_id']}",
                               headers=HEADERS, timeout=30).json()
            if doc["status"] == "completed":
                return doc["data"]
            if doc["status"] == "failed":
                raise RuntimeError(f"Extraction failed: {submit['document_id']}")
            time.sleep(1.5)
        raise TimeoutError(submit["document_id"])
    
    data = parse_document("invoice.pdf")
    print(data["merchant"], data["total"], data["currency"])
    Need your API key first?
    20 free documents/month — no credit card
    Sign up — get a free API key
  4. 4

    Handle errors by error code

    parse_document raises with the error code from the submit step:

    try:
        data = parse_document("invoice.pdf")
    except RuntimeError as e:
        msg = str(e)
        if "LIMIT_EXCEEDED" in msg:
            print("Monthly limit reached")
        elif "UNSUPPORTED_FILE_TYPE" in msg:
            print("Use PDF, JPG, PNG or CSV")
        elif "Extraction failed" in msg:
            print("Try a cleaner scan")
  5. 5

    For async apps, use httpx

    If you're using FastAPI or asyncio, run the same two steps with httpx.AsyncClient:

    import asyncio, os
    import httpx
    
    API = "https://docuparseapi.com/api/v1"
    HEADERS = {"Authorization": f"Bearer {os.environ['DOCUPARSE_API_KEY']}"}
    
    async def parse_document_async(path: str) -> dict:
        async with httpx.AsyncClient(timeout=30) as client:
            # 1. Submit
            with open(path, "rb") as f:
                submit = (await client.post(f"{API}/extract", headers=HEADERS,
                                            files={"file": (os.path.basename(path), f.read())})).json()
            if not submit.get("success"):
                raise RuntimeError(f"[{submit['error']['code']}] {submit['error']['message']}")
    
            # 2. Fetch the result
            for _ in range(40):
                doc = (await client.get(f"{API}/documents/{submit['document_id']}", headers=HEADERS)).json()
                if doc["status"] == "completed":
                    return doc["data"]
                if doc["status"] == "failed":
                    raise RuntimeError(f"Extraction failed: {submit['document_id']}")
                await asyncio.sleep(1.5)
        raise TimeoutError(submit["document_id"])

Full working example

python
import os, time, requests

API = "https://docuparseapi.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['DOCUPARSE_API_KEY']}"}

def parse_document(path: str) -> dict:
    # 1. Submit
    with open(path, "rb") as f:
        submit = requests.post(f"{API}/extract", headers=HEADERS,
                               files={"file": (os.path.basename(path), f)}, timeout=30).json()
    if not submit.get("success"):
        raise RuntimeError(f"[{submit['error']['code']}] {submit['error']['message']}")

    # 2. Fetch the result
    for _ in range(40):
        doc = requests.get(f"{API}/documents/{submit['document_id']}",
                           headers=HEADERS, timeout=30).json()
        if doc["status"] == "completed":
            return doc["data"]
        if doc["status"] == "failed":
            raise RuntimeError(f"Extraction failed: {submit['document_id']}")
        time.sleep(1.5)
    raise TimeoutError(submit["document_id"])

data = parse_document("invoice.pdf")
print(data["merchant"], data["total"], data["currency"])

What gets extracted

FieldDescription
merchantThe vendor or store name
totalThe final charged amount including tax
subtotalThe pre-tax amount
taxThe tax amount charged
dateInvoice or transaction date (ISO 8601)
due_datePayment due date, or null if not present
invoice_idInvoice number or receipt ID from the document
currencyISO 4217 currency code (USD, EUR, GBP, etc.)
payment_methodCard type, cash, or other payment method
line_itemsArray of items with description, quantity, price, line_total, vat_rate

Common errors and fixes

MISSING_API_KEYAuthorization header missingAdd header: Authorization: Bearer YOUR_KEY
INVALID_API_KEYKey not recognisedCheck key in dashboard — regenerate if needed
LIMIT_EXCEEDEDMonthly document limit reachedUpgrade at docuparseapi.com/pricing
UNSUPPORTED_FILE_TYPEFile format not supportedUse PDF, JPG, PNG or CSV
FILE_TOO_LARGE_AUTHENTICATEDThe file is too largeCompress the image or split the PDF
TOO_MANY_PAGESMore than 20 pagesSplit the PDF into parts of up to 20 pages
EXTRACTION_FAILEDDocument could not be parsedTry a cleaner scan or different file

Ready to start?

20 documents a month free, with full API access. No credit card. Webhooks on Starter and Pro.

Sign up — get a free API key