BrowseWiz Logo
BrowseWiz on Discord
n8n invoice workflow: cztery nody w stylu n8n (Trigger, Extract, AI, Drive upload) z modelem czatu podpiętym do kroku AI, które automatycznie zbierają faktury i paragony

Automatyzacja faktur w n8n: workflow ze schematem blokowym, który zbiera faktury i paragony z Gmaila

Tom
Tom

Ten workflow n8n zbiera z Gmaila faktury kosztowe i paragony z wybranego zakresu dat. Pobiera każdy załącznik PDF, pyta model OpenAI, czy plik to faktura albo paragon, wrzuca pasujące pliki do nowego folderu na Dysku Google, a jeśli tego chcesz, wysyła całą paczkę mailem do księgowości. Schemat blokowy poniżej pokazuje przebieg krok po kroku, a ponieważ na starcie stoi node Webhook, uruchomisz go wiadomością na czacie BrowseWiz, poleceniem curl albo tagiem NFC.

Opublikowałem ten workflow jako szablon n8n nr 3719 w kwietniu 2025. Nazwy nodów i ustawień w tej wersji odpowiadają temu, co n8n pokazuje według stanu na wrzesień 2026. Poprawiłem też trzy błędy z oryginału. Workflow nie łączy się z Krajowym Systemem e-Faktur (KSeF), w którym od 1 lutego 2026 odbiera się faktury ustrukturyzowane. Obejmuje dokumenty, które przychodzą mailem jako PDF, np. paragony i faktury od zagranicznych dostawców spoza KSeF.

Schemat blokowy workflowu n8n do automatyzacji faktur

Schemat blokowy workflowu n8n do przetwarzania faktur: Webhook, folder na Dysku Google, załączniki z Gmaila, tekst z PDF, sprawdzenie przez OpenAI, zapis pliku i mail

Tabela uzupełnia pomocnicze nody, których nie ma na diagramie.

Krok

Node n8n

Co robi

1

Webhook

Odbiera startDate, endDate i sendEmail (POST)

2

Google Drive: Create a folder

Tworzy folder z zakresem dat w nazwie

3

Respond to Webhook

Od razu odpowiada statusem 202 i linkiem do folderu

4

Edit Fields (Set) o nazwie Configure

Trzyma ustawienia: frazę dopasowania, limit tokenów, adres księgowości

5

Gmail: Get many messages

Pobiera maile z załącznikami PDF z zakresu dat

6

Code

Robi z każdego załącznika osobny element (item)

7

If: Is attachment a PDF?

Przepuszcza PDF-y, reszta kończy w No Operation, do nothing

8

Extract From File: Extract From PDF

Odczytuje tekst każdego PDF-a

9

If, OpenAI, Merge

Pomija bardzo długie pliki, pyta „faktura czy paragon?”, łączy odpowiedź z plikiem

10

If: Is matched

Zostawia pliki, dla których model odpowiedział true

11

Google Drive: Upload a file

Wrzuca każdy pasujący plik do nowego folderu

12

If, Code, Gmail: Send a message

Gdy sendEmail ma wartość true, wysyła wszystkie pasujące pliki w jednym mailu

Jak zbudować workflow do automatyzacji faktur w n8n

Zaimportuj szablon i dodaj poświadczenia (credentials) do Gmaila, Google Drive i OpenAI albo zbuduj workflow ręcznie z poniższymi ustawieniami.

Trigger i folder na Dysku Google

  • Webhook: HTTP Method POST, Authentication Header auth (poświadczenie przyjmuje nazwę nagłówka w polu Name i wartość w polu Value), Respond ustawione na Using 'Respond to Webhook' Node.

  • Google Drive o nazwie Create folder: Resource Folder, Operation Create, Folder Name {{ 'invoices_' + $json.body.startDate.split('T')[0] + '_' + $json.body.endDate.split('T')[0] }}, do tego Parent Drive i Parent Folder.

  • Respond to Webhook: Respond With JSON, opcja Response Code ustawiona na 202 i link do folderu w treści odpowiedzi:

{
  "status": "Accepted",
  "driveFolderUrl": "https://drive.google.com/drive/folders/{{ $json.id }}"
}

Workflow odpowiada wcześnie, bo przetworzenie maili z całego miesiąca może trwać kilka minut, a w n8n Cloud webhook, który nie odpowie w ciągu 100 sekund, kończy się błędem 524. n8n wykonuje równoległe gałęzie od góry obszaru roboczego (canvas) w dół, więc umieść Respond to Webhook nad gałęzią Configure, bo inaczej odpowiedź poczeka na koniec całego przebiegu.

