DokladOID - Bezplatný generátor faktur pro OSVČ

Free, registration-free generátor faktur. Vložíš IČO, ARES auto-vyplní, přidáš položky s DPH, stáhneš PDF s QR platebním kódem. Vše za 30 sekund.

Next.jsTypeScriptARES APIPDF generatorQR codesVercel

Faktura za 30 s

Brief

DokladOID je nejjednodušší online generátor faktur pro české OSVČ. Cílí na uživatele, kteří fakturují 3–10× ročně - řemeslník, který občas vystaví fakturu firmě, lektor, který má jednu eventovou zakázku, freelancer mimo IT. Ti nepotřebují účetní SaaS s recurring fee, potřebují PDF s QR kódem za půl minuty bez registrace.

Cena: zdarma, bez accountu, bez emailu (pokud nechceš). Monetizace později přes affiliate (banky, Stripe Atlas-like services), ne přes subscription. Vědomě postavený jako lead magnet pro DokladBot (placené pokročilé funkce) a Marušku (lidská účetní).

Proč "no registration" je killer feature

Klasický invoice generator vyžaduje:

  1. Registrace (email + heslo)
  2. Verifikace emailu
  3. První onboarding (zadáš IČO firmy, banku, šablonu)
  4. Pak teprve můžeš fakturovat

To je 3–5 minut overhead pro uživatele, který chce vystavit jednu fakturu. Pro pravidelně fakturujícího OSVČ je to ok (amortizuje se), pro toho sporadického je to friction, kvůli kterému jde do Excelu, ten otevře fakturu z roku 2019 a 20 minut tam upravuje data.

DokladOID jde rovnou do flow:

[1. IČO]  →  [2. Položky]  →  [3. Stáhni PDF]
   ↑              ↑                ↑
ARES auto-fill   live preview    QR + SPD code

Žádný account, žádný onboarding. State žije v URL hash (base64-encoded JSON), takže si fakturu můžeš bookmarknout nebo poslat odkaz účetní. Když uživatel ovou stejnou fakturu o měsíc později chce duplikovat, otevře bookmark, klikne stáhnout. Hotovo.

ARES API integrace + caching

ARES je oficiální český registr ekonomických subjektů. Volné API, ale pomalé (~600–1500 ms) a občas nestabilní. Pro UX, kde uživatel napíše IČO a čeká auto-fill, je p95 1500 ms peklo.

Šel jsem do agresivního cache layeru přes Vercel Runtime Cache (24h TTL):

// src/lib/ares.ts
import { cache } from '@/lib/runtime-cache';
 
interface AresCompany {
  ico: string;
  dic?: string;
  name: string;
  address: { street: string; city: string; zip: string };
  fetchedAt: number;
}
 
export async function lookupAres(ico: string): Promise<AresCompany | null> {
  const cleaned = ico.replace(/\s/g, '');
  if (!/^\d{8}$/.test(cleaned)) return null;
 
  return cache.getOrSet(
    `ares:${cleaned}`,
    24 * 60 * 60, // 24 h TTL
    async () => {
      const res = await fetch(
        `https://ares.gov.cz/ekonomicke-subjekty-v-be/rest/ekonomicke-subjekty/${cleaned}`,
        { signal: AbortSignal.timeout(2500) }
      );
 
      if (!res.ok) return null;
 
      const data = await res.json();
      return {
        ico: cleaned,
        dic: data.dic,
        name: data.obchodniJmeno,
        address: {
          street: data.sidlo?.nazevUlice ?? '',
          city: data.sidlo?.nazevObce ?? '',
          zip: String(data.sidlo?.psc ?? ''),
        },
        fetchedAt: Date.now(),
      };
    }
  );
}

Naměřené p95 latence:

  • ARES samotné: 1 240 ms
  • DokladOID s cache miss: 1 320 ms (margin pro zpracování)
  • DokladOID s cache hit: 38 ms

Cache hit rate v produkci ~78 %, protože těch 50 nejčastějších IČ tvoří většinu B2B vztahů (stejní velcí odběratelé pro freelancery).

Server-side PDF generation

PDF je server-side render přes pdfkit (zachovává reproducibilní renderování napříč prohlížeči, na rozdíl od html2pdf v klientu, který je zranitelný na změny Chrome verze).

// src/app/api/invoice/pdf/route.ts
import PDFDocument from 'pdfkit';
import type { Invoice } from '@/types/invoice';
 
