>
Product Guide 01
Fintech AI

Document AI: How to Build It

A step-by-step guide to building a document AI product. Eight stages, the options at each one, exactly how each step connects to the next, real costs, and what breaks. Written for someone who has not built this before.

Verified September 2026Free · No signupOfficial sources only
BeginnerStart here. No prior knowledge assumed.

How to use this page

This page is different from the rest of this section. The modules explain how things work. The build sheets list what to buy. This page walks you through building one product, start to finish.

It is written for someone who has not built this before. Every step says what goes in, what comes out, and how to plug it into the next step.

If you want...Read...
To understand why document reading is hardthe Identity module
A full list of every tool, with pricesthe Identity Build Sheet
To build the thingthis page

Nothing here is secret. All of it is doable by two engineers in a few weeks. The hard part is not any single step. It is knowing which eight steps there are, and what to connect to what.

What Document AI actually is

Document AI takes a picture of a document and gives you back fields you can put in a database.

Picture of a PAN card goes in. Out comes: name, PAN number, date of birth, father's name. Each one with a score saying how sure the system is.

People also call it ICR, which stands for Intelligent Character Recognition. Older OCR read printed text. ICR is meant to also read handwriting and understand layout. In practice the words get used loosely and nobody minds.

What it is not:

  • It is not a decision. It reads a document. It does not tell you whether to open the account.
  • It is not verification. Reading "Rajesh Kumar" off a card does not prove Rajesh Kumar exists or that this is his card. That is a different product.
  • It is not one model. It is six or seven things in a row. This is the single biggest surprise for teams who thought they were buying an API.

Who buys it: banks, lenders, insurers, and anyone who currently has people typing things off scanned paper. The business case is almost always we have forty people doing data entry.

The whole journey, in one table

Here is the whole thing. Eight steps. Read this table once and the rest of the page is just detail.

#StepIn plain words
1Get the fileThe document arrives from somewhere.
2Check it is usableIs it too blurry to read? Find out before you pay to read it.
3Work out what it isPAN card? Bank statement? You cannot extract fields until you know.
4Read the textTurn pixels into words. This is the bit everyone calls "the OCR".
5Turn words into fieldsA pile of words is not data. Which word is the name?
6Check the fields are realDoes the PAN number pass its checksum? Does the date make sense?
7Accept, review or rejectSend the uncertain ones to a human.
8Keep the evidenceWhat you read, from which image, how sure you were, when.
Note

Steps 2, 6, 7 and 8 are the ones people skip. They are also the ones that decide whether this works in production or only in the demo. A team that builds steps 1, 3, 4 and 5 has built a demo. That is not an insult — it is just a much smaller thing than it looks.

Steps 3 and 4 are where the money goes. Steps 2, 6, 7 and 8 are where the product lives.

IntermediateBuild it. Pipelines, tools and working code.

Steps 1 and 2 — getting a usable file

Step 1 — Get the file

What it does: the document gets from the customer to your server.

OptionWhat it isEffortPick this when
A. Plain uploadA file input on a web page.HoursAlways start here. It works and it costs nothing.
B. Mobile SDK captureA vendor's camera component that guides the user and rejects bad shots on the phone.Days, plus a licenceConsumer app, high volume, and bad photos are killing you.
C. DigiLocker fetchThe customer consents and you receive the issued document directly.Weeks, needs approvalYou want a document that is already verified. Skips steps 2–6 entirely for supported documents.

What comes out: a file on disk or in object storage, plus an id.

Connect it to step 2: do not pass the file around. Save it once, give it an id, and pass the id. Every later step reads from storage using that id. If you pass image bytes between services you will run out of memory on the day someone uploads a 40 MB scan.

Watch out

Option C deserves more thought than it usually gets. If DigiLocker can give you the document directly, you are not reading a photograph of a PAN card — you are receiving the issued record. No blur, no glare, no OCR, no confidence score. Teams build the whole eight-step pipeline and only afterwards discover that a large share of their documents could have come down a route that skips six of the steps. Check what is available before you build.

Step 2 — Check it is usable

