Iteration Layer
Menu
Features
Use Cases
Docs
Resources
Pricing

From PDF Invoices to Formatted Spreadsheets in Two API Calls

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 an Excel spreadsheet, 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 Iteration Layer 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.

{
  "fields": [
    {
      "name": "vendor_name",
      "type": "TEXT",
      "description": "Vendor legal name"
    },
    {
      "name": "invoice_number",
      "type": "TEXT",
      "description": "Invoice number"
    },
    {
      "name": "invoice_date",
      "type": "DATE",
      "description": "Invoice issue date"
    },
    {
      "name": "due_date",
      "type": "DATE",
      "description": "Payment due date"
    },
    {
      "name": "line_items",
      "type": "ARRAY",
      "description": "Invoice line items",
      "fields": [
        {
          "name": "description",
          "type": "TEXT",
          "description": "Line item description"
        },
        {
          "name": "quantity",
          "type": "DECIMAL",
          "description": "Line item quantity"
        },
        {
          "name": "unit_price",
          "type": "CURRENCY_AMOUNT",
          "description": "Unit price"
        },
        {
          "name": "total",
          "type": "CURRENCY_AMOUNT",
          "description": "Line item total"
        }
      ]
    },
    {
      "name": "subtotal",
      "type": "CURRENCY_AMOUNT",
      "description": "Invoice subtotal before tax"
    },
    {
      "name": "tax",
      "type": "CURRENCY_AMOUNT",
      "description": "Tax amount"
    },
    {
      "name": "total_due",
      "type": "CURRENCY_AMOUNT",
      "description": "Total amount due"
    }
  ]
}

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 '{
    "files": [
      {
        "type": "url",
        "name": "invoice.pdf",
        "url": "https://example.com/invoice.pdf"
      }
    ],
    "schema": {
      "fields": [
        {
          "name": "vendor_name",
          "type": "TEXT",
          "description": "Vendor legal name"
        },
        {
          "name": "invoice_number",
          "type": "TEXT",
          "description": "Invoice number"
        },
        {
          "name": "invoice_date",
          "type": "DATE",
          "description": "Invoice issue date"
        },
        {
          "name": "due_date",
          "type": "DATE",
          "description": "Payment due date"
        },
        {
          "name": "line_items",
          "type": "ARRAY",
          "description": "Invoice line items",
          "fields": [
            {
              "name": "description",
              "type": "TEXT",
              "description": "Line item description"
            },
            {
              "name": "quantity",
              "type": "DECIMAL",
              "description": "Line item quantity"
            },
            {
              "name": "unit_price",
              "type": "CURRENCY_AMOUNT",
              "description": "Unit price"
            },
            {
              "name": "total",
              "type": "CURRENCY_AMOUNT",
              "description": "Line item total"
            }
          ]
        },
        {
          "name": "subtotal",
          "type": "CURRENCY_AMOUNT",
          "description": "Invoice subtotal before tax"
        },
        {
          "name": "tax",
          "type": "CURRENCY_AMOUNT",
          "description": "Tax amount"
        },
        {
          "name": "total_due",
          "type": "CURRENCY_AMOUNT",
          "description": "Total amount due"
        }
      ]
    }
  }'
Response
{
  "success": true,
  "data": {
    "fields": {
      "vendor_name": {
        "value": "Muller Services GmbH",
        "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": 1140.00,
        "confidence": 0.95
      },
      "total_due": {
        "value": 61140.00,
        "confidence": 0.98
      }
    }
  }
}
Request
import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({
  apiKey: "YOUR_API_KEY",
});

const extractionResult = await client.extractDocument({
  files: [
    {
      type: "url",
      name: "invoice.pdf",
      url: "https://example.com/invoice.pdf",
    },
  ],
  schema: {
    fields: [
      {
        name: "vendor_name",
        type: "TEXT",
        description: "Vendor legal name",
      },
      {
        name: "invoice_number",
        type: "TEXT",
        description: "Invoice number",
      },
      {
        name: "invoice_date",
        type: "DATE",
        description: "Invoice issue date",
      },
      {
        name: "due_date",
        type: "DATE",
        description: "Payment due date",
      },
      {
        name: "line_items",
        type: "ARRAY",
        description: "Invoice line items",
        fields: [
          {
            name: "description",
            type: "TEXT",
            description: "Line item description",
          },
          {
            name: "quantity",
            type: "DECIMAL",
            description: "Line item quantity",
          },
          {
            name: "unit_price",
            type: "CURRENCY_AMOUNT",
            description: "Unit price",
          },
          {
            name: "total",
            type: "CURRENCY_AMOUNT",
            description: "Line item total",
          },
        ],
      },
      {
        name: "subtotal",
        type: "CURRENCY_AMOUNT",
        description: "Invoice subtotal before tax",
      },
      {
        name: "tax",
        type: "CURRENCY_AMOUNT",
        description: "Tax amount",
      },
      {
        name: "total_due",
        type: "CURRENCY_AMOUNT",
        description: "Total amount due",
      },
    ],
  },
});

