From PDF Invoices to Formatted Spreadsheets in Two API Calls

6 min read Sheet Generation

The Invoice Spreadsheet Problem

Every accounting team has the same workflow. Invoices arrive as PDFs — from vendors, contractors, service providers. Someone needs to get that data into a spreadsheet for reconciliation, approval, or import into accounting software.

The manual version: open the PDF, copy the line items, paste into Excel, fix the formatting, repeat for the next invoice. The automated version usually involves an OCR service, a pile of regex to parse the output, and a separate process to generate the spreadsheet. Two different systems, two different failure modes, and a lot of glue code in between.

The core problem is the gap between extraction and generation. You get structured data out of a document, but then you need to transform it into a completely different format using a completely different tool. That’s where the bugs live.

Extract Then Generate

The Document Extraction API and the Sheet Generation API are designed to compose. The extraction output — structured JSON with typed fields — maps directly to sheet rows. No intermediate transformation layer, no format juggling.

Here’s the full pipeline: PDF in, formatted XLSX out.

Step 1: Define the Extraction Schema

First, tell the Document Extraction API what fields to look for in your invoice. The schema describes the structure you expect.

{
  "vendor_name": {
    "type": "text"
  },
  "invoice_number": {
    "type": "text"
  },
  "invoice_date": {
    "type": "date"
  },
  "due_date": {
    "type": "date"
  },
  "line_items": {
    "type": "array",
    "items": {
      "description": {
        "type": "text"
      },
      "quantity": {
        "type": "number"
      },
      "unit_price": {
        "type": "currency"
      },
      "total": {
        "type": "currency"
      }
    }
  },
  "subtotal": {
    "type": "currency"
  },
  "tax": {
    "type": "currency"
  },
  "total_due": {
    "type": "currency"
  }
}

Step 2: Extract the Invoice Data

Send the PDF to the extraction endpoint with your schema. The API returns structured JSON with typed values and confidence scores.

Request
curl -X POST https://api.iterationlayer.com/document-extraction/v1/extract \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file": "'"$INVOICE_PDF_BASE64"'",
    "schema": {
      "vendor_name": {
        "type": "text"
      },
      "invoice_number": {
        "type": "text"
      },
      "invoice_date": {
        "type": "date"
      },
      "due_date": {
        "type": "date"
      },
      "line_items": {
        "type": "array",
        "items": {
          "description": {
            "type": "text"
          },
          "quantity": {
            "type": "number"
          },
          "unit_price": {
            "type": "currency"
          },
          "total": {
            "type": "currency"
          }
        }
      },
      "subtotal": {
        "type": "currency"
      },
      "tax": {
        "type": "currency"
      },
      "total_due": {
        "type": "currency"
      }
    }
  }'
Response
{
  "success": true,
  "data": {
    "fields": {
      "vendor_name": {
        "value": "Acme Services LLC",
        "confidence": 0.97
      },
      "invoice_number": {
        "value": "INV-2026-0042",
        "confidence": 0.99
      },
      "invoice_date": {
        "value": "2026-03-15",
        "confidence": 0.95
      },
      "due_date": {
        "value": "2026-04-14",
        "confidence": 0.94
      },
      "line_items": {
        "value": [
          {
            "description": {
              "value": "Consulting services",
              "confidence": 0.96
            },
            "quantity": {
              "value": 40,
              "confidence": 0.98
            },
            "unit_price": {
              "value": 150.00,
              "confidence": 0.97
            },
            "total": {
              "value": 6000.00,
              "confidence": 0.97
            }
          }
        ],
        "confidence": 0.96
      },
      "subtotal": {
        "value": 6000.00,
        "confidence": 0.97
      },
      "tax": {
        "value": 495.00,
        "confidence": 0.95
      },
      "total_due": {
        "value": 6495.00,
        "confidence": 0.98
      }
    }
  }
}
Request
import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
  apiKey: "YOUR_API_KEY",
});

