Skip to main content

Installation

npm install parsefy zod
  • parsefy: Parsefy SDK for document extraction
  • zod: TypeScript-first schema validation library

Environment setup

Add your API key to .env.local:
PARSEFY_API_KEY=pk_your_api_key

Server Action

Create a server action to handle document extraction:
// app/actions/extract.ts
'use server';

import { Parsefy } from 'parsefy';
import * as z from 'zod';

const client = new Parsefy();

const invoiceSchema = z.object({
  invoice_number: z.string().describe('The invoice number'),
  date: z.string().describe('Invoice date'),
  total: z.number().describe('Total amount'),
  vendor: z.string().describe('Vendor name'),
  line_items: z.array(z.object({
    description: z.string(),
    quantity: z.number(),
    amount: z.number(),
  })).describe('Line items'),
});

export async function extractInvoice(formData: FormData) {
  const file = formData.get('file') as File;
  
  const { object, error } = await client.extract({
    file,
    schema: invoiceSchema,
  });

  if (error) {
    return { error: error.message };
  }

  return { data: object };
}

React component

Create a form component to upload documents:
// app/components/InvoiceUploader.tsx
'use client';

import { useState } from 'react';
import { extractInvoice } from '../actions/extract';

export function InvoiceUploader() {
  const [result, setResult] = useState<any>(null);
  const [loading, setLoading] = useState(false);

  async function handleSubmit(formData: FormData) {
    setLoading(true);
    const response = await extractInvoice(formData);
    setResult(response);
    setLoading(false);
  }

  return (
    <div>
      <form action={handleSubmit}>
        <input type="file" name="file" accept=".pdf,.docx" />
        <button type="submit" disabled={loading}>
          {loading ? 'Extracting...' : 'Extract'}
        </button>
      </form>
      
      {result?.data && (
        <pre>{JSON.stringify(result.data, null, 2)}</pre>
      )}
      
      {result?.error && (
        <p className="error">{result.error}</p>
      )}
    </div>
  );
}

API Route (alternative)

If you prefer API routes over server actions:
// app/api/extract/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Parsefy } from 'parsefy';
import * as z from 'zod';

const client = new Parsefy();

const invoiceSchema = z.object({
  invoice_number: z.string().describe('The invoice number'),
  date: z.string().describe('Invoice date'),
  total: z.number().describe('Total amount'),
});

export async function POST(request: NextRequest) {
  const formData = await request.formData();
  const file = formData.get('file') as File;

  const { object, error, metadata } = await client.extract({
    file,
    schema: invoiceSchema,
  });

  if (error) {
    return NextResponse.json({ error: error.message }, { status: 422 });
  }

  return NextResponse.json({ 
    data: object,
    credits: metadata.credits,
  });
}