Download index.html from getreadystack/ksef-fa3-invoice-lint: direct link, hf CLI and curl.
- Browser
- Download file 46.1 kB
-
https://huggingface.co/spaces/getreadystack/ksef-fa3-invoice-lint/resolve/main/index.html
- Command line
-
hf download hf://spaces/getreadystack/ksef-fa3-invoice-lint/index.html
-
curl -L -o index.html https://huggingface.co/spaces/getreadystack/ksef-fa3-invoice-lint/resolve/main/index.html
46.1 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>KSeF fa3 Invoice check — check invoice xml free</title> | |
| <meta name="description" content="This browser tool checks structured KSeF invoice XML against the FA(3) schema for namespaces, system codes, NIP, decimal separators, and correction references."> | |
| <style> | |
| :root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512} | |
| .wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px} | |
| textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box} | |
| .bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer} | |
| input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px} | |
| table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65} | |
| .sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600} | |
| .buylink{display:inline-block;margin-top:10px;padding:9px 14px;border-radius:8px;background:#1f5f46;color:#fff;text-decoration:none;font-weight:600} | |
| .note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa} | |
| </style> | |
| <script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script> | |
| <!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/ksef-fa3-invoice-lint"></head> | |
| <body> | |
| <div class="wrap"> | |
| <h1>KSeF fa3 Invoice check — check invoice xml free</h1> | |
| <p class="lede">Lint Polish KSeF structured invoice XML against the FA(3) schema before you send it: namespace, kodSystemowy, NIP, decimal separators and correction references. Runs entirely in your browser — nothing is uploaded.</p> | |
| <textarea id="src" spellcheck="false"><?xml version="1.0" encoding="ISO-8859-2"?> | |
| <Faktura xmlns="http://crd.gov.pl/wzor/2023/06/29/12648/"> | |
| <Naglowek> | |
| <KodFormularza kodSystemowy="FA (2)" wersjaSchemy="1-0E">FA</KodFormularza> | |
| <WariantFormularza>2</WariantFormularza> | |
| <DataWytworzeniaFa>2026-09-14</DataWytworzeniaFa> | |
| </Naglowek> | |
| <Podmiot1> | |
| <DaneIdentyfikacyjne> | |
| <NIP>PL 526-231-11-82</NIP> | |
| <Nazwa>Kowalski Systemy Sp. z o.o.</Nazwa> | |
| </DaneIdentyfikacyjne> | |
| </Podmiot1> | |
| <Podmiot2> | |
| <DaneIdentyfikacyjne> | |
| <NIP>1234567890</NIP> | |
| <Nazwa></Nazwa> | |
| </DaneIdentyfikacyjne> | |
| </Podmiot2> | |
| <Fa> | |
| <KodWaluty>zl</KodWaluty> | |
| <P_1>14.09.2026</P_1> | |
| <P_2></P_2> | |
| <P_13_1>4 200,00</P_13_1> | |
| <P_14_1>966,00</P_14_1> | |
| <P_15>5166,00</P_15> | |
| <Adnotacje> | |
| <P_16>2</P_16> | |
| <P_17>2</P_17> | |
| </Adnotacje> | |
| <RodzajFaktury>KOR</RodzajFaktury> | |
| <FaWiersz> | |
| <NrWierszaFa>1</NrWierszaFa> | |
| <P_7>Wdrozenie integracji KSeF</P_7> | |
| <P_8B>1,00</P_8B> | |
| <P_9A>4 200,00</P_9A> | |
| <P_11>4200,00</P_11> | |
| <P_12>23</P_12> | |
| </FaWiersz> | |
| </Fa> | |
| </Faktura></textarea> | |
| <div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div> | |
| <div id="out" aria-live="polite"></div> | |
| <div id="paid"><strong>Free here:</strong> Lints the invoice XML file you have open and names every field KSeF will reject, with the exact value it wants. <strong>In the editor:</strong> Scans every invoice XML in the workspace in one run and writes a dated REPORT.md you keep as your own audit evidence. — that part asks for a licence key. <a href="https://getreadystack.com/api/buy/cl/polar_cl_JEQ1km4V0rbblgu9hwXyGlYM9I06o2ERzguUP2O8bd9" class="buylink">Sweep every invoice XML in the workspace + the dated REPORT.md — $29 once, one licence key per person or CI seat</a></div> | |
| <p class="note">Same engine as the VS Code extension, byte for byte.</p> | |
| </div> | |
| <script>var KSEF_RULES = [ | |
| {"id": "fa3_namespace", "sev": "err", "msg": "Root \u003cFaktura\u003e must carry the FA(3) namespace xmlns=\"http://crd.gov.pl/wzor/2025/06/25/13775/\". Any other CRD template is an FA(2)-era namespace and KSeF rejects the document."}, | |
| {"id": "kod_systemowy", "sev": "err", "msg": "KodFormularza must have kodSystemowy=\"FA (3)\" - with one space before the bracket."}, | |
| {"id": "wersja_schemy", "sev": "err", "msg": "KodFormularza must have wersjaSchemy=\"1-0E\" for the FA(3) structure."}, | |
| {"id": "wariant_formularza", "sev": "err", "msg": "\u003cWariantFormularza\u003e must be 3 for FA(3)."}, | |
| {"id": "data_wytworzenia", "sev": "err", "msg": "\u003cDataWytworzeniaFa\u003e is xs:dateTime, not a date: use 2026-09-14T09:12:31Z form."}, | |
| {"id": "nip_format", "sev": "err", "msg": "\u003cNIP\u003e must be exactly 10 digits - no PL prefix, no dashes, no spaces."}, | |
| {"id": "kod_waluty", "sev": "err", "msg": "\u003cKodWaluty\u003e must be a 3-letter ISO 4217 code such as PLN or EUR."}, | |
| {"id": "p_1_data", "sev": "err", "msg": "\u003cP_1\u003e (issue date) must be ISO yyyy-mm-dd, not the Polish dd.mm.yyyy form."}, | |
| {"id": "p_2_numer", "sev": "err", "msg": "\u003cP_2\u003e (invoice number) must be present and non-empty."}, | |
| {"id": "rodzaj_faktury", "sev": "err", "msg": "\u003cRodzajFaktury\u003e must be one of VAT, KOR, ZAL, ROZ, UPR, KOR_ZAL, KOR_ROZ."}, | |
| {"id": "decimal_comma", "sev": "err", "msg": "Amounts use a dot decimal separator. A Polish locale comma makes the amount unparseable for KSeF."}, | |
| {"id": "amount_space", "sev": "err", "msg": "Amounts carry no thousands separator and no spaces - digits and one dot only."}, | |
| {"id": "encoding_utf8", "sev": "err", "msg": "The XML declaration must say encoding=\"UTF-8\"; Polish diacritics break under any other encoding."}, | |
| {"id": "adnotacje_flags", "sev": "err", "msg": "\u003cAdnotacje\u003e must carry the P_16, P_17, P_18 and P_18A flags, each 1 or 2."}, | |
| {"id": "korekta_ref", "sev": "err", "msg": "A correction invoice must identify the invoice it corrects in \u003cDaneFaKorygowanej\u003e."}, | |
| {"id": "placeholder_data", "sev": "err", "msg": "Placeholder value left in the document - a generated sample identifier, not real party data."}, | |
| {"id": "podmiot_nazwa", "sev": "err", "msg": "Podmiot1 (seller) and Podmiot2 (buyer) each need identification with a non-empty \u003cNazwa\u003e or a surname."}, | |
| {"id": "penalty_clock", "sev": "info", "msg": "Penalty clock:"} | |
| ] | |
| ;</script> | |
| <script>// KSeF FA(3) invoice lint - one brain for the VS Code extension and the free web page. | |
| (function (root) { | |
| var RULES = (typeof module !== 'undefined' && module.exports) ? require('./rules.json') : root.KSEF_RULES; | |
| var FA3_NS = 'http://crd.gov.pl/wzor/2025/06/25/13775/'; | |
| var PENALTY_DAY = '2027-01-01'; | |
| var RODZAJ = ['VAT', 'KOR', 'ZAL', 'ROZ', 'UPR', 'KOR_ZAL', 'KOR_ROZ']; | |
| var AMOUNT_EL = /<(P_8B|P_9A|P_9B|P_11|P_11A|P_13_\d|P_14_\d|P_15|KursWaluty)>([^<]*)<\/\1>/g; | |
| var PLACEHOLDER = /(1234567890|0000000000|9999999999|XXXXXXXXXX|PLACEHOLDER|TODO|example\.com|Nazwa Firmy)/g; | |
| function byId(id) { | |
| for (var i = 0; i < RULES.length; i++) { if (RULES[i].id === id) return RULES[i]; } | |
| return { id: id, sev: 'err', msg: id }; | |
| } | |
| function lineAt(text, idx) { return text.slice(0, idx < 0 ? 0 : idx).split('\n').length; } | |
| function one(text, re) { re.lastIndex = 0; return re.exec(text); } | |
| function days(a, b) { return Math.round((Date.parse(b) - Date.parse(a)) / 86400000); } | |
| function check(text, opts) { | |
| text = String(text || ''); | |
| opts = opts || {}; | |
| var today = opts.today || '2026-09-14'; | |
| var F = []; | |
| function add(id, line, extra) { | |
| var r = byId(id); | |
| F.push({ check: r.id, sev: r.sev, msg: extra ? r.msg + ' ' + extra : r.msg, line: line || 1 }); | |
| } | |
| var m, i; | |
| var faIdx = text.indexOf('<Faktura'); | |
| var ns = one(text, /<Faktura[^>]*xmlns\s*=\s*"([^"]*)"/); | |
| if (!ns) add('fa3_namespace', faIdx >= 0 ? lineAt(text, faIdx) : 1, 'Found: no xmlns on <Faktura>.'); | |
| else if (ns[1] !== FA3_NS) add('fa3_namespace', lineAt(text, ns.index), 'Found: ' + ns[1]); | |
| var ks = one(text, /kodSystemowy\s*=\s*"([^"]*)"/); | |
| if (!ks) add('kod_systemowy', 1, 'Found: no kodSystemowy attribute.'); | |
| else if (ks[1] !== 'FA (3)') add('kod_systemowy', lineAt(text, ks.index), 'Found: "' + ks[1] + '".'); | |
| var ws = one(text, /wersjaSchemy\s*=\s*"([^"]*)"/); | |
| if (!ws) add('wersja_schemy', 1, 'Found: no wersjaSchemy attribute.'); | |
| else if (ws[1] !== '1-0E') add('wersja_schemy', lineAt(text, ws.index), 'Found: "' + ws[1] + '".'); | |
| var wf = one(text, /<WariantFormularza>\s*([^<]*)<\/WariantFormularza>/); | |
| if (!wf) add('wariant_formularza', 1, 'Found: element missing.'); | |
| else if (wf[1].trim() !== '3') add('wariant_formularza', lineAt(text, wf.index), 'Found: ' + wf[1].trim() + '.'); | |
| var dw = one(text, /<DataWytworzeniaFa>\s*([^<]*)<\/DataWytworzeniaFa>/); | |
| if (!dw) add('data_wytworzenia', 1, 'Found: element missing.'); | |
| else if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(dw[1].trim())) add('data_wytworzenia', lineAt(text, dw.index), 'Found: "' + dw[1].trim() + '".'); | |
| var reNip = /<NIP>\s*([^<]*)<\/NIP>/g; | |
| while ((m = reNip.exec(text))) { | |
| var nip = m[1].trim(); | |
| if (!/^\d{10}$/.test(nip)) add('nip_format', lineAt(text, m.index), 'Found: "' + nip + '".'); | |
| } | |
| var kw = one(text, /<KodWaluty>\s*([^<]*)<\/KodWaluty>/); | |
| if (!kw) add('kod_waluty', 1, 'Found: element missing.'); | |
| else if (!/^[A-Z]{3}$/.test(kw[1].trim())) add('kod_waluty', lineAt(text, kw.index), 'Found: "' + kw[1].trim() + '".'); | |
| var p1 = one(text, /<P_1>\s*([^<]*)<\/P_1>/); | |
| if (!p1) add('p_1_data', 1, 'Found: element missing.'); | |
| else if (!/^\d{4}-\d{2}-\d{2}$/.test(p1[1].trim())) add('p_1_data', lineAt(text, p1.index), 'Found: "' + p1[1].trim() + '".'); | |
| var p2 = one(text, /<P_2>\s*([^<]*)<\/P_2>/); | |
| if (!p2) add('p_2_numer', 1, 'Found: element missing.'); | |
| else if (!p2[1].trim()) add('p_2_numer', lineAt(text, p2.index), 'Found: empty.'); | |
| var rf = one(text, /<RodzajFaktury>\s*([^<]*)<\/RodzajFaktury>/); | |
| if (!rf) add('rodzaj_faktury', 1, 'Found: element missing.'); | |
| else if (RODZAJ.indexOf(rf[1].trim()) < 0) add('rodzaj_faktury', lineAt(text, rf.index), 'Found: "' + rf[1].trim() + '".'); | |
| AMOUNT_EL.lastIndex = 0; | |
| while ((m = AMOUNT_EL.exec(text))) { | |
| var val = m[2].trim(); | |
| var where = '<' + m[1] + '> = "' + val + '".'; | |
| if (val.indexOf(',') >= 0) add('decimal_comma', lineAt(text, m.index), where); | |
| if (/\s/.test(val)) add('amount_space', lineAt(text, m.index), where); | |
| else if (val && val.indexOf(',') < 0 && !/^-?\d+(\.\d+)?$/.test(val)) add('amount_space', lineAt(text, m.index), where); | |
| } | |
| var xd = one(text, /<\?xml[^>]*\?>/); | |
| if (!xd) add('encoding_utf8', 1, 'Found: no XML declaration.'); | |
| else if (!/encoding\s*=\s*"utf-8"/i.test(xd[0])) add('encoding_utf8', 1, 'Found: ' + xd[0].trim()); | |
| var ad = one(text, /<Adnotacje>([\s\S]*?)<\/Adnotacje>/); | |
| var adLine = ad ? lineAt(text, ad.index) : 1; | |
| var flags = ['P_16', 'P_17', 'P_18', 'P_18A']; | |
| for (i = 0; i < flags.length; i++) { | |
| var fm = ad ? new RegExp('<' + flags[i] + '>\\s*([^<]*)</' + flags[i] + '>').exec(ad[1]) : null; | |
| if (!fm) add('adnotacje_flags', adLine, 'Missing <' + flags[i] + '>.'); | |
| else if (['1', '2'].indexOf(fm[1].trim()) < 0) add('adnotacje_flags', adLine, '<' + flags[i] + '> = "' + fm[1].trim() + '".'); | |
| } | |
| if (rf && /^KOR/.test(rf[1].trim()) && !/<DaneFaKorygowanej>/.test(text)) { | |
| add('korekta_ref', lineAt(text, rf.index), 'RodzajFaktury = ' + rf[1].trim() + '.'); | |
| } | |
| PLACEHOLDER.lastIndex = 0; | |
| while ((m = PLACEHOLDER.exec(text))) add('placeholder_data', lineAt(text, m.index), 'Found: "' + m[0] + '".'); | |
| var parties = ['Podmiot1', 'Podmiot2']; | |
| for (i = 0; i < parties.length; i++) { | |
| var b = new RegExp('<' + parties[i] + '>([\\s\\S]*?)</' + parties[i] + '>').exec(text); | |
| if (!b) { add('podmiot_nazwa', 1, 'Missing <' + parties[i] + '> block.'); continue; } | |
| var nz = /<Nazwa>\s*([^<]*)<\/Nazwa>/.exec(b[1]); | |
| var person = /<Nazwisko>\s*[^<\s][^<]*<\/Nazwisko>/.test(b[1]); | |
| if ((!nz || !nz[1].trim()) && !person) add('podmiot_nazwa', lineAt(text, b.index), '<' + parties[i] + '> has no non-empty <Nazwa>.'); | |
| } | |
| var errs = 0; | |
| for (i = 0; i < F.length; i++) { if (F[i].sev === 'err') errs++; } | |
| if (errs && today < PENALTY_DAY) { | |
| add('penalty_clock', 1, errs + ' blocking errors, ' + days(today, PENALTY_DAY) + ' days before KSeF penalties resume on ' + PENALTY_DAY + '.'); | |
| } else if (errs) { | |
| add('penalty_clock', 1, errs + ' blocking errors, and the KSeF penalty grace period ended on ' + PENALTY_DAY + '.'); | |
| } | |
| F.sort(function (a, b) { return a.line - b.line; }); | |
| return { findings: F }; | |
| } | |
| var API = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length }; | |
| if (typeof module !== 'undefined' && module.exports) { module.exports = API; } | |
| if (typeof root !== 'undefined' && root) { root.KSEFENGINE = API; } | |
| })(typeof window !== 'undefined' ? window : this); | |
| </script> | |
| <script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다. | |
| ; | |
| function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); } | |
| function summaryLine(res) { | |
| const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length; | |
| return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.'; | |
| } | |
| function toText(res, label) { | |
| const f = (res && res.findings) || []; | |
| const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)]; | |
| f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); }); | |
| return lines.join('\n'); | |
| } | |
| function toHtml(res) { | |
| const f = (res && res.findings) || []; | |
| if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>'; | |
| const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join(''); | |
| return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>'; | |
| } | |
| var KSEFREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml }; | |
| if (typeof module !== 'undefined' && module.exports) module.exports = KSEFREPORT; | |
| else window.KSEFREPORT = KSEFREPORT; | |
| </script> | |
| <script> | |
| (function(){ | |
| var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today'); | |
| today.value=new Date().toISOString().slice(0,10); | |
| function run(){ try { var res=window.KSEFENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.KSEFREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } } | |
| go.onclick=run; if (src.value.trim()) run(); | |
| })(); | |
| </script> | |
| <section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://marketplace.visualstudio.com/items?itemName=ReadyStack.ksef-fa3-invoice-lint" rel="noopener" data-yj-install-door="mp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'ksef-fa3-invoice-lint',src:'mp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">VS Code Marketplace</a><a href="https://open-vsx.org/extension/readystack/ksef-fa3-invoice-lint" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'ksef-fa3-invoice-lint',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/ksef-fa3-invoice-lint" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'ksef-fa3-invoice-lint',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://www.npmjs.com/package/@readystack/ksef-fa3-invoice-lint" rel="noopener" data-yj-install-door="mcp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'ksef-fa3-invoice-lint',src:'mcp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">MCP server (npx)</a><a href="https://hub.docker.com/r/getreadystack/ksef-fa3-invoice-lint" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'ksef-fa3-invoice-lint',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">ext install ReadyStack.ksef-fa3-invoice-lint | |
| npx @readystack/ksef-fa3-invoice-lint <file> | |
| npx @readystack/ksef-fa3-invoice-lint --mcp</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/cl/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section> | |
| <section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get the full rule table as a PDF</b><div style="opacity:.78;margin:.35rem 0 .8rem">All 18 rules KSeF FA(3) Invoice Lint checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Email me the PDF</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">Sent. It arrives within the hour - check spam too.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"ksef-fa3-invoice-lint",lang:"en",source:"rule_table"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section> | |
| <section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Finds the lines KSeF will reject in a Polish structured invoice XML, before you send it</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A mid-size KSeF ERP integration project in Poland costs PLN 10,000 to PLN 50,000 and runs 2 to 4 months (ELTE-S, 2026)</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_JEQ1km4V0rbblgu9hwXyGlYM9I06o2ERzguUP2O8bd9" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section> | |
| <!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div> | |
| <script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script> | |
| <script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script> | |
| <section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-15">Updated 2026-09-15</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-15","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku68045_result_card.jpg" alt="KSeF FA(3) Invoice Lint" loading="lazy" style="max-width:100%;border-radius:6px"></p> | |
| <p>22 blocking errors in one invoice file — that is what one Polish ERP export returned when we ran it through the FA(3) rules on 2026-09-14, and the developer had no way to see them before the gateway answered.</p> | |
| <p>Since 2026-02-01 the Krajowy System e-Faktur accepts only the FA(3) structure from the largest taxpayers, and since 2026-04-01 it is the standard for every other active VAT payer in Poland. The obligation is old news. What is not is that the sanction-free transitional period ends with this year. From 2027-01-01 a KSeF failure can carry up to 100% of the VAT amount shown on the invoice, or 18.7% of the gross amount on a VAT-exempt one. On 2026-09-14 that leaves 109 days.</p> | |
| <p>The gap that costs money is smaller than the regulation. FA(3) does not live where FA(2) lived. The root element must carry xmlns="http://crd.gov.pl/wzor/2025/06/25/13775/", the form code must read kodSystemowy="FA (3)" with one space before the bracket, wersjaSchemy must read "1-0E", and WariantFormularza must be 3. Almost every published example and almost every generated snippet still carries the 2023 template. The code compiles, the XML is well-formed, and the gateway rejects it.</p> | |
| <h3>What the shipped fixtures measure</h3> | |
| <p>The extension ships two invoices. clean.xml is a valid FA(3) document: 0 findings. dirty.xml is the same invoice as FA(2)-shaped code emits it: 23 findings, 22 of them blocking, across 16 of the 18 rules.</p> | |
| <p>Six of those lines are the ones nearly every generated file gets wrong:</p> | |
| <ul><li>xmlns=".../wzor/2023/06/29/12648/" instead of ".../wzor/2025/06/25/13775/"</li><li>kodSystemowy="FA (2)" instead of kodSystemowy="FA (3)"</li><li><WariantFormularza>2 instead of 3</li><li><NIP>PL 526-231-11-82</NIP> instead of <NIP>5262311182</NIP></li><li><P_15>5166,00</P_15> instead of <P_15>5166.00</P_15></li><li><DataWytworzeniaFa>2026-09-14</DataWytworzeniaFa> instead of the xs:dateTime form 2026-09-14T09:12:31Z</li></ul> | |
| <p>The fifth is the quietest and the most Polish. A comma is the decimal separator in every Polish interface and every spreadsheet; in the XML it makes the amount unparseable, and one formatter left on the system locale puts it on every line your system produces.</p> | |
| <h3>Why the gateway is not the answer</h3> | |
| <p>KSeF validates — after the call. You build the session, sign, send, and get back a schema code, not a line number in your file. When you are fixing a batch export, that loop is minutes long and reports one failure at a time.</p> | |
| <p>The lint runs on the text. Open the invoice XML, run KSeF FA(3): Check This File, and every rejectable line is marked in place with the value the schema wants. 18 rules cover the namespace and the KodFormularza attributes, the NIP shape, the ISO 4217 currency code, ISO dates, dot decimals, the P_16 to P_18A flags, correction invoices that never say which invoice they correct, UTF-8, and sample identifiers such as 1234567890 left behind by a generator.</p> | |
| <p>The last rule is a clock: it counts the blocking errors and the days left before penalties resume on 2027-01-01.</p> | |
| <h3>Free, and where the key starts</h3> | |
| <p>Checking one file is free and complete — in the editor, or on the web page, which runs the same engine in the browser. No key, no account, no locked answer.</p> | |
| <p>The licence key opens a different axis: scope. Sweep Workspace runs every invoice XML in the folder in one pass and writes a dated REPORT.md — file, line, rule, found value, wanted value — that you keep. $29 once, one licence key per person or CI seat, 7-day full refund. A mid-size KSeF ERP integration in Poland costs PLN 10,000 to PLN 50,000.</p> | |
| <p>Not tax advice — verify against the current Ministry of Finance publication.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku68045_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku68045_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does KSeF FA(3) Invoice Lint actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads a Polish structured invoice XML and reports every line the KSeF gateway will reject, with the value the FA(3) schema wants instead. 18 rules cover the namespace, KodFormularza attributes, WariantFormularza, NIP format, currency code, ISO dates, dot decimal separators, the P_16 to P_18A annotation flags and correction references.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is it for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Polish VAT-registered sellers and the ERP or billing developers who generate their KSeF XML, in SAP, Microsoft Dynamics, Comarch or an in-house system. It is aimed at the person who has an invoice file open and needs to know why the gateway said no, not at the accountant who only sees the finished document.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why is a chatbot or the free gateway not enough?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Generative models still emit the FA(2) namespace and the FA(2) kodSystemowy, because most published examples predate the 2025/06/25/13775 template. The KSeF gateway does validate, but it answers after the call, with a schema code rather than a line, and each round trip runs through your integration. The lint answers in the editor.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs a licence key?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free and complete for one file: open an invoice XML, run the lint, get every finding with line numbers, in the editor or on the web page, with no key and no account. The licence key opens a different axis, scope: sweeping every invoice XML in the workspace in one run and writing a dated REPORT.md you own and keep.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What would this cost otherwise?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A mid-size KSeF integration project in Poland runs PLN 10,000 to PLN 50,000 over 2 to 4 months, and most of that budget is spent making the XML pass validation. From 2027-01-01 a KSeF failure can carry up to 100% of the invoice VAT. The lint is $29 once, for one person or one CI seat.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask ChatGPT or another AI chat?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. KSeF FA(3) Invoice Lint checks the file you open against 18 rules from a rule set dated 2026-09-20, and points at the exact line. For a filing, an audit or a client you need that dated result on your own files.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does KSeF FA(3) Invoice Lint actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads a Polish structured invoice XML and reports every line the KSeF gateway will reject, with the value the FA(3) schema wants instead. 18 rules cover the namespace, KodFormularza attributes, WariantFormularza, NIP format, currency code, ISO dates, dot decimal separators, the P_16 to P_18A annotation flags and correction references."}}, {"@type": "Question", "name": "Who is it for?", "acceptedAnswer": {"@type": "Answer", "text": "Polish VAT-registered sellers and the ERP or billing developers who generate their KSeF XML, in SAP, Microsoft Dynamics, Comarch or an in-house system. It is aimed at the person who has an invoice file open and needs to know why the gateway said no, not at the accountant who only sees the finished document."}}, {"@type": "Question", "name": "Why is a chatbot or the free gateway not enough?", "acceptedAnswer": {"@type": "Answer", "text": "Generative models still emit the FA(2) namespace and the FA(2) kodSystemowy, because most published examples predate the 2025/06/25/13775 template. The KSeF gateway does validate, but it answers after the call, with a schema code rather than a line, and each round trip runs through your integration. The lint answers in the editor."}}, {"@type": "Question", "name": "What is free and what needs a licence key?", "acceptedAnswer": {"@type": "Answer", "text": "Free and complete for one file: open an invoice XML, run the lint, get every finding with line numbers, in the editor or on the web page, with no key and no account. The licence key opens a different axis, scope: sweeping every invoice XML in the workspace in one run and writing a dated REPORT.md you own and keep."}}, {"@type": "Question", "name": "What would this cost otherwise?", "acceptedAnswer": {"@type": "Answer", "text": "A mid-size KSeF integration project in Poland runs PLN 10,000 to PLN 50,000 over 2 to 4 months, and most of that budget is spent making the XML pass validation. From 2027-01-01 a KSeF failure can carry up to 100% of the invoice VAT. The lint is $29 once, for one person or one CI seat."}}, {"@type": "Question", "name": "Why not just ask ChatGPT or another AI chat?", "acceptedAnswer": {"@type": "Answer", "text": "A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. KSeF FA(3) Invoice Lint checks the file you open against 18 rules from a rule set dated 2026-09-20, and points at the exact line. For a filing, an audit or a client you need that dated result on your own files."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:68045,slug:"ksef-fa3-invoice-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/dashboard-ui-kit-eu-vat-billing"><span class="yj-rel-t">Dashboard UI Kit for EU SaaS Billing — VAT ID, Reverse Charge & OSS States (Fi</span><span class="yj-rel-p">$168</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ksef-10k-exemption-watch"><span class="yj-rel-t">KSeF 10k Exemption Watch - the invoice that ends it</span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/reverse-charge-vat-invoice-checker"><span class="yj-rel-t">Reverse Charge VAT Invoice Checker 2026</span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cbpr-address-lint"><span class="yj-rel-t">CBPR+ Structured Address Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/einvoice-mandate-lint"><span class="yj-rel-t">E-Invoice Mandate Lint - EU 2026</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/en16931-einvoice-lint"><span class="yj-rel-t">EN 16931 e-Invoice Lint</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body> | |
| </html> | |