用 n8n 和 Gemini 從 Gmail 擷取發票,並在付款前檢查 IBAN
Extracting invoices from Gmail with n8n and Gemini, then checking the IBAN before anyone pays it
文章介紹免費 n8n 範本如何配合 Gemini 從 Gmail 擷取發票資料,並示範如何另行接入 API 檢查 IBAN 等付款識別碼。範本以 Structured Output Parser 限定 JSON 結構,在程式碼中核對小計與税額,並將低信心資料標記為 needs_review。
Most invoice automations stop at extraction: an LLM pulls the vendor, total and bank details out of a PDF, and the numbers go straight into a spreadsheet or ledger. The risky part is that an LLM can read a perfectly formatted IBAN with one wrong digit, and nothing downstream notices.
This post walks through a free n8n template that handles the extraction, and a small API I built that handles the checksum part. They're separate pieces: the template doesn't call the API out of the box. I'll show how to add it.
Part 1: the free n8n template
Nodes, in order:
- Gmail Trigger: polls for unread mail labelled
invoiceswith a PDF attached. - Split PDF Attachments (Code node): one item per PDF, so an email with three invoices produces three rows.
- Extract From File: reads the PDF's text layer. Scanned image-only PDFs need OCR first.
- Gemini + Structured Output Parser: returns vendor, invoice number, PO number, dates, currency, subtotal, tax, total, line items and a confidence score as strict JSON. Temperature 0, retries on rate limits.
- Normalize Invoice (Code node): cleans numbers and dates, checks that subtotal + tax = total, and marks low-confidence rows
needs_review. - Google Sheets: appends the row. Then Gmail marks the email read so it's never processed twice.
Setup takes about 10 minutes: a Gmail label and filter, a sheet with an Invoices tab, and three credentials (Gmail, Sheets, a free Gemini key from Google AI Studio).
Two things that made it more reliable:
- Strict schema over free text. The Structured Output Parser rejects anything that isn't the expected JSON, so a malformed response fails loudly instead of writing garbage.
- Check the math in code, not in the prompt. Asking Gemini "does this add up?" is slower and less reliable than one line of arithmetic in the Normalize node.
Part 2: validating payment IDs with an API
Extraction confidence doesn't tell you whether an IBAN is real. The ISO 13616 mod-97 checksum does. I put that, plus a few related checks, in a Cloudflare Worker:
- IBAN: country, length, mod-97 checksum, SEPA membership
- BIC: format and country
- EU VAT: format, plus an optional live lookup against the EU's VIES service
- UK VAT: format and checksum
- US EIN: format and IRS prefix (EINs have no check digit, so that's as far as honest validation goes)
Up to 50 identifiers per batch request. Here's a real response from the keyless demo endpoint:
curl "https://invoice-validator.mohamed-bahaa53000.workers.dev/demo/v1/iban?value=DE89370400440532013000"
{
"iban": "DE89370400440532013000",
"country": "DE",
"check_digits": "89",
"bban": "370400440532013000",
"valid": true,
"formatted": "DE89 3704 0044 0532 0130 00",
"sepa": true,
"errors": []
}
The demo allows 10 calls per IP per day without a key.
Why a Worker rather than an n8n Code node? Mostly reuse: the same check is useful from Make, Zapier or a backend, and it's stateless, so it runs at the edge in milliseconds. It also isolates the slow part. VIES throttles by member state, so when it's unavailable the API returns checked: false with a reason instead of a false "invalid".
Part 3: wiring them together yourself
After Normalize Invoice, add an HTTP Request node:
- Method: POST, to the
/v1/batchendpoint from the RapidAPI listing - Headers:
X-RapidAPI-KeyandX-RapidAPI-Host - Body:
{
"items": [
{ "id": "INV-1042-iban", "type": "iban", "value": "DE89370400440532013000" },
{ "id": "INV-1042-vat", "type": "eu_vat", "value": "DE123456789", "live": true }
]
}
In n8n, map each value with an expression from the previous node, for example $json.invoice_number, $json.vendor_iban and $json.vendor_vat.
You'll need to add vendor_iban and vendor_vat to the Gemini schema first. Then treat valid: false as "needs review", and checked: false from VIES as "verify manually", not as a rejection. A person sees exactly why a row was flagged.
What I took away
- Fail open to a human, never closed to the ledger. Anything that can time out should route to review.
- Batch external checks. One call per identifier multiplies latency and quota.
- Keep each piece honest about what it does. The template extracts; the API validates; you decide how strict to be.
Links
- Free n8n template: https://mohabaha0.gumroad.com/l/ap-invoice-triage-free
- Invoice & Payment ID Validator on RapidAPI: https://rapidapi.com/MohamedBahaa/api/invoice-payment-id-validator
Feedback on either is welcome, especially edge cases where the extraction or the validation gets it wrong.
來源:DEV Community · dev.to