const fields = extractionResult;
Response
{
  "success": true,
  "data": {
    "fields": {
      "vendor_name": {
        "value": "Muller Services GmbH",
        "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": 1140.00,
        "confidence": 0.95
      },
      "total_due": {
        "value": 61140.00,
        "confidence": 0.98
      }
    }
  }
}
Request
from iterationlayer import IterationLayer
client = IterationLayer(api_key="YOUR_API_KEY")

extraction_result = client.extract_document(
    files=[
        {
            "type": "url",
            "name": "invoice.pdf",
            "url": "https://example.com/invoice.pdf",
        },
    ],
    schema={
        "fields": [
            {
                "name": "vendor_name",
                "type": "TEXT",
                "description": "Vendor legal name",
            },
            {
                "name": "invoice_number",
                "type": "TEXT",
                "description": "Invoice number",
            },
            {
                "name": "invoice_date",
                "type": "DATE",
                "description": "Invoice issue date",
            },
            {
                "name": "due_date",
                "type": "DATE",
                "description": "Payment due date",
            },
            {
                "name": "line_items",
                "type": "ARRAY",
                "description": "Invoice line items",
                "fields": [
                    {
                        "name": "description",
                        "type": "TEXT",
                        "description": "Line item description",
                    },
                    {
                        "name": "quantity",
                        "type": "DECIMAL",
                        "description": "Line item quantity",
                    },
                    {
                        "name": "unit_price",
                        "type": "CURRENCY_AMOUNT",
                        "description": "Unit price",
                    },
                    {
                        "name": "total",
                        "type": "CURRENCY_AMOUNT",
                        "description": "Line item total",
                    },
                ],
            },
            {
                "name": "subtotal",
                "type": "CURRENCY_AMOUNT",
                "description": "Invoice subtotal before tax",
            },
            {
                "name": "tax",
                "type": "CURRENCY_AMOUNT",
                "description": "Tax amount",
            },
            {
                "name": "total_due",
                "type": "CURRENCY_AMOUNT",
                "description": "Total amount due",
            },
        ],
    },
)