const extractionResult = await client.extract({
  file: invoiceBase64,
  schema: {
    vendor_name: {
      type: "text",
    },
    invoice_number: {
      type: "text",
    },
    invoice_date: {
      type: "date",
    },
    due_date: {
      type: "date",
    },
    line_items: {
      type: "array",
      items: {
        description: {
          type: "text",
        },
        quantity: {
          type: "number",
        },
        unit_price: {
          type: "currency",
        },
        total: {
          type: "currency",
        },
      },
    },
    subtotal: {
      type: "currency",
    },
    tax: {
      type: "currency",
    },
    total_due: {
      type: "currency",
    },
  },
});

const fields = extractionResult.data.fields;
Response
{
  "success": true,
  "data": {
    "fields": {
      "vendor_name": {
        "value": "Acme Services LLC",
        "confidence": 0.97
      },
      "invoice_number": {
        "value": "INV-2026-0042",
        "confidence": 0.99
      },
      "invoice_date": {
        "value": "2026-03-15",
        "confidence": 0.95
      },
      "due_date": {
        "value": "2026-04-14",
        "confidence": 0.94
      },
      "line_items": {
        "value": [
          {
            "description": {
              "value": "Consulting services",
              "confidence": 0.96
            },
            "quantity": {
              "value": 40,
              "confidence": 0.98
            },
            "unit_price": {
              "value": 150.00,
              "confidence": 0.97
            },
            "total": {
              "value": 6000.00,
              "confidence": 0.97
            }
          }
        ],
        "confidence": 0.96
      },
      "subtotal": {
        "value": 6000.00,
        "confidence": 0.97
      },
      "tax": {
        "value": 495.00,
        "confidence": 0.95
      },
      "total_due": {
        "value": 6495.00,
        "confidence": 0.98
      }
    }
  }
}
Request
from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")

extraction_result = client.extract(
    file=invoice_base64,
    schema={
        "vendor_name": {
            "type": "text",
        },
        "invoice_number": {
            "type": "text",
        },
        "invoice_date": {
            "type": "date",
        },
        "due_date": {
            "type": "date",
        },
        "line_items": {
            "type": "array",
            "items": {
                "description": {
                    "type": "text",
                },
                "quantity": {
                    "type": "number",
                },
                "unit_price": {
                    "type": "currency",
                },
                "total": {
                    "type": "currency",
                },
            },
        },
        "subtotal": {
            "type": "currency",
        },
        "tax": {
            "type": "currency",
        },
        "total_due": {
            "type": "currency",
        },
    },
)

fields = extraction_result.data.fields
Response
{
  "success": true,
  "data": {
    "fields": {
      "vendor_name": {
        "value": "Acme Services LLC",
        "confidence": 0.97
      },
      "invoice_number": {
        "value": "INV-2026-0042",
        "confidence": 0.99
      },
      "invoice_date": {
        "value": "2026-03-15",
        "confidence": 0.95
      },
      "due_date": {
        "value": "2026-04-14",
        "confidence": 0.94
      },
      "line_items": {
        "value": [
          {
            "description": {
              "value": "Consulting services",
              "confidence": 0.96
            },
            "quantity": {
              "value": 40,
              "confidence": 0.98
            },
            "unit_price": {
              "value": 150.00,
              "confidence": 0.97
            },
            "total": {
              "value": 6000.00,
              "confidence": 0.97
            }
          }
        ],
        "confidence": 0.96
      },
      "subtotal": {
        "value": 6000.00,
        "confidence": 0.97
      },
      "tax": {
        "value": 495.00,
        "confidence": 0.95
      },
      "total_due": {
        "value": 6495.00,
        "confidence": 0.98
      }
    }
  }
}
Request
package main

import il "github.com/iterationlayer/sdk-go"

