Stripe payments to invoices
Seven n8n workflows turn Stripe payments into German invoices (email with PDF) and a Telegram message. No double invoice, no lost event.
Problem
Stripe delivers payment events by webhook, sometimes more than once, and expects a quick answer. A webhook that acknowledges an event before storing it loses that event when the database is down. Processing the same event twice creates duplicate invoices and messages. And failures go unnoticed when nobody is alerted.
Solution
Intake checks the Stripe signature (HMAC-SHA256) and rejects timestamps older than 5 minutes. It answers only after the event is stored; if the insert fails it answers 500, so Stripe retries.
Every minute a Processor claims up to 10 events atomically (FOR UPDATE SKIP LOCKED). Each paid event gets exactly one invoice, enforced by UNIQUE constraints in PostgreSQL. The email, the PDF and the Telegram message are built from the stored invoice row only, so every retry produces the same document.
A Monitor workflow reports dead or stuck events by Telegram and email; a failed event can be replayed with a reason and an audit row. An outside heartbeat reports when the system has been silent for about 15 minutes.
Results
Tech stack
- n8n
- PostgreSQL
- TypeScript (n8n Workflow SDK)
- Docker Compose (WSL)
- Gotenberg
- Mailpit
- Telegram Bot API
- Healthchecks.io
- Stripe
- PowerShell
Screenshots



Runs only in Stripe's sandbox on my own machine. The invoices are a technical demo and do not claim compliance with German invoicing rules (§ 14 UStG, GoBD). The repository cannot be cloned and run yet; that is the next step.