Node Configure

Node Edit Fields (Set) o nazwie Configure trzyma ustawienia, z których korzystają pozostałe nody: Match on (np. „receipt or invoice”), maxTokenSize (8000), replyTokenSize (50), sendInvoicesTo i sendEmail. Oryginalny szablon porównywał sendEmail ze stringiem "true", więc wartość logiczna true z JSON-a, wysłana przez narzędzie czatu, nigdy nie uruchamiała wysyłki maila. To wyrażenie przyjmuje obie postaci:

{{ String($('Webhook').item.json.body.sendEmail) === 'true' }}

Załączniki z Gmaila

  • Gmail: Resource Message, Operation Get Many, Return All włączone, Simplify wyłączone (sekcja Options pojawia się dopiero przy wyłączonym Simplify). W Filters ustaw Search na has:attachment filename:pdf, a do Received After i Received Before przypisz startDate i endDate z webhooka. W Options włącz Download Attachments. Pomiń filtr Read Status, bo domyślnie obejmuje tylko nieprzeczytane maile.

  • Code w domyślnym trybie Run Once for All Items tworzy dla każdego załącznika osobny element z plikiem w data:

const results = [];
for (const item of $input.all()) {
  for (const key of Object.keys(item.binary ?? {})) {
    results.push({ json: {}, binary: { data: item.binary[key] } });
  }
}
return results;

Tekst z PDF i klasyfikacja przez AI

  • If: {{ $binary.data.fileExtension }} is equal to pdf, z włączoną opcją Ignore Case, żeby przeszedł też INVOICE.PDF. Wyjście false prowadzi do No Operation, do nothing.

  • Extract From File: Operation Extract From PDF, Input Binary Field data i opcja Keep Source ustawiona na Both. Bez niej node gubi PDF i upload nie ma czego wysłać. Ten node zastępuje przestarzały (deprecated) node Read PDF z szablonu.

  • If o nazwie „Is text within token limit?”: jeden token to mniej więcej cztery znaki angielskiego tekstu, więc warunek dzieli długość tekstu przez 4 i porównuje wynik z maxTokenSize minus replyTokenSize. Polski tekst dzieli się na więcej tokenów: w naszym teście tokenizerem o200k_base (GPT-4o) wychodziło około 3,3 znaku na token, więc przy polskich fakturach bezpieczniej dzielić przez 3.

  • OpenAI: Resource Text, Operation Message a Model, z takim promptem:

Does this PDF file look like a {{ $('Configure').first().json['Match on'] }}?
Return "true" if it is and "false" if not. Reply only with lowercase true or false.
Filename: {{ $binary.data.fileName }}
Text: {{ $json.text }}
  • Merge: Mode Combine, Combine By Position, z OpenAI na wejściu 1 i If od limitu tokenów na wejściu 2, żeby każda odpowiedź trafiła obok swojego PDF-a.

  • If o nazwie „Is matched”: {{ $json.output[0].content[0].text }} is equal to true. W tym polu obecny node OpenAI zwraca odpowiedź przy włączonym Simplify Output. W szablonie, który używa starszej wersji OpenAI, jest to $json.message.content.

Zapis na Dysku Google i wysyłka maila

  • Google Drive: Resource File, Operation Upload, Input Data Field Name data, File Name {{ $binary.data.fileName }}, Parent Drive ustawione na My Drive, Parent Folder By ID {{ $('Create folder').first().json.id }}.

  • If sprawdza sendEmail z Configure. Przy true node Code pakuje wszystkie pasujące pliki do jednego elementu, żeby wyszły w jednym mailu. Szablon używał nazw plików jako kluczy, więc dwa załączniki o nazwie invoice.pdf zlewały się w jeden. Numerowane klucze zachowują wszystkie, a Gmail i tak nazywa każdy załącznik tak jak plik:

const merged = { json: {}, binary: {} };
$input.all().forEach((item, i) => {
  merged.binary[`file_${i}`] = item.binary.data;
});
return [merged];
  • Gmail: Resource Message, Operation Send, To {{ $('Configure').first().json.sendInvoicesTo }}. Szablon miał w tym miejscu przykładowy adres. W Options dodaj Attachments z {{ Object.keys($binary).join(',') }} jako nazwami pól i wyłącz Append n8n attribution, jeśli nie chcesz stopki.