func main() {
    client := il.NewClient("YOUR_API_KEY")

    extractionResult, err := client.Extract(il.ExtractRequest{
        File: invoiceBase64,
        Schema: map[string]il.SchemaField{
            "vendor_name": {
                Type: "text",
            },
            "invoice_number": {
                Type: "text",
            },
            "invoice_date": {
                Type: "date",
            },
            "due_date": {
                Type: "date",
            },
            "line_items": {
                Type: "array",
                Items: map[string]il.SchemaField{
                    "description": {
                        Type: "text",
                    },
                    "quantity": {
                        Type: "number",
                    },
                    "unit_price": {
                        Type: "currency",
                    },
                    "total": {
                        Type: "currency",
                    },
                },
            },
            "subtotal": {
                Type: "currency",
            },
            "tax": {
                Type: "currency",
            },
            "total_due": {
                Type: "currency",
            },
        },
    })
    if err != nil {
        panic(err)
    }

    fields := extractionResult.Data.Fields
    _ = fields
}
Response
{
  "success": true,
  "data": {
    "fields": {
      "vendor_name": {
        "value": "Acme Services LLC",
        "confidence": 0.97
      },
      "invoice_number": {
        "value": "INV-2026-0042",
        "confidence": 0.99
      },
      "invoice_date": {
        "value": "2026-03-15",
        "confidence": 0.95
      },
      "due_date": {
        "value": "2026-04-14",
        "confidence": 0.94
      },
      "line_items": {
        "value": [
          {
            "description": {
              "value": "Consulting services",
              "confidence": 0.96
            },
            "quantity": {
              "value": 40,
              "confidence": 0.98
            },
            "unit_price": {
              "value": 150.00,
              "confidence": 0.97
            },
            "total": {
              "value": 6000.00,
              "confidence": 0.97
            }
          }
        ],
        "confidence": 0.96
      },
      "subtotal": {
        "value": 6000.00,
        "confidence": 0.97
      },
      "tax": {
        "value": 495.00,
        "confidence": 0.95
      },
      "total_due": {
        "value": 6495.00,
        "confidence": 0.98
      }
    }
  }
}

The extraction result gives you typed fields: fields.vendor_name.value is a string, fields.line_items.value is an array, fields.total_due.value is a number. Each field also carries a confidence score so you can flag low-confidence extractions for review.

Step 3: Build the Spreadsheet

Map the extracted data directly into the sheet generation payload. The line items become rows. The invoice metadata goes into a header section.

Request
curl -X POST https://api.iterationlayer.com/sheet-generation/v1/generate \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "xlsx",
    "styles": {
      "header": {
        "is_bold": true,
        "background_color": "#2d3748",
        "font_color": "#ffffff"
      },
      "body": {
        "font_size_in_pt": 10
      }
    },
    "sheets": [
      {
        "name": "Invoice INV-2026-0042",
        "columns": [
          {
            "name": "Description",
            "width": 35
          },
          {
            "name": "Quantity",
            "width": 12
          },
          {
            "name": "Unit Price",
            "width": 16
          },
          {
            "name": "Total",
            "width": 16
          }
        ],
        "rows": [
          [
            {
              "value": "Consulting services"
            },
            {
              "value": 40,
              "format": "number"
            },
            {
              "value": 150.00,
              "format": "currency",
              "currency_code": "USD"
            },
            {
              "value": 6000.00,
              "format": "currency",
              "currency_code": "USD"
            }
          ],
          [
            {
              "value": "Subtotal",
              "styles": {
                "is_bold": true
              }
            },
            {
              "value": null
            },
            {
              "value": null
            },
            {
              "value": 6000.00,
              "format": "currency",
              "currency_code": "USD"
            }
          ],
          [
            {
              "value": "Tax",
              "styles": {
                "is_bold": true
              }
            },
            {
              "value": null
            },
            {
              "value": null
            },
            {
              "value": 495.00,
              "format": "currency",
              "currency_code": "USD"
            }
          ],
          [
            {
              "value": "Total Due",
              "styles": {
                "is_bold": true,
                "font_size_in_pt": 12
              }
            },
            {
              "value": null
            },
            {
              "value": null
            },
            {
              "value": 6495.00,
              "format": "currency",
              "currency_code": "USD",
              "styles": {
                "is_bold": true,
                "font_size_in_pt": 12
              }
            }
          ]
        ]
      }
    ]
  }'
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
  apiKey: "YOUR_API_KEY",
});

