# Bulk Invoice generator (`nautical_scour/invoice-generator`) Actor

https://apify.com/ideas/invoice-generator-dc557656

- **URL**: https://apify.com/nautical\_scour/invoice-generator.md
- **Developed by:** [Maciej](https://apify.com/nautical_scour) (community)
- **Categories:** Automation, E-commerce
- **Stats:** 3 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$50.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Invoice Generator Actor

Automate creation of polished PDF invoices (single or bulk) with **pdfkit** on Apify.\
Supports **Excel column paste** *or* a full **JSON array** of invoices, auto-numbering, defaults, logo, and ZIP output.

### Features

- Subtotal, discount, tax, grand total (auto)
- **Two input styles**: Excel-paste textareas *or* `invoicesJson` (array)
- **Auto numbering** (e.g., `00000`, `00001`, …)
- **Bulk ZIP** + individual PDFs in Key-Value Store
- Logo + seller block + one-page clamp

***

### Quick start

1. **Install deps** in `package.json`:

```json
{
  "dependencies": {
    "apify": "^3.0.0",
    "jszip": "^3.10.1",
    "pdfkit": "^0.14.0"
  }
}
```

2. **Run the actor** from Apify UI or API using one of the inputs below.

***

### Input options

#### A) Excel-paste mode (no JSON needed)

Paste one value **per line** in the UI:

- **Client Names**, **Client Addresses**, *(optional)* **Client Emails**
- *(optional)* **Invoice Numbers**, *(optional)* **Invoice Dates (YYYY-MM-DD)**
- **Line Description**, *(optional)* **Quantity**, **Amount**

Also set top-level defaults (currency, tax, logo, seller, auto numbering).

**Example (what you paste):**

Client Names:

```
ACME LTD
Globex LLC
Initech
```

Client Addresses:

```
123 Main St, Springfield
Hauptstraße 1, Berlin
ul. Testowa 2, Warszawa
```

Line Item — Description:

```
Monthly subscription
Design sprint (1 day)
Consulting package
```

Line Item — Amount:

```
199.99
600
1200
```

Leave **Invoice Numbers** empty to let auto numbering handle it.

#### B) JSON array (full control)

Set `invoicesJson` (textarea) to a JSON array:

```json
[
  {
    "invoiceNumber": "",
    "invoiceDate": "2025-11-03",
    "currency": "USD",
    "locale": "en-US",
    "onePage": true,
    "seller": { "name": "Your Company", "address": "Street 1", "email": "billing@company.com", "vat": "PL1234567890" },
    "client": { "name": "Client A", "address": "Road 10", "email": "a@client.com" },
    "items": [
      { "item": "SUB-MONTH", "description": "Monthly subscription", "quantity": 1, "amount": 199.99 }
    ],
    "taxRate": 23,
    "discount": 0,
    "paymentTerms": "Net 14",
    "footerNote": "Bank: XYZ • IBAN PL00 0000 0000 0000 0000 0000"
  }
]
```

Empty or missing `invoiceNumber` will be auto-assigned if auto numbering is on.

***

### Auto numbering

Control via top-level fields:

- `useAutoInvoiceNumbering` (boolean, default `true`)
- `invoiceNumberStart` (number, e.g., `0`)
- `invoiceNumberWidth` (number, e.g., `5` → `00000`, `00001`, …)

**Rules:** Explicit numbers (from JSON or the “Invoice Numbers” textarea) are **kept**. Missing ones are generated.

***

### Global invoice date

If the **Invoice Dates** textarea is empty, set a single date for all with:

- `globalInvoiceDate` (YYYY-MM-DD)

Missing per-row dates fall back to `globalInvoiceDate`, then today.

***

### Output

- **Single invoice** → `INVOICE-<number>.pdf`
- **Multiple invoices** → individual PDFs **and** a ZIP (e.g., `INVOICES.zip`)
- Files appear in the run’s **Key-Value Store**

***

### API usage examples

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/<USERNAME>~invoice-generator/runs?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "clientNamesLines": "ACME LTD\nGlobex LLC",
    "clientAddressesLines": "123 Main St\nHauptstraße 1",
    "lineDescLines": "Monthly subscription\nDesign sprint",
    "lineAmountLines": "199.99\n600",
    "defaultCurrency": "USD",
    "defaultLocale": "en-US",
    "defaultTaxRate": 23,
    "useAutoInvoiceNumbering": true,
    "invoiceNumberStart": 0,
    "invoiceNumberWidth": 5,
    "globalInvoiceDate": "2025-11-03",
    "sellerName": "Your Company Sp. z o.o.",
    "sellerAddress": "ul. Przykładowa 1, 00-000 Warszawa",
    "sellerEmail": "billing@company.com",
    "sellerVat": "PL1234567890",
    "zipName": "INVOICES.zip"
  }'