What it does: looks at the image and decides whether it is worth reading. Blurry, dark, cropped, upside down, or a photo of a screen.

OptionWhat it isRoughly costsPick this when
A. Simple mathsOpenCV. Measure blur, brightness and resolution with about thirty lines of code.FreeStart here. It catches most of the bad ones.
B. A small modelA trained classifier that scores image quality.Your own GPU timeSimple maths is passing things that later fail.
C. Skip itSend everything to the OCR and see what happens.You pay per page, so this is the expensive optionNever, once you are past a few hundred documents a day.
Python — step 2, the cheapest useful quality gate
import cv2

# This is the whole thing. It is not clever. It works.
def usable(path):
    img = cv2.imread(path)
    if img is None:
        return {"ok": False, "why": "not_an_image"}

    grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    h, w = grey.shape

    # Blur. Laplacian variance: sharp images have high variance, blurry ones low.
    blur = cv2.Laplacian(grey, cv2.CV_64F).var()

    # Brightness. A photo taken in the dark, or washed out by flash.
    bright = grey.mean()

    checks = {
        "too_small":  w < 800 or h < 500,
        "too_blurry": blur < 100,       # tune this on YOUR documents
        "too_dark":   bright < 50,
        "too_bright": bright > 205,
    }
    failed = [k for k, v in checks.items() if v]
    return {"ok": not failed, "why": failed,
            "blur": round(blur, 1), "brightness": round(bright, 1)}

# WHAT TO CHECK
# [ ] tune the thresholds on 200 of YOUR real documents, not on the numbers
#     above. A PAN card photographed indoors and a scanned bank statement have
#     completely different normal ranges
# [ ] tell the user WHICH check failed. "Please try again" makes people retry
#     the same bad photo. "Too dark - move to a window" gets you a good one
# [ ] let the user override after two failures and send it to human review.
#     A gate with no escape hatch becomes a customer who cannot open an account
# [ ] log the scores even when the image passes. When accuracy drops next month
#     you will want to know whether the images got worse

What comes out: a yes/no, and if no, which check failed.

Connect it to step 3: only files that pass go forward. Files that fail go back to the user with the specific reason. This is the cheapest step on the page and it removes more OCR cost than anything else you will do.

Steps 3 and 4 — what is it, and reading it

Step 3 — Work out what the document is

What it does: decides whether this is a PAN card, an Aadhaar, a passport, a salary slip or a bank statement.

You need this because step 4 and step 5 are different for each type. There is no general "read any document" that gives you clean fields.

OptionWhat it isRoughly costsPick this when
A. Ask the userA dropdown: "what are you uploading?"FreeStart here. Genuinely. Most products never need more.
B. Keyword rulesRun cheap OCR, look for giveaway words ("INCOME TAX DEPARTMENT", "Permanent Account Number").≈ $1.50 per 1,000 pagesYou have a few document types and they have distinctive text.
C. A classifier modelAzure or Google classify the document before reading it.≈ $3 per 1,000Many types, or documents arrive in bulk with no user to ask.
Note

Option A sounds lazy and is usually right. If the user is standing in your app uploading their PAN card, they know it is a PAN card. Asking costs nothing and is more accurate than any classifier. Save the classifier for post boxes and bulk scans, where there is no user to ask.

What comes out: a document type, and a confidence score if you used B or C.

Connect it to step 4: the document type chooses which reader you call. PAN and Aadhaar go to an identity-document API. A bank statement goes to a table extractor. Sending a bank statement to an ID reader gets you nothing useful and still bills you.

Step 4 — Read the text

What it does: turns the picture into words, with a position on the page and a confidence for each one.

OptionWhat it isRoughly costs per 1,000 pagesPick this when
A. Plain OCRAWS, Google or Azure. Just gives you words and boxes.≈ $1.50, all three within cents of each otherYou will do the field-finding yourself in step 5.
B. Identity-document APIAWS Textract AnalyzeID and equivalents. Knows what a passport and a driving licence look like.≈ $10–25ID documents specifically. It does steps 4 and 5 together.
C. Prebuilt or custom modelsAzure and Google models for invoices, receipts, and your own trained ones.Prebuilt ≈ $10, custom ≈ $30A document type with a stable layout and real volume.
D. Self-hostedPaddleOCR, docTR, Tesseract on your own machine.No per-page fee. You pay for CPU, and GPU if you use a vision modelData cannot leave your building, or volume is high enough that per-page pricing hurts.
Watch out