const lineItemRows = fields.line_items.value.map((item) => [
  {
    value: item.description.value,
  },
  {
    value: item.quantity.value,
    format: "number",
  },
  {
    value: item.unit_price.value,
    format: "currency",
    currency_code: "USD",
  },
  {
    value: item.total.value,
    format: "currency",
    currency_code: "USD",
  },
]);

const summaryRows = [
  [
    {
      value: "Subtotal",
      styles: {
        is_bold: true,
      },
    },
    {
      value: null,
    },
    {
      value: null,
    },
    {
      value: fields.subtotal.value,
      format: "currency",
      currency_code: "USD",
    },
  ],
  [
    {
      value: "Tax",
      styles: {
        is_bold: true,
      },
    },
    {
      value: null,
    },
    {
      value: null,
    },
    {
      value: fields.tax.value,
      format: "currency",
      currency_code: "USD",
    },
  ],
  [
    {
      value: "Total Due",
      styles: {
        is_bold: true,
        font_size_in_pt: 12,
      },
    },
    {
      value: null,
    },
    {
      value: null,
    },
    {
      value: fields.total_due.value,
      format: "currency",
      currency_code: "USD",
      styles: {
        is_bold: true,
        font_size_in_pt: 12,
      },
    },
  ],
];

const sheetResult = await client.generateSheet({
  format: "xlsx",
  styles: {
    header: {
      is_bold: true,
      background_color: "#2d3748",
      font_color: "#ffffff",
    },
    body: {
      font_size_in_pt: 10,
    },
  },
  sheets: [
    {
      name: `Invoice ${fields.invoice_number.value}`,
      columns: [
        {
          name: "Description",
          width: 35,
        },
        {
          name: "Quantity",
          width: 12,
        },
        {
          name: "Unit Price",
          width: 16,
        },
        {
          name: "Total",
          width: 16,
        },
      ],
      rows: [...lineItemRows, ...summaryRows],
    },
  ],
});
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")

line_item_rows = [
    [
        {
            "value": item.description.value,
        },
        {
            "value": item.quantity.value,
            "format": "number",
        },
        {
            "value": item.unit_price.value,
            "format": "currency",
            "currency_code": "USD",
        },
        {
            "value": item.total.value,
            "format": "currency",
            "currency_code": "USD",
        },
    ]
    for item in fields.line_items.value
]

summary_rows = [
    [
        {
            "value": "Subtotal",
            "styles": {
                "is_bold": True,
            },
        },
        {
            "value": None,
        },
        {
            "value": None,
        },
        {
            "value": fields.subtotal.value,
            "format": "currency",
            "currency_code": "USD",
        },
    ],
    [
        {
            "value": "Tax",
            "styles": {
                "is_bold": True,
            },
        },
        {
            "value": None,
        },
        {
            "value": None,
        },
        {
            "value": fields.tax.value,
            "format": "currency",
            "currency_code": "USD",
        },
    ],
    [
        {
            "value": "Total Due",
            "styles": {
                "is_bold": True,
                "font_size_in_pt": 12,
            },
        },
        {
            "value": None,
        },
        {
            "value": None,
        },
        {
            "value": fields.total_due.value,
            "format": "currency",
            "currency_code": "USD",
            "styles": {
                "is_bold": True,
                "font_size_in_pt": 12,
            },
        },
    ],
]