```

#### Node.js (Apify Client)

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('<USERNAME>/invoice-generator').call({
  invoicesJson: JSON.stringify([
    {
      invoiceNumber: "",
      invoiceDate: "2025-11-03",
      currency: "EUR",
      locale: "de-DE",
      seller: { name: "Your Company", address: "Street 1", email: "billing@company.com", vat: "PL1234567890" },
      client: { name: "Client B GmbH", address: "Hauptstraße 1, Berlin", email: "ap@b.com" },
      items: [{ item: "Consulting", description: "8h package", quantity: 8, amount: 1200 }],
      taxRate: 19,
      paymentTerms: "Net 14"
    }
  ]),
  defaultCurrency: "EUR",
  defaultLocale: "de-DE",
  useAutoInvoiceNumbering: true,
  invoiceNumberStart: 42,
  invoiceNumberWidth: 5
});

console.log('Run:', run.data.id);
```

***

### Common formatting pitfalls (and fixes)

- **Always fence code** with triple backticks and a language hint:
  - ```json for JSON
    ```
  - ```js for JavaScript
    ```
  - ```bash for shell/CLI
    ```
- **Valid JSON only** in `invoicesJson` (no comments, no trailing commas).
- When pasting columns: **one value per line**; blank lines are ignored.
- If your README shows curly braces weirdly inside Markdown lists, put them in a fenced code block.

***

### Troubleshooting

- **“invoicesJson must be a non-empty JSON array”**\
  Your textarea isn’t valid JSON or it’s empty. Paste an array `[...]`.

- **Got multiple pages unexpectedly**\
  Ensure `defaultOnePage: true` (or set `onePage: true` per invoice). Long item lists get truncated with “... and N more item(s)”.

- **Logo not showing**\
  `defaultLogoPath` must point to a file the actor can read (e.g., uploaded via schema file field). Paths are inside the actor’s sandbox.

# Actor input Schema

## `clientNamesLines` (type: `string`):

Example: ACME LTD⏎Globex LLC⏎Initech

## `clientAddressesLines` (type: `string`):

Match rows with Client Names. Example: 123 Main St⏎Hauptstraße 1⏎ul. Testowa 2

## `clientEmailsLines` (type: `string`):

Optional; match rows with names/addresses.

## `invoiceNumbersLines` (type: `string`):

Optional per-row invoice numbers. If omitted and auto-numbering is enabled, numbers are generated.

## `invoiceDatesLines` (type: `string`):

Optional; per-row dates. If omitted, today is used.

## `globalInvoiceDate` (type: `string`):

YYYY-MM-DD. Used for all invoices if 'Invoice Dates' textarea is empty. Also used as fallback for any missing row.

## `lineDescLines` (type: `string`):

If you want ONE line item per invoice, paste description per row here.

## `lineQtyLines` (type: `string`):

Optional; defaults to 1 when empty.

## `lineAmountLines` (type: `string`):

Line TOTAL amount per row (e.g., 199.99).

## `useAutoInvoiceNumbering` (type: `boolean`):

If true, missing invoice numbers will be assigned sequentially.

## `invoiceNumberStart` (type: `integer`):

First number to assign when auto-numbering (e.g., 0 → 00000).

## `invoiceNumberWidth` (type: `integer`):

Zero-padding length for auto numbers (e.g., 5 → 00000).

## `defaultCurrency` (type: `string`):

ISO code (USD, EUR, PLN) when a row doesn't specify currency.

## `defaultLocale` (type: `string`):

BCP 47 code (e.g., en-US, pl-PL).

## `defaultTaxRate` (type: `number`):

Percent tax when not specified in a row.