Plain OCR is a commodity. Do not spend a week choosing. AWS, Google and Azure price it at roughly $1.50 per 1,000 pages and match each other to the cent. Pick the one your infrastructure already uses. The interesting choice is B versus A-plus-your-own-step-5, and that is a build-versus-buy decision, not a vendor comparison.

What comes out: a list of text pieces. Each has the text, a box saying where it sat on the page, and a confidence between 0 and 1.

Connect it to step 5: this is the most important handoff on the page, so it has its own section below.

The wiring between step 4 and step 5

Most guides stop after "call the OCR API". That is where the actual work starts, so this is the part we are going to be precise about.

Step 4 gives you words. Step 5 needs to produce fields. The contract between them is where teams lose a fortnight.

The wiring — what step 4 hands to step 5, and what step 5 hands back
# STEP 4 GIVES YOU THIS. Every OCR engine returns roughly this shape, with
# different key names. Normalise to one shape IMMEDIATELY, in one small adapter
# per engine. Then nothing downstream knows or cares which engine you used --
# and swapping engines becomes a one-file change instead of a rewrite.

ocr_output = {
    "doc_id": "doc_8814",
    "engine": "textract-v1",          # keep this. You WILL need to know later.
    "pages": [{
        "page": 1,
        "words": [
            # text,            box (x, y, width, height as 0-1 fractions), score
            {"text": "INCOME",   "box": [0.10, 0.05, 0.08, 0.03], "score": 0.99},
            {"text": "TAX",      "box": [0.19, 0.05, 0.04, 0.03], "score": 0.99},
            {"text": "ABCDE1234F","box": [0.10, 0.44, 0.22, 0.04], "score": 0.97},
            {"text": "RAJESH",   "box": [0.10, 0.52, 0.12, 0.03], "score": 0.94},
            {"text": "KUMAR",    "box": [0.23, 0.52, 0.11, 0.03], "score": 0.95},
        ],
    }],
}

# STEP 5 MUST GIVE YOU THIS. Note what is carried through: the score, and WHERE
# on the page it came from. Without those two, steps 6, 7 and 8 cannot work.

fields_output = {
    "doc_id": "doc_8814",
    "doc_type": "pan_card",
    "fields": {
        "pan":  {"value": "ABCDE1234F", "score": 0.97,
                 "source": {"page": 1, "box": [0.10, 0.44, 0.22, 0.04]}},
        "name": {"value": "RAJESH KUMAR", "score": 0.94,   # LOWEST of its words
                 "source": {"page": 1, "box": [0.10, 0.52, 0.24, 0.03]}},
    },
    "missing": ["father_name", "dob"],      # ALWAYS list what you did not find
}

# WHAT TO CHECK
# [ ] boxes as fractions of the page (0-1), never pixels. Pixels break the
#     moment someone uploads the same document at a different resolution
# [ ] a joined field takes the LOWEST score of its parts, not the average.
#     "RAJESH" at 0.99 and "KUMAR" at 0.60 is a 0.60 name, not a 0.80 one.
#     Averaging confidence is how bad reads get through
# [ ] "missing" is a real list, not an absence of keys. "We could not find the
#     date of birth" and "we never looked for it" are different facts
# [ ] keep the box. When a human reviews this in step 7, you want to highlight
#     the exact spot on the image. Reviewers go three to five times faster when
#     they can see where the value came from
# [ ] keep the engine name and its version. When accuracy shifts next quarter,
#     the first question is whether the vendor changed the model
# [ ] normalise every engine into this ONE shape in an adapter. Do not let
#     Textract's key names leak into your database