sheet_result = client.generate_sheet(
    format="xlsx",
    styles={
        "header": {
            "is_bold": True,
            "background_color": "#2d3748",
            "font_color": "#ffffff",
        },
        "body": {
            "font_size_in_pt": 10,
        },
    },
    sheets=[
        {
            "name": f"Invoice {fields.invoice_number.value}",
            "columns": [
                {
                    "name": "Description",
                    "width": 35,
                },
                {
                    "name": "Quantity",
                    "width": 12,
                },
                {
                    "name": "Unit Price",
                    "width": 16,
                },
                {
                    "name": "Total",
                    "width": 16,
                },
            ],
            "rows": line_item_rows + summary_rows,
        },
    ],
)
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
package main

import il "github.com/iterationlayer/sdk-go"

func main() {
    client := il.NewClient("YOUR_API_KEY")

    var rows []il.SheetRow
    for _, item := range fields.LineItems.Value {
        rows = append(rows, il.SheetRow{
            {
                Value: item.Description.Value,
            },
            {
                Value:  item.Quantity.Value,
                Format: "number",
            },
            {
                Value:        item.UnitPrice.Value,
                Format:       "currency",
                CurrencyCode: "USD",
            },
            {
                Value:        item.Total.Value,
                Format:       "currency",
                CurrencyCode: "USD",
            },
        })
    }

    summaryRows := []il.SheetRow{
        {
            {
                Value: "Subtotal",
                Styles: &il.CellStyle{
                    IsBold: true,
                },
            },
            {
                Value: nil,
            },
            {
                Value: nil,
            },
            {
                Value:        fields.Subtotal.Value,
                Format:       "currency",
                CurrencyCode: "USD",
            },
        },
        {
            {
                Value: "Tax",
                Styles: &il.CellStyle{
                    IsBold: true,
                },
            },
            {
                Value: nil,
            },
            {
                Value: nil,
            },
            {
                Value:        fields.Tax.Value,
                Format:       "currency",
                CurrencyCode: "USD",
            },
        },
        {
            {
                Value: "Total Due",
                Styles: &il.CellStyle{
                    IsBold:       true,
                    FontSizeInPt: 12,
                },
            },
            {
                Value: nil,
            },
            {
                Value: nil,
            },
            {
                Value:        fields.TotalDue.Value,
                Format:       "currency",
                CurrencyCode: "USD",
                Styles: &il.CellStyle{
                    IsBold:       true,
                    FontSizeInPt: 12,
                },
            },
        },
    }

    rows = append(rows, summaryRows...)

    sheetResult, err := client.GenerateSheet(il.GenerateSheetRequest{
        Format: "xlsx",
        Styles: &il.SheetStyles{
            Header: &il.CellStyle{
                IsBold:          true,
                BackgroundColor: "#2d3748",
                FontColor:       "#ffffff",
            },
            Body: &il.CellStyle{
                FontSizeInPt: 10,
            },
        },
        Sheets: []il.Sheet{
            {
                Name: "Invoice " + fields.InvoiceNumber.Value,
                Columns: []il.SheetColumn{
                    {
                        Name:  "Description",
                        Width: 35,
                    },
                    {
                        Name:  "Quantity",
                        Width: 12,
                    },
                    {
                        Name:  "Unit Price",
                        Width: 16,
                    },
                    {
                        Name:  "Total",
                        Width: 16,
                    },
                },
                Rows: rows,
            },
        },
    })
    if err != nil {
        panic(err)
    }
    _ = sheetResult
}
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}

Two API calls. The PDF becomes structured data, and the structured data becomes a formatted spreadsheet. No local PDF parser, no XLSX library, no intermediate file formats.

Scaling to Multiple Invoices

The single-invoice pipeline extends naturally to batch processing. Extract all invoices, then consolidate them into one spreadsheet with multiple sheets — or one sheet with all line items.