fields = extraction_result
Response
{
  "success": true,
  "data": {
    "fields": {
      "vendor_name": {
        "value": "Muller Services GmbH",
        "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": 1140.00,
        "confidence": 0.95
      },
      "total_due": {
        "value": 61140.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.ExtractDocument(il.ExtractDocumentRequest{
        Files: []il.FileInput{
            {
                Type: "url",
                Name: "invoice.pdf",
                Url:  "https://example.com/invoice.pdf",
            },
        },
        Schema: il.ExtractionSchema{
            Fields: []any{
                il.TextFieldConfig{
                    Name:        "vendor_name",
                    Type:        "TEXT",
                    Description: "Vendor legal name",
                },
                il.TextFieldConfig{
                    Name:        "invoice_number",
                    Type:        "TEXT",
                    Description: "Invoice number",
                },
                il.DateFieldConfig{
                    Name:        "invoice_date",
                    Type:        "DATE",
                    Description: "Invoice issue date",
                },
                il.DateFieldConfig{
                    Name:        "due_date",
                    Type:        "DATE",
                    Description: "Payment due date",
                },
                il.ArrayFieldConfig{
                    Name:        "line_items",
                    Type:        "ARRAY",
                    Description: "Invoice line items",
                    Fields: []any{
                        il.TextFieldConfig{Name: "description", Type: "TEXT", Description: "Line item description"},
                        il.DecimalFieldConfig{Name: "quantity", Type: "DECIMAL", Description: "Line item quantity"},
                        il.CurrencyAmountFieldConfig{Name: "unit_price", Type: "CURRENCY_AMOUNT", Description: "Unit price"},
                        il.CurrencyAmountFieldConfig{Name: "total", Type: "CURRENCY_AMOUNT", Description: "Line item total"},
                    },
                },
                il.CurrencyAmountFieldConfig{
                    Name:        "subtotal",
                    Type:        "CURRENCY_AMOUNT",
                    Description: "Invoice subtotal before tax",
                },
                il.CurrencyAmountFieldConfig{
                    Name:        "tax",
                    Type:        "CURRENCY_AMOUNT",
                    Description: "Tax amount",
                },
                il.CurrencyAmountFieldConfig{
                    Name:        "total_due",
                    Type:        "CURRENCY_AMOUNT",
                    Description: "Total amount due",
                },
            },
        },
    })
    if err != nil {
        panic(err)
    }

    fields := extractionResult
    _ = fields
}
Response
{
  "success": true,
  "data": {
    "fields": {
      "vendor_name": {
        "value": "Muller Services GmbH",
        "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": 1140.00,
        "confidence": 0.95
      },
      "total_due": {
        "value": 61140.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": "EUR"
            },
            {
              "value": 6000.00,
              "format": "currency",
              "currency_code": "EUR"
            }
          ],
          [
            {
              "value": "Subtotal",
              "styles": {
                "is_bold": true
              }
            },
            {
              "value": null
            },
            {
              "value": null
            },
            {
              "value": 6000.00,
              "format": "currency",
              "currency_code": "EUR"
            }
          ],
          [
            {
              "value": "Tax",
              "styles": {
                "is_bold": true
              }
            },
            {
              "value": null
            },
            {
              "value": null
            },
            {
              "value": 1140.00,
              "format": "currency",
              "currency_code": "EUR"
            }
          ],
          [
            {
              "value": "Total Due",
              "styles": {
                "is_bold": true,
                "font_size_in_pt": 12
              }
            },
            {
              "value": null
            },
            {
              "value": null
            },
            {
              "value": 61140.00,
              "format": "currency",
              "currency_code": "EUR",
              "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: "EUR",
  },
  {
    value: item.total.value,
    format: "currency",
    currency_code: "EUR",
  },
]);

const summaryRows = [
  [
    {
      value: "Subtotal",
      styles: {
        is_bold: true,
      },
    },
    {
      value: null,
    },
    {
      value: null,
    },
    {
      value: fields.subtotal.value,
      format: "currency",
      currency_code: "EUR",
    },
  ],
  [
    {
      value: "Tax",
      styles: {
        is_bold: true,
      },
    },
    {
      value: null,
    },
    {
      value: null,
    },
    {
      value: fields.tax.value,
      format: "currency",
      currency_code: "EUR",
    },
  ],
  [
    {
      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: "EUR",
      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": "EUR",
        },
        {
            "value": item.total.value,
            "format": "currency",
            "currency_code": "EUR",
        },
    ]
    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": "EUR",
        },
    ],
    [
        {
            "value": "Tax",
            "styles": {
                "is_bold": True,
            },
        },
        {
            "value": None,
        },
        {
            "value": None,
        },
        {
            "value": fields.tax.value,
            "format": "currency",
            "currency_code": "EUR",
        },
    ],
    [
        {
            "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": "EUR",
            "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: "EUR",
            },
            {
                Value:        item.Total.Value,
                Format:       "currency",
                CurrencyCode: "EUR",
            },
        })
    }

    summaryRows := []il.SheetRow{
        {
            {
                Value: "Subtotal",
                Styles: &il.CellStyle{
                    IsBold: true,
                },
            },
            {
                Value: nil,
            },
            {
                Value: nil,
            },
            {
                Value:        fields.Subtotal.Value,
                Format:       "currency",
                CurrencyCode: "EUR",
            },
        },
        {
            {
                Value: "Tax",
                Styles: &il.CellStyle{
                    IsBold: true,
                },
            },
            {
                Value: nil,
            },
            {
                Value: nil,
            },
            {
                Value:        fields.Tax.Value,
                Format:       "currency",
                CurrencyCode: "EUR",
            },
        },
        {
            {
                Value: "Total Due",
                Styles: &il.CellStyle{
                    IsBold:       true,
                    FontSizeInPt: 12,
                },
            },
            {
                Value: nil,
            },
            {
                Value: nil,
            },
            {
                Value:        fields.TotalDue.Value,
                Format:       "currency",
                CurrencyCode: "EUR",
                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": "EUR"
            },
            {
              "value": 6000.00,
              "format": "currency",
              "currency_code": "EUR"
            }
          ]
        ]
      },
      {
        "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": "EUR"
            },
            {
              "value": 1600.00,
              "format": "currency",
              "currency_code": "EUR"
            }
          ]
        ]
      }
    ]
  }'
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.extractDocument({
      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: "EUR",
        },
        {
          value: item.total.value,
          format: "currency",
          currency_code: "EUR",
        },
      ]),
    };
  }),
);

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_document(
        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": "EUR",
                },
                {
                    "value": item.total.value,
                    "format": "currency",
                    "currency_code": "EUR",
                },
            ]
            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.ExtractDocument(il.ExtractDocumentRequest{
            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: "EUR",
                },
                {
                    Value:        item.Total.Value,
                    Format:       "currency",
                    CurrencyCode: "EUR",
                },
            })
        }

        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:

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. Start the 7-day trial to try the pipeline yourself.

Written by
Fabian Schucht Fabian Schucht
Published on
Reading time
5 min read
Categories

Related reading

Learn how to turn the same pattern into production-ready document, image, and automation workflows.

Try with your own data

Start the trial and run this in minutes.