export async function POST(req: Request) {
  const invoice = (await req.json()) as Invoice;
 
  const doc = new PDFDocument({ size: 'A4', margin: 50 });
  const chunks: Buffer[] = [];
  doc.on('data', (c) => chunks.push(c));
 
  // Header
  doc.font('Helvetica-Bold').fontSize(20).text('FAKTURA', 50, 50);
  doc.fontSize(10).text(`č. ${invoice.number}`, 50, 75);
 
  // Supplier / customer dvousloupcově
  drawAddressBlock(doc, 50, 110, 'Dodavatel', invoice.supplier);
  drawAddressBlock(doc, 320, 110, 'Odběratel', invoice.customer);
 
  // Položky table
  drawItemsTable(doc, 50, 240, invoice.items);
 
  // Total + DPH breakdown
  drawTotals(doc, 350, 500, invoice);
 
  // QR platba (CZ standard)
  const qrPng = await renderQrPayment(invoice);
  doc.image(qrPng, 50, 600, { width: 120 });
 
  doc.end();
  await new Promise((r) => doc.on('end', r));
  const pdfBuffer = Buffer.concat(chunks);
 
  return new Response(pdfBuffer, {
    status: 200,
    headers: {
      'Content-Type': 'application/pdf',
      'Content-Disposition': `attachment; filename="${invoice.number}.pdf"`,
    },
  });
}

PDF generation latence p95 180 ms na Vercel serverless (cold start +400 ms, ale runtime caching pdfkit modulu řeší).

QR kód: český SPD formát

QR platba je standardizovaná Českou bankovní asociací jako SPD (Short Payment Descriptor). Formát:

SPD*1.0*ACC:CZ6508000000192000145399*AM:1500.00*CC:CZK*MSG:Faktura č. 2026003

Pole oddělená *, hodnoty po :. Stačí to vykreslit jako QR (libovolná knihovna, použil jsem qrcode):

import QRCode from 'qrcode';
 
export async function renderQrPayment(invoice: Invoice): Promise<Buffer> {
  const spd = [
    'SPD',
    '1.0',
    `ACC:${invoice.supplier.iban}`,
    `AM:${invoice.totalGross.toFixed(2)}`,
    `CC:${invoice.currency}`,
    `MSG:Faktura ${invoice.number}`,
    `X-VS:${invoice.number}`, // variabilní symbol
  ].join('*');
 
  return QRCode.toBuffer(spd, { type: 'png', width: 240, margin: 1 });
}

Detail: X-VS (variabilní symbol) by měl být numerický a maximálně 10 znaků - implementoval jsem normalizaci ze invoice.number (která může být 2026/003).

Performance budget - 30 s end-to-end

Celý flow má rozpočet 30 sekund od landing page po stažený PDF:

KrokCílNaměřeno
Landing → vyplnění IČOuživatelem~5 s
ARES lookup< 1.5 s1.24 s p95
Vyplnění položekuživatelem~15 s
Klik "Stáhnout" → PDF< 500 ms180 ms p95
Total user-perceived< 30 s~22 s median

Pod foldem je timer s dramatickou animací "ty jsi vystavil fakturu za 22 sekund", aby si uživatel uvědomil, že to je rychlé. Zní to triviálně, ale signál "tahle aplikace mi šetří čas" je důvod, proč se vrátí.

DokladOID vs DokladBot

DokladOIDDokladBot
Cílone-off fakturyrecurring účetnictví
Registraceneano
Cenazdarma199 Kč/měs
AIneano (kategorizace, výkazy)
StorageURL statePostgres + history
Target usersporadický fakturantaktivní OSVČ

Tyto dva produkty se nepřekrývají - kdo fakturuje 5× ročně, nikdy nezaplatí 199/měs. Kdo fakturuje 50× měsíčně, nemůže si dovolit DokladOID workflow bez historie.

Lessons

  • No-registration je marketingová zbraň, ne lenost developera. Konverze (počet stažených PDF / unikátní návštěvníci) je 31 %, oproti ~8 % u SaaS competitors s registrací.
  • URL state je underrated. ?invoice=base64({...}) umožňuje sdílení, bookmarking i undo přes prohlížeč.
  • Vercel Runtime Cache pro ARES dela 78 % cache hit ratio. Stačí pro 99 % uživatelů p95 < 50 ms.
  • pdfkit je víc nudný a víc spolehlivý než puppeteer-based PDF. Žádné Chrome dependency, žádné cold start drama.