Request
# Extract each invoice and generate a consolidated spreadsheet.
# In practice, you'd script the extraction loop and build the
# sheets array dynamically. Here's the final generate call
# with data from three extracted invoices:
curl -X POST https://api.iterationlayer.com/sheet-generation/v1/generate \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "xlsx",
    "styles": {
      "header": {
        "is_bold": true,
        "background_color": "#2d3748",
        "font_color": "#ffffff"
      }
    },
    "sheets": [
      {
        "name": "Invoice 001",
        "columns": [
          {
            "name": "Description",
            "width": 35
          },
          {
            "name": "Quantity",
            "width": 12
          },
          {
            "name": "Unit Price",
            "width": 16
          },
          {
            "name": "Total",
            "width": 16
          }
        ],
        "rows": [
          [
            {
              "value": "Consulting services"
            },
            {
              "value": 40,
              "format": "number"
            },
            {
              "value": 150.00,
              "format": "currency",
              "currency_code": "USD"
            },
            {
              "value": 6000.00,
              "format": "currency",
              "currency_code": "USD"
            }
          ]
        ]
      },
      {
        "name": "Invoice 002",
        "columns": [
          {
            "name": "Description",
            "width": 35
          },
          {
            "name": "Quantity",
            "width": 12
          },
          {
            "name": "Unit Price",
            "width": 16
          },
          {
            "name": "Total",
            "width": 16
          }
        ],
        "rows": [
          [
            {
              "value": "Design review"
            },
            {
              "value": 8,
              "format": "number"
            },
            {
              "value": 200.00,
              "format": "currency",
              "currency_code": "USD"
            },
            {
              "value": 1600.00,
              "format": "currency",
              "currency_code": "USD"
            }
          ]
        ]
      }
    ]
  }'
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
  apiKey: "YOUR_API_KEY",
});

const invoiceFiles = ["invoice-001.pdf", "invoice-002.pdf", "invoice-003.pdf"];

const sheets = await Promise.all(
  invoiceFiles.map(async (filename) => {
    const pdf = await Bun.file(filename).arrayBuffer();
    const pdfBase64 = Buffer.from(pdf).toString("base64");

    const extraction = await client.extract({
      file: pdfBase64,
      schema: extractionSchema,
    });

    const invoiceFields = extraction.data.fields;

    return {
      name: `Invoice ${invoiceFields.invoice_number.value}`,
      columns: [
        {
          name: "Description",
          width: 35,
        },
        {
          name: "Quantity",
          width: 12,
        },
        {
          name: "Unit Price",
          width: 16,
        },
        {
          name: "Total",
          width: 16,
        },
      ],
      rows: invoiceFields.line_items.value.map((item) => [
        {
          value: item.description.value,
        },
        {
          value: item.quantity.value,
          format: "number",
        },
        {
          value: item.unit_price.value,
          format: "currency",
          currency_code: "USD",
        },
        {
          value: item.total.value,
          format: "currency",
          currency_code: "USD",
        },
      ]),
    };
  }),
);

const consolidatedResult = await client.generateSheet({
  format: "xlsx",
  styles: {
    header: {
      is_bold: true,
      background_color: "#2d3748",
      font_color: "#ffffff",
    },
  },
  sheets,
});
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")

invoice_files = ["invoice-001.pdf", "invoice-002.pdf", "invoice-003.pdf"]

sheets = []
for filename in invoice_files:
    with open(filename, "rb") as f:
        import base64
        pdf_base64 = base64.b64encode(f.read()).decode()

    extraction = client.extract(
        file=pdf_base64,
        schema=extraction_schema,
    )

    invoice_fields = extraction.data.fields

    sheets.append({
        "name": f"Invoice {invoice_fields.invoice_number.value}",
        "columns": [
            {
                "name": "Description",
                "width": 35,
            },
            {
                "name": "Quantity",
                "width": 12,
            },
            {
                "name": "Unit Price",
                "width": 16,
            },
            {
                "name": "Total",
                "width": 16,
            },
        ],
        "rows": [
            [
                {
                    "value": item.description.value,
                },
                {
                    "value": item.quantity.value,
                    "format": "number",
                },
                {
                    "value": item.unit_price.value,
                    "format": "currency",
                    "currency_code": "USD",
                },
                {
                    "value": item.total.value,
                    "format": "currency",
                    "currency_code": "USD",
                },
            ]
            for item in invoice_fields.line_items.value
        ],
    })