Na koniec opublikuj workflow (przycisk Publish albo Shift+P). Production URL uruchamia tylko opublikowaną wersję, a Test URL nasłuchuje przez 120 sekund od kliknięcia Listen for test event.

Uruchamianie workflowu n8n z BrowseWiz poleceniem w języku naturalnym

BrowseWiz to panel boczny z AI dla Chrome i Edge. Jego własne narzędzia wysyłają na zarejestrowany przez ciebie endpoint treść JSON, którą model wypełnia na podstawie twojej wiadomości, a Webhook w n8n przyjmuje ją bez zmian.

  1. W nodzie Webhook skopiuj Production URL.

  2. Otwórz panel boczny (Alt+B w Windows, Option+B na Macu), kliknij ikonę klucza francuskiego, a potem Zarządzaj Narzędziami. Na stronie z narzędziami przejdź do sekcji własnych narzędzi, oznaczonej jako Narzędzia API/Webhooki.

  3. Wypełnij pola Nazwa Narzędzia (etykieta, którą zobaczysz w menu pod ikoną klucza), URL Endpoint (adres webhooka), Metoda HTTP (POST), Nagłówki (nazwa i wartość z poświadczenia Header auth, oznaczone jako tajne, żeby BrowseWiz przechowywał je bezpiecznie) i wklej ten Schemat JSON:

{
  "name": "getInvoicesAndReceiptsFromEmails",
  "description": "Finds receipts and invoices in Gmail within a date range, uploads them to a new Google Drive folder and optionally emails them to the accountant.",
  "parameters": {
    "type": "object",
    "properties": {
      "startDate": {
        "type": "string",
        "format": "date-time",
        "description": "Start of the email date range, ISO 8601."
      },
      "endDate": {
        "type": "string",
        "format": "date-time",
        "description": "End of the email date range, ISO 8601."
      },
      "sendEmail": {
        "type": "boolean",
        "description": "true to email the collected files to the accountant."
      }
    },
    "required": ["startDate", "endDate"]
  }
}

Sprawdź, czy narzędzie jest włączone w sekcji Custom Tools menu pod ikoną klucza, a potem napisz np. „Zbierz moje faktury i paragony z sierpnia 2026 i wyślij je do księgowości”. Model zamieni to na treść żądania:

{
  "startDate": "2026-08-01T00:00:00Z",
  "endDate": "2026-09-01T00:00:00Z",
  "sendEmail": true
}

Webhook odsyła wynik do modelu, więc w odpowiedzi na czacie może się pojawić link do folderu na Dysku Google. Resztę przebiegu widać w zakładce Executions w n8n.

Model sam decyduje, kiedy wywołać narzędzie, a dokumentacja BrowseWiz zaleca ostrożność przy endpointach, które zmieniają dane, więc wyłączaj to narzędzie, gdy go nie potrzebujesz. Jeśli model źle zinterpretuje „poprzedni miesiąc”, podaj mu konkretne daty.

Uruchamianie workflowu n8n tagiem NFC, skrótem w telefonie lub przez curl

n8n nie ma triggera NFC, więc to tag musi sprawić, że telefon wywoła webhook. Telefon nie doda łatwo nagłówka uwierzytelniającego, którego wymaga główny webhook, dlatego daję mu osobny, mały workflow:

  1. Node Webhook z HTTP Method GET i opcją Only Run If ustawioną na {{ $json.query.token === 'long-random-string' }}. Przebieg uruchamiają tylko adresy kończące się na ?token=long-random-string.

  2. Node HTTP Request, który wysyła POST na Production URL głównego webhooka z twoim poświadczeniem Header Auth (Authentication: Generic Credential Type) i treścią JSON obejmującą poprzedni miesiąc: startDate ustawione na {{ $today.minus({ months: 1 }).startOf('month').toISO() }}, endDate na {{ $today.startOf('month').toISO() }}.

Potem skieruj telefon na URL pomocniczego webhooka:

  • iPhone: w aplikacji Skróty (Shortcuts) zbuduj skrót z akcją „Pobierz zawartość URL” (Get Contents of URL) wskazującą ten adres, dodaj automatyzację z wyzwalaczem NFC i zeskanuj tag. Skróty ignorują zawartość tagu poza jego unikalnym identyfikatorem, a Apple wymienia NFC wśród automatyzacji, które mogą działać bez pytania o zgodę.

  • Android: zapisz URL na tagu. Na Androidzie 16 zeskanowanie tagu z linkiem http lub https otwiera go jak każdy inny link, co wysyła żądanie GET; od Androida 17 trzeba najpierw stuknąć powiadomienie o otwarciu linku. Każdy, kto zeskanuje tag, może odczytać URL razem z tokenem.

  • curl, do testowania głównego webhooka:

