Last updated: January 6

<span aria-hidden="true" id="lets-build-ai-invoice-parser-with-transloadit"></span>

# Let's Build: AI invoice parser with Transloadit

![Kevin van Zonneveld](/assets/images/teammates/avatar-kvz-4.jpg?dpl=dpl_AsMTCxwVXNuJ5TmdPevSCe63JuJo)

**Kevin van Zonneveld**

Co-founder · Amsterdam, The Netherlands · Show bio

[](https://x.com/kvz)[](https://github.com/kvz)

Invoices are a core workflow for finance teams, but extracting fields by hand is slow and error prone. In this Let’s Build, we’ll assemble a small invoice parsing service using Transloadit’s primitives: route files, normalize formats, and ask AI for structured JSON.

<span aria-hidden="true" id="what-were-building"></span>

## What we’re building

* Accept any invoice format (PDF, DOCX, image)
* Convert non-PDFs to PDF with [🤖 /document/convert](/docs/robots/document-convert.md)
* Extract structured fields with [🤖 /ai/chat](/docs/robots/ai-chat.md)

<span aria-hidden="true" id="schema-first-zod"></span>

## Schema first (zod)

We’ll use Zod to define the invoice schema and hand the JSON Schema to the AI step. This keeps the output predictable.

```ts
import { z } from 'zod'
import { zodToJsonSchema } from 'zod-to-json-schema'

const invoiceSchema = z.object({
  vendor_name: z.string().optional(),
  invoice_number: z.string().optional(),
  invoice_date: z.string().optional(),
  due_date: z.string().optional(),
  currency: z.string().optional(),
  subtotal: z.number().optional(),
  tax: z.number().optional(),
  total: z.number().optional(),
  line_items: z
    .array(
      z.object({
        description: z.string().optional(),
        quantity: z.number().optional(),
        unit_price: z.number().optional(),
        total: z.number().optional(),
      }),
    )
    .optional(),
})

const toJsonSchema = (schema: z.ZodTypeAny): unknown =>
  typeof (z as { toJSONSchema?: typeof zodToJsonSchema }).toJSONSchema === 'function'
    ? (z as { toJSONSchema: typeof zodToJsonSchema }).toJSONSchema(schema)
    : zodToJsonSchema(schema)

const invoiceJsonSchema = toJsonSchema(invoiceSchema)

```

<span aria-hidden="true" id="pipeline-overview"></span>

## Pipeline overview

```
PDF invoices ──▶ /ai/chat
Other docs  ──▶ /document/convert (pdf) ──▶ /ai/chat

```

<span aria-hidden="true" id="assembly-snippet"></span>

## Assembly snippet

```ts
const assembly = await transloadit.createAssembly({
  params: {
    steps: {
      pdf_verified: {
        robot: '/file/filter',
        use: ':original',
        accepts: [['${file.mime}', '==', 'application/pdf']],
      },
      non_pdf: {
        robot: '/file/filter',
        use: ':original',
        accepts: [['${file.mime}', '!=', 'application/pdf']],
      },
      pdf_converted: {
        robot: '/document/convert',
        use: 'non_pdf',
        format: 'pdf',
      },
      extract_invoice: {
        robot: '/ai/chat',
        use: ['pdf_verified', 'pdf_converted'],
        model: 'anthropic/claude-4-sonnet-20250514',
        format: 'json',
        schema: JSON.stringify(invoiceJsonSchema),
        messages: 'Extract invoice fields. Omit keys if unknown.',
        result: true,
      },
    },
  },
  files: {
    document: filePath,
  },
  waitForCompletion: true,
})

```

<span aria-hidden="true" id="try-the-example-app"></span>

## Try the example app

The runnable version of this post lives at `example_apps/invoice-parser/run.ts`.

```bash
node example_apps/invoice-parser/run.ts

```

<span aria-hidden="true" id="suggested-inputs-for-visuals"></span>

## Suggested inputs for visuals

Use the bundled samples or swap in your own invoice PDFs for screenshots:

* `_assets/demos/inputs/scan.pdf`
* `_assets/demos/inputs/first_document.pdf`
* `_assets/demos/inputs/second_document.pdf`

<span aria-hidden="true" id="next-steps"></span>

## Next steps

* Add multi-currency normalization in your application layer.
* Store results in your database and add human review queues.
* Expand the schema to support multiple vendors and locales.

[#letsbuild](/blog/tags/letsbuild.md)[#ai](/blog/tags/ai.md)[#document-processing-service](/blog/tags/document-processing-service.md)[#artificial-intelligence-service](/blog/tags/artificial-intelligence-service.md)[#developer-experience](/blog/tags/developer-experience.md)

### 👩‍💻 Join 20k+ developers

Sign up for our [monthly newsletter](/newsletters.md) to receive direct links to 3 exclusive tech — and 2 product updates. No less, no more.

Your email:

Get access

## File uploading and encoding. Made simple.

Transloadit streamlines file handling for developers, trusted by brands like Coursera and The New York Times. We’re known for a reliable API, top-notch support, and a strong commitment to open source, with projects like [Uppy⁠](https://uppy.io) and [Tus⁠](https://tus.io) setting standards in file processing.

[Sign up](/c/)[Book a Demo](https://survey.typeform.com/to/kRg47Xi5)

No credit card needed

Cancel anytime