The rule underneath all of that: carry the confidence and the position all the way through. They feel like debugging information at step 5. By step 7 they are the product, and by step 8 they are your evidence.

Steps 5 and 6 — fields, and checking them

Step 5 — Turn words into fields

What it does: decides which of those words is the name, which is the PAN number, which is the date of birth.

OptionWhat it isRoughly costsPick this when
A. Position rulesOn a PAN card the number is always in the same place. Take whatever text sits in that box.FreeFixed-layout documents. Fast, free, and completely predictable.
B. Label matchingFind the word "Name", take what is to the right of it.FreeForms with printed labels. Handles small layout shifts.
C. Pattern matchingA PAN is five letters, four digits, one letter. Find anything that matches.FreeFields with a strict format. Combine with A or B.
D. Let the API do itYou picked option B in step 4, so fields come back already extracted.Included in the $10–25ID documents. Least code by a distance.
E. Ask a language modelGive the model the OCR text and ask for JSON.Per token, so it dependsMessy or varied layouts where A, B and C all fail.
Watch out

Option E has a trap. A language model will happily invent a plausible date of birth if the OCR did not read one. You asked for JSON with a dob field and it will give you a dob field. Two rules if you use it: pass only the OCR text and never the image description, and then check every returned value actually appears in the OCR output. If the model returns something the OCR never read, throw it away and mark the field missing. This is the same rule as the refusal gate in Build Sheet 06 — the value must be present in the retrieved text, not merely plausible.

Connect it to step 6: pass the whole field object, with scores and boxes. Do not flatten it to plain strings here. Step 6 needs the scores and step 7 needs the boxes.

Step 6 — Check the fields are real

What it does: catches wrong values that the OCR was confident about. This is the step that separates a demo from a product.

A confidence score tells you how clearly the system saw the characters. It does not tell you whether the answer is right. An OCR engine can read a smudged 8 as a 3 with 0.98 confidence.

CheckWhat it catchesCosts
FormatA PAN that is not five letters, four digits, one letter. An eleven-digit phone number.Free
ChecksumAadhaar has a check digit. So do IFSC and GSTIN and many others. A single misread character fails it.Free
Cross-fieldDate of birth after today. Issue date after expiry date. Age of four on a PAN card.Free
Against the sourceAsk the issuing authority whether this number exists and matches this name.Per lookup, varies by provider
Note

The first three are free and catch most of it. Do all three before you spend money on the fourth. A field that fails a checksum does not need a paid lookup to tell you it is wrong — and sending it anyway is a cost you can remove on your first afternoon.

Connect it to step 7: each field now carries both a confidence and a validation result. Step 7 needs both, and they disagree more often than you would expect. A field can be read clearly and still be wrong; a field can be read poorly and still be correct.

Steps 7 and 8 — deciding, and keeping proof

Step 7 — Accept, review or reject

What it does: turns scores and checks into an actual decision about this document.

Python — step 7, deciding what to do with each document
# Three outcomes. Never two. A system with only accept and reject will either
# reject good customers or accept bad data, and usually both.

def decide(fields, doc_type, rules):
    hard_fail, weak = [], []

    for name, f in fields.items():
        if name in rules["required"][doc_type]:
            if f["value"] is None:
                hard_fail.append((name, "missing"))
                continue
            if not f["valid"]:                    # from step 6
                hard_fail.append((name, f["invalid_reason"]))
                continue
            if f["score"] < rules["min_score"].get(name, 0.90):
                weak.append((name, f["score"]))

    # A failed CHECKSUM is different from a LOW SCORE. The first means the value
    # is wrong. The second means we are unsure. Do not merge them into one
    # "confidence" number -- you lose the ability to tell the user which it was.
    if hard_fail:
        return {"outcome": "review", "reason": "failed_validation",
                "detail": hard_fail, "show_boxes": True}
    if weak:
        return {"outcome": "review", "reason": "low_confidence",
                "detail": weak, "show_boxes": True}
    return {"outcome": "accept"}

