Language

Invoice Parsing in Node.js — Receipt & Invoice Extraction for JavaScript Apps

One POST request. Clean JSON back. Works in Express, Next.js, or any Node.js environment.

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

The guide

  1. 1

    No install needed for Node 18+

    Node.js 18 has fetch, FormData and Blob built in.

  2. 2

    Set your API key as an environment variable

    Never put the key in client-side 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 poll GET /api/v1/documents/{id} until the status is completed. 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.

    const API = "https://docuparseapi.com/api/v1";
    const headers = { Authorization: `Bearer ${process.env.DOCUPARSE_API_KEY}` };
    
    async function parseDocument(fileBuffer, fileName) {
      // 1. Submit
      const form = new FormData();
      form.append("file", new Blob([fileBuffer]), fileName);
      const submit = await fetch(`${API}/extract`, { method: "POST", headers, body: form }).then((r) => r.json());
      if (!submit.success) throw new Error(`[${submit.error.code}] ${submit.error.message}`);
    
      // 2. Fetch the result
      for (let i = 0; i < 40; i++) {
        const doc = await fetch(`${API}/documents/${submit.document_id}`, { headers }).then((r) => r.json());
        if (doc.status === "completed") return doc.data;
        if (doc.status === "failed") throw new Error(`Extraction failed: ${submit.document_id}`);
        await new Promise((r) => setTimeout(r, 1500));
      }
      throw new Error(`Timed out: ${submit.document_id}`);
    }
    
    const data = await parseDocument(require("fs").readFileSync("invoice.pdf"), "invoice.pdf");
    console.log(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

    Read the JSON result

    Access fields directly on the fetched data object — no post-processing needed:

    const data = await parseDocument(require("fs").readFileSync("invoice.pdf"), "invoice.pdf");
    console.log(data.merchant);
    console.log(data.total);
    console.log(data.currency);
    console.log(data.line_items); // description, quantity, price, line_total, vat_rate
  5. 5

    Add a server-side proxy for browser apps

    Never call the DocuParse API from browser JavaScript — your key would be exposed. Use a Next.js route handler to proxy the request:

    // app/api/documents/parse/route.ts — keeps your API key on the server
    import { NextRequest, NextResponse } from "next/server";
    
    const API = "https://docuparseapi.com/api/v1";
    const headers = { Authorization: `Bearer ${process.env.DOCUPARSE_API_KEY}` };
    
    export async function POST(request: NextRequest) {
      const incoming = await request.formData();
      const upstream = new FormData();
      upstream.append("file", incoming.get("file") as File);
    
      const submit = await fetch(`${API}/extract`, { method: "POST", headers, body: upstream }).then((r) => r.json());
      if (!submit.success) return NextResponse.json(submit, { status: 400 });
    
      // Return the id now; the client polls GET /api/documents/[id] (which calls
      // GET ${API}/documents/{id}), or use a webhook on Starter and Pro.
      return NextResponse.json({ document_id: submit.document_id, status: submit.status });
    }

Full working example

javascript
const API = "https://docuparseapi.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.DOCUPARSE_API_KEY}` };

async function parseDocument(fileBuffer, fileName) {
  // 1. Submit
  const form = new FormData();
  form.append("file", new Blob([fileBuffer]), fileName);
  const submit = await fetch(`${API}/extract`, { method: "POST", headers, body: form }).then((r) => r.json());
  if (!submit.success) throw new Error(`[${submit.error.code}] ${submit.error.message}`);

  // 2. Fetch the result
  for (let i = 0; i < 40; i++) {
    const doc = await fetch(`${API}/documents/${submit.document_id}`, { headers }).then((r) => r.json());
    if (doc.status === "completed") return doc.data;
    if (doc.status === "failed") throw new Error(`Extraction failed: ${submit.document_id}`);
    await new Promise((r) => setTimeout(r, 1500));
  }
  throw new Error(`Timed out: ${submit.document_id}`);
}

const data = await parseDocument(require("fs").readFileSync("invoice.pdf"), "invoice.pdf");
console.log(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