curl -X POST "https://your-n8n.example.com/webhook/<path>" \
  -H "X-Invoice-Key: <your-secret>" \
  -H "Content-Type: application/json" \
  -d '{"startDate":"2026-08-01T00:00:00Z","endDate":"2026-09-01T00:00:00Z","sendEmail":false}'

Warianty: zeskanowane paragony, osobne foldery, długie pliki

  • Zeskanowane paragony. Sfotografowany paragon zapisany jako PDF nie ma warstwy tekstowej, więc Extract From PDF zwraca niewiele albo nic. Wyślij sam plik PDF jako wiadomość typu File (File Data z pola binarnego) w nodzie OpenAI, w operacji Message a Model. Modele obsługujące obraz (gpt-4o i nowsze) dostają też obraz każdej strony. Alternatywą z OCR jest operacja Extract Text w nodzie Mistral AI.

  • Faktury osobno, paragony osobno. Node Text Classifier z kategoriami invoice i receipt oraz opcją When No Clear Match ustawioną na Output on Extra, 'Other' Branch może zastąpić OpenAI, Merge i Is matched, a każdą kategorię skierować do osobnego folderu. Do działania potrzebuje podpiętego modelu czatu (sub-node), np. OpenAI Chat Model albo OpenRouter Chat Model (jak działają OpenRouter i inne API zgodne z OpenAI).

  • Długie pliki. W szablonie „Is text within token limit?” ma niepodłączone wyjście false, więc długie PDF-y przepadają. Podłącz je do zapisu w folderze „do ręcznej weryfikacji”.

  • Wybór modelu. Do odpowiedzi true lub false nie trzeba modelu z najwyższej półki; mały i tani model utrzyma niski koszt przetworzenia jednego PDF-a. Przy trudniejszych zadaniach, np. odczytywaniu zeskanowanych paragonów, wybór ułatwi nasze porównanie najlepszych modeli AI.

  • Pierwsze uruchomienia. Klasyfikator popełnia błędy, więc zaczynaj z sendEmail ustawionym na false i sprawdź folder, zanim cokolwiek trafi do księgowości.

Najczęściej zadawane pytania

Jak zobaczyć workflow n8n jako schemat blokowy?

Obszar roboczy edytora n8n już nim jest. Nody to kroki, połączenia to strzałki, a nody If rozgałęziają się na wyjścia true i false. Klawisz 1 dopasowuje widok do okna, Shift+S dodaje notatkę (sticky note), a w n8n 2.31.0 i nowszych Ctrl/Cmd+G zbiera powiązane nody w nazwaną grupę (Canvas Group). Jeśli potrzebujesz diagramu poza n8n, pobierz JSON workflowu z menu edytora i zapisz nazwy nodów jako flowchart LR w Mermaid. Taki diagram wyrenderują edytory takie jak mermaid.live.

Czy n8n może automatycznie przetwarzać faktury?

Tak. Ten workflow działa na żądanie przez webhook, ale ten sam łańcuch nodów może startować z Schedule Trigger pierwszego dnia każdego miesiąca (z opisanymi wyżej wyrażeniami dat $today) albo z Gmail Trigger przy każdym nowym mailu. Wyrywkowo sprawdzaj, co wybiera AI.

Jak uruchomić workflow n8n tagiem NFC?

n8n nie ma triggera NFC, więc tag musi sprawić, że telefon wywoła URL webhooka. Na iPhonie automatyzacja w Skrótach z wyzwalaczem NFC uruchamia akcję „Pobierz zawartość URL”. Na Androidzie tag z zapisanym adresem otwiera go jako żądanie GET, więc node Webhook musi przyjmować GET.

Co zastąpiło node Read PDF w n8n?

Extract From File z operacją Extract From PDF. Read PDF jest na liście przestarzałych nodów n8n, więc wciąż działa, ale nie dostaje poprawek. Przy zamianie ustaw Keep Source na Both, inaczej PDF wypadnie z elementu.

Tom's avatar

About Tom

I'm a software engineer and solutions architect specializing in AI-driven tools and productivity software, passionate about helping users reclaim their valuable time through intelligent automation.