# WHAT TO CHECK
# [ ] "reject" is almost never the right automatic outcome for a document that
#     a real customer uploaded. Route to REVIEW. Let a person reject
# [ ] the review screen shows the image with the box drawn on it, next to the
#     extracted value, in one editable field. Reviewers go 3-5x faster
# [ ] thresholds live in config, are versioned, and are approved. Changing a
#     threshold changes who gets accepted -- treat it as a control change
# [ ] measure the review queue every week. If it is growing faster than volume,
#     something upstream broke and nobody noticed
# [ ] measure the OVERRIDE RATE. If humans accept 95% of what you send them,
#     your thresholds are too tight and you are paying people to click yes
# [ ] every correction a reviewer makes is training data and a bug report.
#     Store the before and after. This is the highest-value data you will
#     generate and most teams throw it away

Connect it to step 8: the decision, the reason and the reviewer's edits all go into the record. Especially the edits.

Step 8 — Keep the evidence

What it does: stores what happened, so that in two years you can answer "why did you accept this document?"

This is the step that gets left until last and then never gets built. It is also the one that regulators and auditors ask about first.

StoreWhy
The original imageEverything else is a claim about it.
The full OCR outputSo you can re-run step 5 later without paying for step 4 again.
The extracted fields, with scores and boxesWhat you believed, and how sure you were.
Which engine and which versionWhen accuracy shifts, this is the first thing you check.
Which thresholds were in forceThe rules change. The record must say which rules applied that day.
The decision, and who made itAutomatic, or a named reviewer.
Every correction a human madeYour best training data and your best bug report.
Watch out

Store the record append-only. A correction is a new row, never an edit to the old one. The question is not only “what do we believe now” but “what did we believe on the day we opened the account”, and an updated row cannot answer the second one.

What it costs

Document AI — what it costs per 1,000 pages

Verified May 2026
Quality gate (step 2)oss
Free. OpenCV, thirty lines. Removes more OCR spend than any other decision here.
Classification (step 3)direct
Free if you ask the user. ≈ $3 per 1,000 for a cloud classifier. ≈ $1.50 if you classify by running plain OCR and keyword matching.
Plain OCR (step 4)direct
≈ $1.50 per 1,000 pages on AWS, Google and Azure — matching to the cent. Falls to ≈ $0.60 at high volume (above roughly 1M/month on Azure, 5M on Google). Price is not a reason to choose between them.
Identity-document API (step 4+5)direct
AWS Textract AnalyzeID and equivalents: ≈ $10–25 per 1,000. Does the reading and the field extraction together for ID documents.
Prebuilt and custom modelsdirect
Prebuilt ≈ $10 per 1,000. Custom extraction ≈ $30 per 1,000 on both Azure and Google.
Forms and tablesdirect
AWS Textract: tables ≈ $15, forms ≈ $50, forms+tables+queries ≈ $65–70 per 1,000. The wrong tool for an ID card — this is for bank statements and application forms.
Self-hosted (step 4)oss
No per-page fee. PaddleOCR, docTR, Tesseract. You pay for CPU, and GPU if you use a vision model. Check the licence of every model you pull — some are research-only.
Human review (step 7)direct
The line that decides your business case. A reviewer costs the same whether the document was cheap or expensive to read. If 30% of documents go to review, your real cost per document is dominated by people, not by API calls.
Where to buy these: Identity Onboarding Build Sheet names every tool with its unit cost. Getting Access covers which ones you can sign up for today, which need a sales call, and which are licensed.
Watch out

Features stack, and one document can hit several meters. A non-standard document typically runs a classifier (≈$3) and then custom extraction (≈$30), so the real cost is the sum of every model that fires — not a single headline rate. This is the most common mistake in a document-AI cost estimate.

Note

Two more things that quietly distort estimates. Google bills roughly $0.05 an hour per deployed custom processor version — about $438 a year whether or not you send it any traffic. And multi-page documents bill page by page, so a 40-page file is 40 billable pages even if you only need page one.

These figures were verified in May 2026 for Build Sheet 01 and are carried here unchanged. Cloud pricing moves. Check the vendor's calculator before you commit to a number in a business case.

AdvancedShip it. Failure modes, thresholds and evidence.