## `defaultDiscount` (type: `number`):

Percent discount when not specified in a row.

## `defaultPaymentTerms` (type: `string`):

Fallback for per-row terms.

## `defaultFooterNote` (type: `string`):

Fallback footer text.

## `defaultOnePage` (type: `boolean`):

Clamp invoices to one page unless a row overrides it.

## `invoicesJson` (type: `string`):

Optional: A JSON array of full invoice objects. If provided, this is used instead of the pasted columns.

## `defaultLogoPath` (type: `string`):

Fallback logo file path.

## `sellerName` (type: `string`):

Your company name shown on all invoices.

## `sellerAddress` (type: `string`):

Your address shown on all invoices.

## `sellerEmail` (type: `string`):

Your billing/contact email.

## `sellerVat` (type: `string`):

Your tax identifier.

## `zipName` (type: `string`):

Filename for the resulting ZIP.

## Actor input object example

```json
{
  "useAutoInvoiceNumbering": true,
  "invoiceNumberStart": 0,
  "invoiceNumberWidth": 5,
  "defaultCurrency": "USD",
  "defaultLocale": "en-US",
  "defaultTaxRate": 0,
  "defaultDiscount": 0,
  "defaultPaymentTerms": "Due in 30 days",
  "defaultFooterNote": "Thank you for your business!",
  "defaultOnePage": true,
  "sellerName": "Your Company Sp. z o.o.",
  "sellerAddress": "ul. Przykładowa 1, 00-000 Warszawa",
  "sellerEmail": "billing@company.com",
  "sellerVat": "PL1234567890",
  "zipName": "INVOICES.zip"
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "clientNamesLines": "",
    "clientAddressesLines": "",
    "clientEmailsLines": "",
    "invoiceNumbersLines": "",
    "invoiceDatesLines": "",
    "globalInvoiceDate": "",
    "lineDescLines": "",
    "lineQtyLines": "",
    "lineAmountLines": "",
    "defaultPaymentTerms": "Due in 30 days",
    "defaultFooterNote": "Thank you for your business!",
    "invoicesJson": "",
    "sellerName": "Your Company Sp. z o.o.",
    "sellerAddress": "ul. Przykładowa 1, 00-000 Warszawa",
    "sellerEmail": "billing@company.com",
    "sellerVat": "PL1234567890",
    "zipName": "INVOICES.zip"
};

// Run the Actor and wait for it to finish
const run = await client.actor("nautical_scour/invoice-generator").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "clientNamesLines": "",
    "clientAddressesLines": "",
    "clientEmailsLines": "",
    "invoiceNumbersLines": "",
    "invoiceDatesLines": "",
    "globalInvoiceDate": "",
    "lineDescLines": "",
    "lineQtyLines": "",
    "lineAmountLines": "",
    "defaultPaymentTerms": "Due in 30 days",
    "defaultFooterNote": "Thank you for your business!",
    "invoicesJson": "",
    "sellerName": "Your Company Sp. z o.o.",
    "sellerAddress": "ul. Przykładowa 1, 00-000 Warszawa",
    "sellerEmail": "billing@company.com",
    "sellerVat": "PL1234567890",
    "zipName": "INVOICES.zip",
}

# Run the Actor and wait for it to finish
run = client.actor("nautical_scour/invoice-generator").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "clientNamesLines": "",
  "clientAddressesLines": "",
  "clientEmailsLines": "",
  "invoiceNumbersLines": "",
  "invoiceDatesLines": "",
  "globalInvoiceDate": "",
  "lineDescLines": "",
  "lineQtyLines": "",
  "lineAmountLines": "",
  "defaultPaymentTerms": "Due in 30 days",
  "defaultFooterNote": "Thank you for your business!",
  "invoicesJson": "",
  "sellerName": "Your Company Sp. z o.o.",
  "sellerAddress": "ul. Przykładowa 1, 00-000 Warszawa",
  "sellerEmail": "billing@company.com",
  "sellerVat": "PL1234567890",
  "zipName": "INVOICES.zip"
}' |
apify call nautical_scour/invoice-generator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=nautical_scour/invoice-generator",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/wpKfZbbbhWSEssOHQ/builds/551l0KuNPfG3S2G4h/openapi.json
