Vergabeautomat
German public contracts are spread across the EU tender database and the federal notice service. Vergabeautomat reads both every day and helps companies find relevant public tenders.
My own product. I do all of it: product, code, infrastructure, support.
- Stage
- Live, pre-revenue
- Site
- vergabeautomat.de
- Not yet
- Revenue. There is no paying customer.


Sources
Two integrations cover the two halves of the market. TED is the EU’s tender database for contracts above the EU threshold, and it publishes 700,000+ notices a year across the EU. Below the threshold, German contracts go to the federal notice service, BKMS, which 100+ platforms must publish to by law. One integration covers the German half, so I did not write a parser per portal.
Search
Search runs three arms in one PostgreSQL database: exact words, a substring arm that matches each word’s German stem prefix, and meaning through pgvector. PostgreSQL does not split German compounds, so a search for Automatisierung could not find Prozessautomatisierung until the substring arm existed. Adding a keyword score to a similarity score put the notices containing the exact words typed at the bottom of the list, so the arms are now fused by rank position. The embedding model runs in my own container, which keeps the cost per search inside the product’s economics.
Trade-offs
I removed the relevance verdict
Five weighted signals used to add up to one verdict on each notice. The only relevance labels were ones I wrote myself, for one company profile, and I could not validate the weighting against them well enough to defend it. I removed the verdict and kept the signals visible, so the user of the product sees why a notice appeared. It makes the screen busier and the first impression weaker.
A missing value says so
When a notice omits the contract value, the value signal says it cannot be computed instead of scoring zero. A zero would count against the notice for information the authority did not publish.
No confidence threshold for codes
The product suggests procurement codes from a company’s own description. The first measurement had tested a different design from the one that shipped. Measuring the shipped one showed correct and wrong codes scoring in overlapping bands, and the top-scoring candidate was wrong. No threshold can separate them, so the screen pre-selects nothing and the company chooses.
Built with
- Code
- TypeScript, Next.js
- Database
- PostgreSQL with pgvector
- Embeddings
- Self-hosted, in my own container
- Runs on
- A VPS I provision and operate. Docker, Coolify, GitHub Actions
- Records
- 51 decision records and 316 test files, on 4 October 2026