Three versions you could build

The weekend version

Build: upload form → OpenCV quality check → ask the user what the document is → Textract AnalyzeID → format and checksum validation → anything uncertain goes to a spreadsheet a person looks at → store everything in one Postgres table.

You get: a working product. Genuinely. Two engineers, one weekend, and it handles real documents.

It breaks when: volume passes a few hundred a day, or the review spreadsheet gets more than one person using it.

The proper version — start here if you are serious

Build: everything above, plus — a real review interface that draws the box on the image → one adapter per OCR engine so you can switch → thresholds in versioned config → an append-only evidence table → corrections captured as training data → weekly numbers on queue size and override rate.

You get: something you can run a business on and show an auditor.

Cost shape: the API bill is small. The reviewers are the cost.

It breaks when: nothing, for a long time. This is the right build for almost everyone.

The enterprise version

Build: everything above, plus — self-hosted OCR for data that cannot leave your building → custom models per document type → a routing layer that picks the cheapest engine that will work → full audit and model governance.

Use when: millions of documents, or a data-residency rule that rules out the cloud APIs.

It breaks when: you build it too early. Most teams that start here spend six months and end up with the proper version anyway, having paid for the detour.

Note

If you take one thing from this page: build the weekend version first, this week. Run 200 real documents through it. What you learn in those 200 documents will change your design more than any amount of planning, and you will have thrown away almost nothing.

What goes wrong

Ranked by how often we see them, not by how serious they are.

What goes wrongWhyFix
High confidence, wrong valueConfidence measures how clearly the characters were seen, not whether the answer is right.Step 6. Checksums and format rules, always, even on 0.99 fields.
Review queue quietly growsSomething upstream changed — a new phone camera, a redesigned document, a vendor model update.Chart queue size weekly. A rising line is always upstream.
The cost is triple the estimateFeatures stacked. Classifier plus custom extraction plus tables, all on one document.Add up every meter that fires, per document type.
Averaged confidence hides a bad readA name joined from two words took the mean instead of the minimum.Lowest score wins on any joined field.
The model invented a fieldA language model was asked for JSON and filled in a blank.Check every value appears in the OCR text. If not, mark it missing.
Cannot explain a decision from last yearThe record was updated in place, or the thresholds were never stored.Append-only, with the threshold version on every row.
Works in the demo, fails in the appDemo used clean scans. Real users send photos at night, at an angle, with a thumb over the corner.Step 2, and test on photos your own team took on their own phones.

Where to go next

This page covered one product. The same eight-step shape appears in others, and once you have built this you will recognise it.

Watch out

This page is a guide, not a specification. Document AI inside a regulated process carries KYC, record-keeping and data-protection obligations. Nothing here is legal advice. Have your retention, consent and review process checked by someone qualified before real customer documents go through it.

Sources

Every figure, rule and date on this page, and where to check it. Entries are typed so you can see which numbers are primary-sourced and which are industry reporting — they are not equivalent, and treating them as if they were is how a confident wrong number gets repeated.

  1. vendorAWS Textract pricing — plain OCR, AnalyzeID, tables, forms and queries, and the high-volume tiering. aws.amazon.com
  2. vendorAzure AI Document Intelligence pricing — prebuilt and custom extraction rates, and the volume tiers. azure.microsoft.com
  3. vendorGoogle Document AI pricing — processor rates, the per-hour deployed custom processor charge, and per-page billing on multi-page files. cloud.google.com
  4. officialDigiLocker — the issued-document route that skips most of the pipeline for supported documents. www.digilocker.gov.in
  5. officialIncome Tax Department — PAN — the PAN format used in the validation step. www.incometax.gov.in
  6. industryOpen-source OCR projects — PaddleOCR, docTR and Tesseract, and the licence check required on any model pulled with them.

Checked September 2026. Pricing and draft regulation move; the date is part of the claim.

Ask an AI about this page

Opens your assistant with this page as the source, and a question rather than a summary. It will ask what you are building before it answers.

Nothing is sent from here. The link carries only this page’s title and address.