consolidated_result = client.generate_sheet(
    format="xlsx",
    styles={
        "header": {
            "is_bold": True,
            "background_color": "#2d3748",
            "font_color": "#ffffff",
        },
    },
    sheets=sheets,
)
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}
Request
package main

import (
    "encoding/base64"
    "os"

    il "github.com/iterationlayer/sdk-go"
)

func main() {
    client := il.NewClient("YOUR_API_KEY")

    invoiceFiles := []string{"invoice-001.pdf", "invoice-002.pdf", "invoice-003.pdf"}

    var sheets []il.Sheet
    for _, filename := range invoiceFiles {
        pdfBytes, err := os.ReadFile(filename)
        if err != nil {
            panic(err)
        }
        pdfBase64 := base64.StdEncoding.EncodeToString(pdfBytes)

        extraction, err := client.Extract(il.ExtractRequest{
            File:   pdfBase64,
            Schema: extractionSchema,
        })
        if err != nil {
            panic(err)
        }

        invoiceFields := extraction.Data.Fields

        var rows []il.SheetRow
        for _, item := range invoiceFields.LineItems.Value {
            rows = append(rows, il.SheetRow{
                {
                    Value: item.Description.Value,
                },
                {
                    Value:  item.Quantity.Value,
                    Format: "number",
                },
                {
                    Value:        item.UnitPrice.Value,
                    Format:       "currency",
                    CurrencyCode: "USD",
                },
                {
                    Value:        item.Total.Value,
                    Format:       "currency",
                    CurrencyCode: "USD",
                },
            })
        }

        sheets = append(sheets, il.Sheet{
            Name: "Invoice " + invoiceFields.InvoiceNumber.Value,
            Columns: []il.SheetColumn{
                {
                    Name:  "Description",
                    Width: 35,
                },
                {
                    Name:  "Quantity",
                    Width: 12,
                },
                {
                    Name:  "Unit Price",
                    Width: 16,
                },
                {
                    Name:  "Total",
                    Width: 16,
                },
            },
            Rows: rows,
        })
    }

    consolidatedResult, err := client.GenerateSheet(il.GenerateSheetRequest{
        Format: "xlsx",
        Styles: &il.SheetStyles{
            Header: &il.CellStyle{
                IsBold:          true,
                BackgroundColor: "#2d3748",
                FontColor:       "#ffffff",
            },
        },
        Sheets: sheets,
    })
    if err != nil {
        panic(err)
    }
    _ = consolidatedResult
}
Response
{
  "success": true,
  "data": {
    "buffer": "UEsDBBQAAAAIAA...",
    "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  }
}

Each invoice gets its own sheet tab. One XLSX file, all invoices, properly formatted.

When to Use This Pipeline

This extract-then-generate pattern works for any document-to-spreadsheet workflow:

  • Invoices — Vendor invoices to accounts payable spreadsheets
  • Receipts — Expense receipts to expense reports
  • Purchase orders — PO documents to procurement tracking sheets
  • Contracts — Contract terms to comparison matrices
  • Bank statements — PDF statements to transaction logs

The key insight is that document structure maps cleanly to spreadsheet structure. A table in a PDF maps to rows and columns. Currency values map to formatted currency cells. Dates map to date-formatted cells. The extraction gives you typed data, and the sheet generation consumes typed data. No parsing, no regex, no format conversion in between.

Get Started

The Document Extraction docs cover schema design and field types. The Sheet Generation docs cover the full spreadsheet API including styles, formulas, and multi-sheet support.

Both APIs use the same authentication and the same response format. If you’re already using one, adding the other takes minutes. Sign up for a free account to try the pipeline yourself.

Start building in minutes

Free trial included. No credit card required.