kassza 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +48 -0
- package/README.md +152 -22
- package/agents/README.md +6 -1
- package/agents/api.md +64 -12
- package/agents/pitfalls.md +12 -1
- package/agents/recipes.md +67 -8
- package/agents/skills/kassza/SKILL.md +3 -0
- package/agents/skills/migrate-from-szamlazz-js/SKILL.md +39 -0
- package/dist/batch/index.cjs +346 -0
- package/dist/batch/index.d.cts +91 -0
- package/dist/batch/index.d.ts +91 -0
- package/dist/batch/index.js +339 -0
- package/dist/cli.cjs +105 -14
- package/dist/cli.js +104 -13
- package/dist/{client-C-PdfL_P.cjs → client-CLFvJCVW.cjs} +358 -181
- package/dist/{client-CfaS1-Jx.js → client-Cvf-hTz_.js} +311 -152
- package/dist/{client-6MkeuFqD.d.ts → client-DeWWQ-RZ.d.ts} +99 -26
- package/dist/{client-B5FryKxJ.d.cts → client-SVZu25MB.d.cts} +99 -26
- package/dist/{context-DXNbTPwz.d.cts → context-CFNKzStE.d.cts} +82 -58
- package/dist/{context-BxQlIlug.d.ts → context-kb33TgzE.d.ts} +82 -58
- package/dist/cookie-stores/index.cjs +21 -150
- package/dist/cookie-stores/index.d.cts +4 -63
- package/dist/cookie-stores/index.d.ts +4 -63
- package/dist/cookie-stores/index.js +3 -144
- package/dist/create-CflXrPip.js +204 -0
- package/dist/create-CvUvLUaT.cjs +257 -0
- package/dist/{create-once-DgMtKKcG.cjs → create-once-9yxR_Er_.cjs} +285 -33
- package/dist/create-once-Bh6fOWkW.d.cts +20 -0
- package/dist/{create-once-Cz621l8r.js → create-once-Ca2gMk1h.js} +250 -34
- package/dist/create-once-VKp0tVow.d.ts +20 -0
- package/dist/data-link/index.cjs +4 -4
- package/dist/data-link/index.d.cts +2 -52
- package/dist/data-link/index.d.ts +2 -52
- package/dist/data-link/index.js +4 -4
- package/dist/delegation/index.cjs +4 -4
- package/dist/delegation/index.d.cts +2 -2
- package/dist/delegation/index.d.ts +2 -2
- package/dist/delegation/index.js +4 -4
- package/dist/{errors-DLrb0g64.js → errors-DtN4g5Z9.js} +9 -1
- package/dist/{errors-DxeuTslP.cjs → errors-EE96_6D_.cjs} +20 -0
- package/dist/{get-Csm2n0rZ.cjs → get-BdMTseh4.cjs} +9 -183
- package/dist/{get-DT3JEgQ6.js → get-CZEShCcj.js} +4 -124
- package/dist/index-BhUPY_EH.d.cts +109 -0
- package/dist/index-BqGgQ4t3.d.ts +109 -0
- package/dist/{index-CYAGCdKJ.d.cts → index-C-7yWV7L.d.cts} +24 -1
- package/dist/{index-CYAGCdKJ.d.ts → index-C-7yWV7L.d.ts} +24 -1
- package/dist/index.cjs +19 -5
- package/dist/index.d.cts +10 -20
- package/dist/index.d.ts +10 -20
- package/dist/index.js +6 -6
- package/dist/ipn/index.cjs +26 -5
- package/dist/ipn/index.d.cts +12 -1
- package/dist/ipn/index.d.ts +12 -1
- package/dist/ipn/index.js +26 -6
- package/dist/{issue-AGRohSm7.cjs → issue-Bin4tKD_.cjs} +416 -342
- package/dist/{issue-DtSLpVdJ.js → issue-DMA1Nbr1.js} +394 -266
- package/dist/journal/index.cjs +454 -0
- package/dist/journal/index.d.cts +18 -0
- package/dist/journal/index.d.ts +18 -0
- package/dist/journal/index.js +445 -0
- package/dist/journal-DvI81Kt7.d.cts +114 -0
- package/dist/journal-Y9qrIB8G.d.ts +114 -0
- package/dist/mcp/index.cjs +1 -1
- package/dist/mcp/index.d.cts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/money/index.cjs +2 -1
- package/dist/money/index.d.cts +2 -2
- package/dist/money/index.d.ts +2 -2
- package/dist/money/index.js +2 -2
- package/dist/{money-t7uy1n91.js → money-Cw457SD6.js} +95 -3
- package/dist/{money-BxytJW6f.cjs → money-K9j0wPit.cjs} +99 -1
- package/dist/nav/index.cjs +2 -2
- package/dist/nav/index.d.cts +1 -1
- package/dist/nav/index.d.ts +1 -1
- package/dist/nav/index.js +2 -2
- package/dist/{nav-BEwcX7-N.cjs → nav-BNbc8U0R.cjs} +1 -1
- package/dist/{nav-CK1WgYo7.js → nav-BcCerwWS.js} +1 -1
- package/dist/node/index.cjs +124 -0
- package/dist/node/index.d.cts +35 -0
- package/dist/node/index.d.ts +35 -0
- package/dist/node/index.js +120 -0
- package/dist/observe/index.cjs +311 -0
- package/dist/observe/index.d.cts +53 -0
- package/dist/observe/index.d.ts +53 -0
- package/dist/observe/index.js +303 -0
- package/dist/once-BN_3B5OF.cjs +103 -0
- package/dist/once-CqqZxsXG.js +74 -0
- package/dist/{parse-C608ehqM.js → parse-Cr7yQ3_z.js} +2 -2
- package/dist/{parse-BJj-aqKy.cjs → parse-DOA2XQ3e.cjs} +2 -2
- package/dist/payments/barion.cjs +26 -2
- package/dist/payments/barion.d.cts +2 -2
- package/dist/payments/barion.d.ts +2 -2
- package/dist/payments/barion.js +26 -2
- package/dist/payments/index.cjs +7 -2
- package/dist/payments/index.d.cts +4 -4
- package/dist/payments/index.d.ts +4 -4
- package/dist/payments/index.js +3 -3
- package/dist/payments/paypal.cjs +16 -2
- package/dist/payments/paypal.d.cts +2 -2
- package/dist/payments/paypal.d.ts +2 -2
- package/dist/payments/paypal.js +16 -2
- package/dist/payments/revolut.cjs +16 -2
- package/dist/payments/revolut.d.cts +2 -2
- package/dist/payments/revolut.d.ts +2 -2
- package/dist/payments/revolut.js +16 -2
- package/dist/payments/simplepay.cjs +36 -4
- package/dist/payments/simplepay.d.cts +2 -2
- package/dist/payments/simplepay.d.ts +2 -2
- package/dist/payments/simplepay.js +36 -4
- package/dist/payments/stripe.cjs +19 -2
- package/dist/payments/stripe.d.cts +2 -2
- package/dist/payments/stripe.d.ts +2 -2
- package/dist/payments/stripe.js +19 -2
- package/dist/push-BXj0Sf0Z.d.ts +52 -0
- package/dist/push-D4nNbCNV.d.cts +52 -0
- package/dist/reference-B5TATqb5.js +124 -0
- package/dist/reference-BIdYMK0t.cjs +183 -0
- package/dist/reports/index.cjs +1 -1
- package/dist/reports/index.d.cts +1 -1
- package/dist/reports/index.d.ts +1 -1
- package/dist/reports/index.js +1 -1
- package/dist/{serialize-DSE_o9RK.js → serialize-B2eFh3D-.js} +5 -1
- package/dist/{serialize-BXOww1Uq.cjs → serialize-CquIsxA-.cjs} +5 -1
- package/dist/{server-Cd8HB661.js → server-CqqECkMp.js} +8 -7
- package/dist/{server-C6PoNkdD.cjs → server-DENsDDW9.cjs} +17 -16
- package/dist/session-Ckl5eJhV.d.ts +7 -0
- package/dist/{session-CKOuE6Jc.cjs → session-DeM5vjvC.cjs} +69 -13
- package/dist/{session-rMKaJcmq.js → session-SaEEXu2N.js} +58 -14
- package/dist/session-YbChChx7.d.cts +7 -0
- package/dist/storage/fs.cjs +1 -1
- package/dist/storage/fs.js +1 -1
- package/dist/storage/index.cjs +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/store-C1rHd9DB.d.cts +19 -0
- package/dist/store-C1rHd9DB.d.ts +19 -0
- package/dist/stores/index.cjs +24 -0
- package/dist/stores/index.d.cts +4 -0
- package/dist/stores/index.d.ts +4 -0
- package/dist/stores/index.js +3 -0
- package/dist/stores-BNrS0dWl.cjs +506 -0
- package/dist/stores-DhjGBrl_.js +441 -0
- package/dist/testing/index.cjs +28 -16
- package/dist/testing/index.d.cts +6 -3
- package/dist/testing/index.d.ts +6 -3
- package/dist/testing/index.js +26 -14
- package/dist/{types-BVeR7KyU.d.ts → types-B1A8mUIE.d.cts} +13 -1
- package/dist/{types-BVeR7KyU.d.cts → types-ByAEvGsZ.d.ts} +13 -1
- package/dist/{types-k--zHf4l.d.ts → types-D1zDOH_F.d.ts} +1 -1
- package/dist/{types-DH8QoNZK.d.cts → types-lnKkQdot.d.cts} +1 -1
- package/dist/warnings-B3DXnveC.d.cts +31 -0
- package/dist/warnings-B3DXnveC.d.ts +31 -0
- package/dist/warnings-DeIw5RFj.cjs +20 -0
- package/dist/warnings-DwTl5J-2.js +15 -0
- package/dist/{webhook-CrEGohbg.js → webhook-CQVShAfI.js} +44 -1
- package/dist/{webhook-81giRMdQ.cjs → webhook-Ckj-_hPD.cjs} +67 -0
- package/dist/webhook-CmdhGiH5.d.cts +11 -0
- package/dist/webhook-D6lEejob.d.ts +11 -0
- package/llms.txt +4 -3
- package/package.json +92 -4
- package/dist/session-Dm_45x8K.d.cts +0 -11
- package/dist/session-Dm_45x8K.d.ts +0 -11
- package/dist/webhook-CpCMHhn2.d.ts +0 -6
- package/dist/webhook-CpMJuP6c.d.cts +0 -6
package/README.en.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# kassza (English overview)
|
|
2
|
+
|
|
3
|
+
kassza is an unofficial, zero-dependency TypeScript client for the [Számlázz.hu](https://www.szamlazz.hu) Számla Agent API, the most widely used Hungarian invoicing service. The full documentation is in Hungarian at [kasszajs.hu](https://kasszajs.hu), because the domain (Hungarian VAT, NAV reporting, receipt rules) is Hungarian. This page is a short entry point for developers who do not read Hungarian.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install kassza
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { createKassza } from 'kassza'
|
|
11
|
+
|
|
12
|
+
const kassza = createKassza() // reads SZAMLAZZ_AGENT_KEY
|
|
13
|
+
|
|
14
|
+
const { number, created } = await kassza.invoices.createOnce({
|
|
15
|
+
orderNumber: 'WEB-1042',
|
|
16
|
+
paid: true,
|
|
17
|
+
buyer: { name: 'Buyer Ltd.', zip: '1111', city: 'Budapest', address: 'Fő utca 1.' },
|
|
18
|
+
items: [{ name: 'Subscription', grossUnitPrice: 12_700, vat: 27 }],
|
|
19
|
+
})
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## What it does
|
|
23
|
+
|
|
24
|
+
- Invoices, proformas, advance, final and corrective invoices, delivery notes, reversals, payments, PDFs, invoice data, taxpayer lookup.
|
|
25
|
+
- Receipts (nyugta): create, reverse, query, email, and convert to an invoice later.
|
|
26
|
+
- Exactly-once issuing: `createOnce` looks the document up before creating it and after uncertain failures; concurrent calls are merged, and a shared lock (`createOnceLock`) prevents duplicates across serverless instances.
|
|
27
|
+
- Payment providers: Stripe, SimplePay, Barion, Revolut and PayPal webhooks that issue a receipt or invoice exactly once, reverse it on a full refund, and issue corrective invoices on partial refunds.
|
|
28
|
+
- NAV (Hungarian tax authority) daily receipt reports, reconciliation, and a document journal to build them from.
|
|
29
|
+
- Bulk and recurring invoicing with rate limiting, a fake Számla Agent for tests, Express/NestJS adapter, observability (logs, tracing, Prometheus metrics), a CLI (`npx kassza doctor`) and an MCP server.
|
|
30
|
+
- Runs on Node.js, Bun, Deno, Cloudflare Workers and edge runtimes; CI tests all four on the built package.
|
|
31
|
+
- Sends no telemetry.
|
|
32
|
+
|
|
33
|
+
## Rules that matter
|
|
34
|
+
|
|
35
|
+
1. Never retry creating an invoice in a loop: Számlázz.hu bans accounts that do. kassza retries only safe lookups.
|
|
36
|
+
2. Always set an `orderNumber`, and prefer `createOnce`.
|
|
37
|
+
3. Give prices as `netUnitPrice` or `grossUnitPrice` with a VAT rate; kassza applies the official rounding rules.
|
|
38
|
+
4. Errors are `SzamlazzError` with a `category` (`validation`, `duplicate`, `network`, …) and a `docsUrl` to a page about the error code.
|
|
39
|
+
|
|
40
|
+
## For AI coding agents
|
|
41
|
+
|
|
42
|
+
English docs for agents ship inside the package: [agents/README.md](agents/README.md), [pitfalls](agents/pitfalls.md), [API reference](agents/api.md), [recipes](agents/recipes.md), and [llms.txt](llms.txt).
|
|
43
|
+
|
|
44
|
+
## Status
|
|
45
|
+
|
|
46
|
+
kassza is in beta (0.x). The API may still change between minor versions; see the [changelog](CHANGELOG.md) (in Hungarian). It is not affiliated with Számlázz.hu.
|
|
47
|
+
|
|
48
|
+
License: MIT.
|
package/README.md
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<b>Számlázz.hu, TypeScriptben, egyszerűbben.</b><br>
|
|
9
|
-
Nem hivatalos TypeScript wrapper a Számlázz.hu Számla Agenthez. Mind a 11 Agent művelet, 0 függőség, nulla runtime kompromisszum
|
|
9
|
+
Nem hivatalos TypeScript wrapper a Számlázz.hu Számla Agenthez. Mind a 11 Agent művelet, 0 függőség, nulla runtime kompromisszum.<br>
|
|
10
|
+
<sub><a href="https://github.com/futozs/kassza/blob/main/README.en.md">English overview</a></sub>
|
|
10
11
|
</p>
|
|
11
12
|
|
|
12
13
|
<p align="center">
|
|
@@ -14,14 +15,16 @@
|
|
|
14
15
|
<a href="https://www.npmjs.com/package/kassza"><img src="https://img.shields.io/npm/dm/kassza?label=let%C3%B6lt%C3%A9s&style=flat-square&labelColor=28313d&color=c2501a" alt="havi letöltés"></a>
|
|
15
16
|
<a href="https://github.com/futozs/kassza/blob/main/package.json"><img src="https://img.shields.io/badge/f%C3%BCgg%C5%91s%C3%A9g-0-c2501a?style=flat-square&labelColor=28313d" alt="0 futásidejű függőség"></a>
|
|
16
17
|
<a href="https://github.com/futozs/kassza/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/kassza?label=licenc&style=flat-square&labelColor=28313d&color=c2501a" alt="MIT licenc"></a>
|
|
17
|
-
</p>
|
|
18
|
-
|
|
19
|
-
<p align="center">
|
|
20
|
-
<a href="https://kasszajs.hu"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/nav-web-dark.svg"><img src="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/nav-web-light.svg" alt="Weboldal: kasszajs.hu" width="428"></picture></a>
|
|
21
|
-
<a href="https://kasszajs.hu/docs"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/nav-docs-dark.svg"><img src="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/nav-docs-light.svg" alt="Dokumentáció: 113 oldal, magyarul" width="428"></picture></a>
|
|
22
18
|
<br>
|
|
23
|
-
<a href="https://
|
|
24
|
-
<a href="https://
|
|
19
|
+
<a href="https://github.com/futozs/kassza/actions/workflows/ci.yml?query=branch%3Amain"><img src="https://img.shields.io/github/actions/workflow/status/futozs/kassza/ci.yml?branch=main&label=CI&style=flat-square&labelColor=28313d" alt="CI állapota"></a>
|
|
20
|
+
<a href="https://github.com/futozs/kassza/actions/workflows/full-check.yml?query=branch%3Amain"><img src="https://img.shields.io/github/actions/workflow/status/futozs/kassza/full-check.yml?branch=main&label=heti%20teljes%20teszt&style=flat-square&labelColor=28313d" alt="Heti teljes ellenőrzés: CI, XSD, változásfigyelő, élő e2e"></a>
|
|
21
|
+
<a href="https://github.com/futozs/kassza/actions/workflows/release.yml?query=branch%3Amain"><img src="https://img.shields.io/github/actions/workflow/status/futozs/kassza/release.yml?branch=main&label=kiad%C3%A1s&style=flat-square&labelColor=28313d" alt="Kiadás állapota"></a>
|
|
22
|
+
<a href="https://scorecard.dev/viewer/?uri=github.com/futozs/kassza"><img src="https://img.shields.io/ossf-scorecard/github.com/futozs/kassza?label=OpenSSF%20Scorecard&style=flat-square&labelColor=28313d" alt="OpenSSF Scorecard pontszám"></a>
|
|
23
|
+
<br>
|
|
24
|
+
<a href="https://github.com/futozs/kassza/actions/workflows/badges.yml"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Ffutozs%2Fkassza%2Fbadges%2Fcoverage-lines.json&style=flat-square&labelColor=28313d" alt="Sor-lefedettség"></a>
|
|
25
|
+
<a href="https://github.com/futozs/kassza/actions/workflows/badges.yml"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Ffutozs%2Fkassza%2Fbadges%2Fcoverage-branches.json&style=flat-square&labelColor=28313d" alt="Ág-lefedettség"></a>
|
|
26
|
+
<a href="https://github.com/futozs/kassza/actions/workflows/badges.yml"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Ffutozs%2Fkassza%2Fbadges%2Fcoverage-functions.json&style=flat-square&labelColor=28313d" alt="Függvény-lefedettség"></a>
|
|
27
|
+
<a href="https://github.com/futozs/kassza/actions/workflows/badges.yml"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Ffutozs%2Fkassza%2Fbadges%2Fcoverage-statements.json&style=flat-square&labelColor=28313d" alt="Utasítás-lefedettség"></a>
|
|
25
28
|
</p>
|
|
26
29
|
|
|
27
30
|
```bash
|
|
@@ -96,7 +99,8 @@ Ennyi. A kerekítést, a magyar dátumot, az XML-t, a session cookie-t és a hib
|
|
|
96
99
|
| ⚙️ [Beállítás](#beállítás) | 🧾 [Nyugták](#nyugták) | 📊 [NAV nyugta-adatszolgáltatás](#nav-nyugta-adatszolgáltatás) | ⚡ [Serverless és edge](#serverless-és-edge) |
|
|
97
100
|
| 🚨 [Hibakezelés](#hibakezelés) | 🏛️ [Adószám lekérdezés](#adószám-lekérdezés) | 🤝 [Megbízotti számlázás](#megbízotti-számlázás) | 🧪 [Tesztelés](#tesztelés) |
|
|
98
101
|
| 🎛️ [Haladó beállítások](#haladó-beállítások) | 🔔 [Fizetési értesítés (IPN)](#fizetési-értesítés-ipn) | 🔗 [Pénzügyi adatkapcsolat](#pénzügyi-adatkapcsolat) | 🧮 [Validátorok és pénzszámítás](#validátorok-és-pénzszámítás) |
|
|
99
|
-
| 🤖 [AI-val kódolsz?](#ai-val-kódolsz) | | | 💻 [Parancssor és MCP szerver](#parancssor-és-mcp-szerver) |
|
|
102
|
+
| 🤖 [AI-val kódolsz?](#ai-val-kódolsz) | 🔁 [Tömeges számlázás](#tömeges-és-ismétlődő-számlázás) | 🟩 [Node.js és Express](#nodejs-és-express) | 💻 [Parancssor és MCP szerver](#parancssor-és-mcp-szerver) |
|
|
103
|
+
| | | 📒 [Bizonylatnapló](#bizonylatnapló) | 📈 [Megfigyelhetőség](#megfigyelhetőség) |
|
|
100
104
|
|
|
101
105
|
## Weboldal, sandbox és receptek
|
|
102
106
|
|
|
@@ -106,7 +110,7 @@ A teljes magyar dokumentáció, a sandbox és a receptek a **[kasszajs.hu](https
|
|
|
106
110
|
<a href="https://kasszajs.hu/sandbox?pelda=szamla"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/showcase-dark.svg"><img src="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/showcase-light.svg" alt="A kassza sandbox: futtatható példák, TypeScript kód és a ténylegesen elküldött XML" width="100%"></picture></a>
|
|
107
111
|
</p>
|
|
108
112
|
|
|
109
|
-
- 📖 **[Dokumentáció](https://kasszajs.hu/docs)**:
|
|
113
|
+
- 📖 **[Dokumentáció](https://kasszajs.hu/docs)**: 188 oldal magyarul. Minden Agent művelethez kérés, válasz és futtatható minta, a beállítások, a szabályok és az összes ismert hibakód.
|
|
110
114
|
- ▶️ **[Sandbox](https://kasszajs.hu/sandbox)**: 28 példa, amit a böngészőben futtathatsz Agent kulcs nélkül, szimulált Számlázz.hu ellen, a ténylegesen elküldött XML-lel. A saját kódodat linkként meg is oszthatod.
|
|
111
115
|
- 🍳 **[Receptek](https://kasszajs.hu/docs/receptek)**: 11 teljes, bemásolható integráció webshophoz, Stripe és IPN webhookhoz, díjbekérőhöz, pénztári nyugtához, PDF tárhelyhez, Cloudflare Workershez és tesztekhez.
|
|
112
116
|
- 🤖 **[llms.txt](https://kasszajs.hu/llms.txt)**: a dokumentáció tartalomjegyzéke AI asszisztenseknek, a teljes szöveg egy fájlban: [llms-full.txt](https://kasszajs.hu/llms-full.txt).
|
|
@@ -421,6 +425,8 @@ await kassza.invoices.clearPayments('E-WEB-2026-12')
|
|
|
421
425
|
|
|
422
426
|
A `registerPayment` egyetlen befizetést és több részletet is fogad. A `clearPayments` az összes befizetést törli a számláról.
|
|
423
427
|
|
|
428
|
+
Ha ugyanaz a befizetés több helyről is érkezhet (banki értesítés, webhook), a `registerPaymentOnce({ invoiceNumber, key, amount })` egy stabil kulccsal pontosan egyszer rögzíti: a kulcsot jelölőként a befizetés leírásába teszi, és rögzítés előtt megkeresi.
|
|
429
|
+
|
|
424
430
|
📖 **Dokumentáció:** [Befizetés rögzítése](https://kasszajs.hu/docs/befizetes-rogzitese) · ▶️ **Sandbox:** [Befizetések rögzítése](https://kasszajs.hu/sandbox?pelda=befizetes)
|
|
425
431
|
|
|
426
432
|
</details>
|
|
@@ -579,7 +585,7 @@ if (ceg.valid) {
|
|
|
579
585
|
}
|
|
580
586
|
```
|
|
581
587
|
|
|
582
|
-
A cégadatok a NAV-tól jönnek, a cím formázva, például `1031 Budapest, Záhony utca 7.`
|
|
588
|
+
A cégadatok a NAV-tól jönnek, a cím formázva, például `1031 Budapest, Záhony utca 7.` Űrlapokhoz a `taxpayerCache: { store }` beállítás közös tárolóban megjegyzi az eredményt, így ugyanaz az adószám csak egyszer megy ki.
|
|
583
589
|
|
|
584
590
|
📖 **Dokumentáció:** [Adószám lekérdezés](https://kasszajs.hu/docs/adoszam-lekerdezes) · ▶️ **Sandbox:** [Adószám lekérdezése](https://kasszajs.hu/sandbox?pelda=adoszam)
|
|
585
591
|
|
|
@@ -632,6 +638,10 @@ try {
|
|
|
632
638
|
| `network` / `timeout` / `maintenance` | Átmeneti hiba |
|
|
633
639
|
| `rate_limit` | A tesztfiókban túl sok bizonylat készült rövid idő alatt (167) |
|
|
634
640
|
| `attempt_limit` | Ezt a kérést már ötször sikertelenül küldték el, ezért a kassza el sem küldi |
|
|
641
|
+
| `in_progress` | Egy másik folyamat éppen ugyanezt a bizonylatot állítja ki (a `createOnce` zárja) |
|
|
642
|
+
| `store_unavailable` | Egy kötelezőnek beállított tároló (zár, napló) nem érhető el, a kérés el sem ment |
|
|
643
|
+
|
|
644
|
+
Minden ismert hibakódnak saját oldala van; a hiba `docsUrl` mezője oda mutat, így a naplóból egy kattintás.
|
|
635
645
|
|
|
636
646
|
📖 **Dokumentáció:** [Hibakezelés, hibakódok](https://kasszajs.hu/docs/alapok/hibakezeles) · ▶️ **Sandbox:** [Validációs hibák](https://kasszajs.hu/sandbox?pelda=hibakezeles-validacio)
|
|
637
647
|
|
|
@@ -649,7 +659,16 @@ const { number, created } = await kassza.invoices.createOnce({
|
|
|
649
659
|
})
|
|
650
660
|
```
|
|
651
661
|
|
|
652
|
-
Kiállítás előtt megkeresi a számlát, hálózati hiba, időtúllépés vagy 56-os hiba után pedig visszakeresi. Ha a webhook kétszer fut le, a második hívás `created: false` eredménnyel a meglévő számlát adja.
|
|
662
|
+
Kiállítás előtt megkeresi a számlát, hálózati hiba, időtúllépés vagy 56-os hiba után pedig visszakeresi. Ha a webhook kétszer fut le, a második hívás `created: false` eredménnyel a meglévő számlát adja. Az egyszerre érkező, azonos rendelésre szóló hívásokat a kassza összevonja; több szerver vagy serverless példány között a `createOnceLock` közös tároló zárja véd a dupla számla ellen:
|
|
663
|
+
|
|
664
|
+
```ts
|
|
665
|
+
import { upstashRedisStore } from 'kassza/stores'
|
|
666
|
+
|
|
667
|
+
const store = upstashRedisStore(Redis.fromEnv())
|
|
668
|
+
const kassza = createKassza({ cookieStore: store, attemptLedger: store, createOnceLock: store })
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Az `attemptLedger` a folyamatok között is betartja az öt próbálkozásos korlátot, atomikus számlálóval.
|
|
653
672
|
|
|
654
673
|
📖 **Dokumentáció:** [Pontosan egyszer](https://kasszajs.hu/docs/alapok/pontosan-egyszer) · ▶️ **Sandbox:** [Pénztári nyugta, dupla gombnyomás](https://kasszajs.hu/sandbox?pelda=penztari-nyugta)
|
|
655
674
|
|
|
@@ -726,8 +745,9 @@ export const POST = stripeWebhook({
|
|
|
726
745
|
})
|
|
727
746
|
```
|
|
728
747
|
|
|
729
|
-
- Az újraküldött webhook nem állít ki második bizonylatot.
|
|
748
|
+
- Az újraküldött webhook nem állít ki második bizonylatot; a `dedupe: store` opcióval a már feldolgozott eseményt a Számla Agent hívása nélkül nyugtázza.
|
|
730
749
|
- Teljes visszatérítéskor a kassza sztornózza a bizonylatot.
|
|
750
|
+
- Részleges visszatérítéskor számlánál visszatérítésenként egy helyesbítő számlát állít ki, a visszatérített összeget tételenként pontosan szétosztva; több áfakulcsnál és nyugtánál javaslatot ad.
|
|
731
751
|
- Ugyanígy működik a `simplePayWebhook`, a `barionWebhook`, a `revolutWebhook` és a `payPalWebhook`.
|
|
732
752
|
|
|
733
753
|
📖 **Dokumentáció:** [Fizetésből bizonylat](https://kasszajs.hu/docs/fizetesek)
|
|
@@ -773,6 +793,36 @@ A NAV kliens alapból csak olvas: a Számlázz.hu által jelentett nyugtákat ne
|
|
|
773
793
|
<a href="https://kasszajs.hu/docs/nav-nyugta"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-docs-dark.svg"><img src="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-docs-light.svg" alt="Dokumentáció: NAV nyugta-adatszolgáltatás" height="44"></picture></a>
|
|
774
794
|
</p>
|
|
775
795
|
|
|
796
|
+
## Bizonylatnapló
|
|
797
|
+
|
|
798
|
+
A NAV napi összesítő és a napi zárás a saját nyilvántartásodból számol, mert a Számla Agent nem listáz nyugtákat dátum szerint. A `kassza/journal` ezt a nyilvántartást adja.
|
|
799
|
+
|
|
800
|
+
<details>
|
|
801
|
+
<summary><b>Napló a NAV összesítőhöz</b> · <code>createJournal()</code>, <code>kvJournal()</code></summary>
|
|
802
|
+
|
|
803
|
+
```ts
|
|
804
|
+
import { createJournal, kvJournal } from 'kassza/journal'
|
|
805
|
+
import { navDailyReports } from 'kassza/reports'
|
|
806
|
+
|
|
807
|
+
const journal = createJournal(kvJournal(store))
|
|
808
|
+
const kassza = createKassza({
|
|
809
|
+
hooks: { onDocument: (event) => journal.record(event), onDocumentError: 'throw' },
|
|
810
|
+
})
|
|
811
|
+
|
|
812
|
+
const jelentesek = navDailyReports(await journal.receipts({ from: '2026-10-01', to: '2026-10-31' }))
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
- A `trackReceipt()` és a `trackInvoice()` a kiállítás előtt befejezetlen tételt rögzít; ha a folyamat közben leáll, a `settle()` később visszakeresi és lezárja.
|
|
816
|
+
- A `reconcile()` az adatkapcsolat napi nyugtaarchívumával egyeztet, és pótolja a hiányzó tételeket.
|
|
817
|
+
|
|
818
|
+
📖 **Dokumentáció:** [Bizonylatnapló](https://kasszajs.hu/docs/kiegeszitok/bizonylatnaplo)
|
|
819
|
+
|
|
820
|
+
</details>
|
|
821
|
+
|
|
822
|
+
<p>
|
|
823
|
+
<a href="https://kasszajs.hu/docs/nav-nyugta/hatarido"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-docs-dark.svg"><img src="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-docs-light.svg" alt="Dokumentáció: Mi a teendő december 31. előtt?" height="44"></picture></a>
|
|
824
|
+
</p>
|
|
825
|
+
|
|
776
826
|
## Megbízotti számlázás
|
|
777
827
|
|
|
778
828
|
Platformoknak, amelyek sok cég nevében állítanak ki bizonylatot, a cégek saját Számlázz.hu fiókjában.
|
|
@@ -896,13 +946,13 @@ További adapterek: `s3Storage` (AWS SDK), `r2BindingStorage`, `vercelBlobStorag
|
|
|
896
946
|
A session cookie újrahasznosítása gyorsítja a hívásokat. Serverless környezetben tedd közös tárolóba.
|
|
897
947
|
|
|
898
948
|
<details>
|
|
899
|
-
<summary><b>Upstash Redis</b> · <code>
|
|
949
|
+
<summary><b>Upstash Redis</b> · <code>upstashRedisStore()</code></summary>
|
|
900
950
|
|
|
901
951
|
```ts
|
|
902
952
|
import { Redis } from '@upstash/redis'
|
|
903
|
-
import {
|
|
953
|
+
import { upstashRedisStore } from 'kassza/stores'
|
|
904
954
|
|
|
905
|
-
const kassza = createKassza({ cookieStore:
|
|
955
|
+
const kassza = createKassza({ cookieStore: upstashRedisStore(Redis.fromEnv()) })
|
|
906
956
|
```
|
|
907
957
|
|
|
908
958
|
📖 **Dokumentáció:** [Munkamenet (session cookie)](https://kasszajs.hu/docs/alapok/munkamenet) · ▶️ **Sandbox:** [Közös session több kliens között](https://kasszajs.hu/sandbox?pelda=munkamenet)
|
|
@@ -910,19 +960,23 @@ const kassza = createKassza({ cookieStore: upstashRedisCookieStore(Redis.fromEnv
|
|
|
910
960
|
</details>
|
|
911
961
|
|
|
912
962
|
<details>
|
|
913
|
-
<summary><b>Cloudflare Workers</b> · <code>
|
|
963
|
+
<summary><b>Cloudflare Workers</b> · <code>cloudflareKvStore()</code>, <code>durableObjectStore()</code></summary>
|
|
914
964
|
|
|
915
965
|
```ts
|
|
916
|
-
import {
|
|
966
|
+
import { cloudflareKvStore } from 'kassza/stores'
|
|
917
967
|
|
|
918
|
-
const kassza = createKassza({ agentKey: env.SZAMLAZZ_AGENT_KEY, cookieStore:
|
|
968
|
+
const kassza = createKassza({ agentKey: env.SZAMLAZZ_AGENT_KEY, cookieStore: cloudflareKvStore(env.KASSZA_KV) })
|
|
919
969
|
```
|
|
920
970
|
|
|
971
|
+
A KV munkamenetnek jó, de nincs benne atomikus írás: a `createOnce` zárjához és a naplóhoz Workers alatt a `durableObjectStore()` kell.
|
|
972
|
+
|
|
921
973
|
📖 **Dokumentáció:** [Serverless és edge](https://kasszajs.hu/docs/kiegeszitok/serverless-es-edge)
|
|
922
974
|
|
|
923
975
|
</details>
|
|
924
976
|
|
|
925
|
-
Van még `
|
|
977
|
+
Van még `ioredisStore`, `nodeRedisStore` és `customStore` is (a régi `kassza/cookie-stores` nevek is működnek). A `diagnoseStore(store)` megmondja, mire alkalmas egy tároló. Ha a tároló elérhetetlen, a számlázás attól még működik.
|
|
978
|
+
|
|
979
|
+
A csomag minden futtatókörnyezetben ugyanazt adja: a CI a buildelt csomagot Node.js, Bun, Deno és Cloudflare workerd alatt is lefuttatja.
|
|
926
980
|
|
|
927
981
|
<p>
|
|
928
982
|
<a href="https://kasszajs.hu/docs/kiegeszitok/serverless-es-edge"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-docs-dark.svg"><img src="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-docs-light.svg" alt="Dokumentáció: Serverless és edge" height="44"></picture></a>
|
|
@@ -1090,7 +1144,8 @@ const kassza = createKassza({
|
|
|
1090
1144
|
})
|
|
1091
1145
|
```
|
|
1092
1146
|
|
|
1093
|
-
- Az `onDocument` minden kiállított és sztornózott bizonylat, valamint rögzített befizetés után lefut. Ha hibát dob, a bizonylat attól még elkészült.
|
|
1147
|
+
- Az `onDocument` minden kiállított és sztornózott bizonylat, valamint rögzített befizetés után lefut. Ha hibát dob, a bizonylat attól még elkészült; az `onDocumentError: 'throw'` beállítással ilyenkor `DocumentHookError` jön, benne a bizonylattal.
|
|
1148
|
+
- Az `onWarning` megkapja a korábban csendben elnyelt hibákat (tároló, hook, zár).
|
|
1094
1149
|
- A `maintenanceCooldownMs` karbantartási hiba után ennyi ideig nem küld kérést, hanem azonnal `maintenance` hibát ad, így átválthatsz tartalék folyamatra.
|
|
1095
1150
|
|
|
1096
1151
|
📖 **Dokumentáció:** [Pontosan egyszer](https://kasszajs.hu/docs/alapok/pontosan-egyszer)
|
|
@@ -1102,6 +1157,73 @@ const kassza = createKassza({
|
|
|
1102
1157
|
<a href="https://kasszajs.hu/sandbox?pelda=hookok"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-sandbox-dark.svg"><img src="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-sandbox-light.svg" alt="Futtasd a sandboxban: Hookok és újrapróbálás" height="44"></picture></a>
|
|
1103
1158
|
</p>
|
|
1104
1159
|
|
|
1160
|
+
## Megfigyelhetőség
|
|
1161
|
+
|
|
1162
|
+
A kassza nem küld haza semmit. A saját rendszeredben a `kassza/observe` ad strukturált naplót, OpenTelemetry-kompatibilis tracinget és Prometheus metrikákat, függőség nélkül és titokmentesen.
|
|
1163
|
+
|
|
1164
|
+
<details>
|
|
1165
|
+
<summary><b>Napló, tracing, metrikák</b> · <code>observe()</code>, <code>createMetricsRegistry()</code></summary>
|
|
1166
|
+
|
|
1167
|
+
```ts
|
|
1168
|
+
import { combineHooks, createMetricsRegistry, observe } from 'kassza/observe'
|
|
1169
|
+
|
|
1170
|
+
const metrics = createMetricsRegistry()
|
|
1171
|
+
const kassza = createKassza({ hooks: combineHooks(observe({ logger: console, metrics }), sajatHookok) })
|
|
1172
|
+
|
|
1173
|
+
metrics.renderPrometheus()
|
|
1174
|
+
```
|
|
1175
|
+
|
|
1176
|
+
📖 **Dokumentáció:** [Megfigyelhetőség](https://kasszajs.hu/docs/kiegeszitok/megfigyelhetoseg)
|
|
1177
|
+
|
|
1178
|
+
</details>
|
|
1179
|
+
|
|
1180
|
+
## Tömeges és ismétlődő számlázás
|
|
1181
|
+
|
|
1182
|
+
Havidíj, tagdíj, bérleti díj: a `kassza/batch` idempotens kulcsokkal, sebességkorláttal és próbafuttatással állítja ki a bizonylatokat, és a Számlázz.hu korlátjánál megáll.
|
|
1183
|
+
|
|
1184
|
+
<details>
|
|
1185
|
+
<summary><b>Havi számlázás</b> · <code>runBatch()</code>, <code>billingPeriodAt()</code></summary>
|
|
1186
|
+
|
|
1187
|
+
```ts
|
|
1188
|
+
import { billingPeriodAt, runBatch } from 'kassza/batch'
|
|
1189
|
+
|
|
1190
|
+
const idoszak = billingPeriodAt({ interval: 'month', anchor: '2026-01-31' }, new Date())
|
|
1191
|
+
const eredmeny = await runBatch(kassza, {
|
|
1192
|
+
items: elofizetesek.map((elofizetes) => ({
|
|
1193
|
+
key: `SUB-${elofizetes.id}-${idoszak.start}`,
|
|
1194
|
+
document: () => ({ kind: 'invoice', input: szamlaElofizetesbol(elofizetes, idoszak) }),
|
|
1195
|
+
})),
|
|
1196
|
+
dryRun: false,
|
|
1197
|
+
})
|
|
1198
|
+
```
|
|
1199
|
+
|
|
1200
|
+
Egy megszakadt futás újraindítva nem állít ki duplát. A hónap végi kezdőnapot csúszás nélkül kezeli.
|
|
1201
|
+
|
|
1202
|
+
📖 **Dokumentáció:** [Tömeges és ismétlődő számlázás](https://kasszajs.hu/docs/kiegeszitok/tomeges-szamlazas)
|
|
1203
|
+
|
|
1204
|
+
</details>
|
|
1205
|
+
|
|
1206
|
+
## Node.js és Express
|
|
1207
|
+
|
|
1208
|
+
A webhook-kezelők Web-szabványos `(Request) => Response` függvények. Express, NestJS és Fastify alá a `kassza/node` köti be őket, a nyers törzs (aláírás!) megőrzésével.
|
|
1209
|
+
|
|
1210
|
+
<details>
|
|
1211
|
+
<summary><b>Express</b> · <code>toNodeHandler()</code></summary>
|
|
1212
|
+
|
|
1213
|
+
```ts
|
|
1214
|
+
import { toNodeHandler } from 'kassza/node'
|
|
1215
|
+
import { stripeWebhook } from 'kassza/payments/stripe'
|
|
1216
|
+
|
|
1217
|
+
app.post('/webhooks/stripe', toNodeHandler(stripeWebhook({ secret, onPayment })))
|
|
1218
|
+
app.use(express.json())
|
|
1219
|
+
```
|
|
1220
|
+
|
|
1221
|
+
A webhook útvonal az `express.json()` elé kerüljön; ha egy middleware már feldolgozta a törzset, a kassza érthető hibát ad.
|
|
1222
|
+
|
|
1223
|
+
📖 **Dokumentáció:** [Node.js, Express, NestJS](https://kasszajs.hu/docs/kiegeszitok/node-express)
|
|
1224
|
+
|
|
1225
|
+
</details>
|
|
1226
|
+
|
|
1105
1227
|
## Parancssor és MCP szerver
|
|
1106
1228
|
|
|
1107
1229
|
<details>
|
|
@@ -1113,7 +1235,7 @@ npx kassza xml preview szamla.json
|
|
|
1113
1235
|
npx kassza invoice get --order REND-1001
|
|
1114
1236
|
```
|
|
1115
1237
|
|
|
1116
|
-
A `doctor` ellenőrzi a Node.js-t, az Agent kulcsot, a gép óráját és a munkamenetet. Az `xml preview` kiírja a küldendő XML-t az Agent kulcs nélkül, így supportjegyhez is csatolható.
|
|
1238
|
+
A `doctor` ellenőrzi a Node.js-t, az Agent kulcsot, a gép óráját és a munkamenetet; a `--capabilities` az e-számla engedélyt, a `--report` titokmentes Markdown jelentést ad hibajegyhez. Az `xml preview` kiírja a küldendő XML-t az Agent kulcs nélkül, így supportjegyhez is csatolható.
|
|
1117
1239
|
|
|
1118
1240
|
📖 **Dokumentáció:** [Parancssor](https://kasszajs.hu/docs/kiegeszitok/parancssor)
|
|
1119
1241
|
|
|
@@ -1158,6 +1280,14 @@ A weboldal is AI-barát: az [llms.txt](https://kasszajs.hu/llms.txt) a dokument
|
|
|
1158
1280
|
<a href="https://kasszajs.hu/docs/kiegeszitok/ai-asszisztensek"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-docs-dark.svg"><img src="https://raw.githubusercontent.com/futozs/kassza/main/readme/assets/button-docs-light.svg" alt="Dokumentáció: AI asszisztensek" height="44"></picture></a>
|
|
1159
1281
|
</p>
|
|
1160
1282
|
|
|
1283
|
+
## Ki használja?
|
|
1284
|
+
|
|
1285
|
+
A kassza nem küld semmilyen használati adatot, ezért csak az derül ki, ki használja, aki maga jelzi. Ha éles vagy kísérleti projektben használod, [írd meg egy issue-ban](https://github.com/futozs/kassza/issues/new?template=used-by.yml), és felkerülsz ide.
|
|
1286
|
+
|
|
1287
|
+
| Projekt | Mire használja |
|
|
1288
|
+
| --- | --- |
|
|
1289
|
+
| _Légy te az első._ | |
|
|
1290
|
+
|
|
1161
1291
|
---
|
|
1162
1292
|
|
|
1163
1293
|
<p align="center">
|
package/agents/README.md
CHANGED
|
@@ -14,6 +14,11 @@ It also links delegated (principal) accounts through the Agent (`connectPrincipa
|
|
|
14
14
|
- `kassza/data-link`: a receiver for the Számlázz.hu financial data link (pushed invoices, bank transactions and receipts).
|
|
15
15
|
- `kassza/testing`: a mock client and a fake Számla Agent `fetch` for integration tests.
|
|
16
16
|
- `kassza/mcp` and the `kassza` CLI (`npx kassza doctor`, `npx kassza mcp`).
|
|
17
|
+
- `kassza/stores`: shared stores (Redis, Upstash, Cloudflare KV, Durable Object) for the session, the attempt ledger, the `createOnce` lock and webhook deduplication.
|
|
18
|
+
- `kassza/journal`: a document journal for the NAV daily summary, with pending entries and reconciliation.
|
|
19
|
+
- `kassza/batch`: rate-limited, restartable bulk and recurring invoicing, plus billing periods.
|
|
20
|
+
- `kassza/node`: Express, NestJS and `node:http` adapter for the webhook handlers.
|
|
21
|
+
- `kassza/observe`: structured logs, tracing and Prometheus metrics, with no telemetry.
|
|
17
22
|
|
|
18
23
|
It runs on Node 22+, Bun, Deno, Cloudflare Workers and Vercel Edge.
|
|
19
24
|
|
|
@@ -23,7 +28,7 @@ It runs on Node 22+, Bun, Deno, Cloudflare Workers and Vercel Edge.
|
|
|
23
28
|
2. [api.md](./api.md): every method, input and output.
|
|
24
29
|
3. [recipes.md](./recipes.md): webhooks, exactly-once invoicing, receipts, IPN, PDF storage, serverless, tests, payment providers, NAV reports, delegated invoicing, data link.
|
|
25
30
|
|
|
26
|
-
A ready-made Claude Code skill is in [skills/kassza/SKILL.md](./skills/kassza/SKILL.md). Copy the `skills/kassza` folder into `.claude/skills/` in the user's project.
|
|
31
|
+
A ready-made Claude Code skill is in [skills/kassza/SKILL.md](./skills/kassza/SKILL.md). To move a codebase off `szamlazz.js`, use [skills/migrate-from-szamlazz-js/SKILL.md](./skills/migrate-from-szamlazz-js/SKILL.md). Copy the `skills/kassza` folder into `.claude/skills/` in the user's project.
|
|
27
32
|
|
|
28
33
|
## The five things to get right
|
|
29
34
|
|
package/agents/api.md
CHANGED
|
@@ -11,15 +11,18 @@ const kassza = createKassza({
|
|
|
11
11
|
agentKey?: string,
|
|
12
12
|
username?: string, password?: string,
|
|
13
13
|
defaults?: { invoice?: InvoiceDefaults, receipt?: ReceiptDefaults },
|
|
14
|
-
cookieStore?:
|
|
15
|
-
attemptLedger?:
|
|
14
|
+
cookieStore?: KeyValueStore | false,
|
|
15
|
+
attemptLedger?: KeyValueStore,
|
|
16
|
+
attemptLedgerMode?: 'fail-open' | 'fail-closed',
|
|
17
|
+
createOnceLock?: KeyValueStore,
|
|
18
|
+
taxpayerCache?: { store: KeyValueStore, ttlSeconds?, invalidTtlSeconds? },
|
|
16
19
|
timeoutMs?: number,
|
|
17
20
|
maxAttempts?: number,
|
|
18
21
|
retryDelayMs?: number,
|
|
19
22
|
maintenanceCooldownMs?: number,
|
|
20
23
|
fetch?: typeof fetch,
|
|
21
24
|
endpoint?: string,
|
|
22
|
-
hooks?: { onRequest?, onResponse?, onError?, onDocument? },
|
|
25
|
+
hooks?: { onRequest?, onResponse?, onError?, onComplete?, onDocument?, onDocumentError?, onWarning? },
|
|
23
26
|
})
|
|
24
27
|
```
|
|
25
28
|
|
|
@@ -29,9 +32,15 @@ const kassza = createKassza({
|
|
|
29
32
|
- `timeoutMs` defaults to 60000.
|
|
30
33
|
- `maxAttempts` defaults to 3 and is capped at 5. It applies only to operations that are safe to retry.
|
|
31
34
|
- `hooks` receive events for logging. They never receive the XML payload or the key.
|
|
32
|
-
- `
|
|
35
|
+
- `KeyValueStore` (alias `CookieStore`) is `{ get, set, delete }` plus the optional atomic `setIfAbsent`, `increment`, `deleteIfEquals`. Adapters live in `kassza/stores` (see below).
|
|
36
|
+
- `attemptLedger` is a shared store. It counts failed attempts of identical requests across processes for a day, atomically when the store has `increment`. After 5 failures kassza throws an `attempt_limit` error without sending the request; after a human fixed the cause, call `kassza.resetAttempts(error)`. If the store fails, `attemptLedgerMode: 'fail-open'` (default) falls back to an in-process counter and emits `onWarning`; `'fail-closed'` throws `store_unavailable` without sending (create the adapter with `resilient: false` so read errors reach kassza).
|
|
37
|
+
- `createOnceLock` is a shared store with `setIfAbsent` (Redis, Upstash, Durable Object; not Cloudflare KV). It makes `createOnce` exactly-once across processes. Calls for the same order inside one process are always merged, without any option.
|
|
38
|
+
- `taxpayerCache` caches `taxpayer.query` results (valid ones for a day, invalid ones for 10 minutes; errors are never cached).
|
|
33
39
|
- `maintenanceCooldownMs` defaults to 0. When set, a maintenance error (code 1) blocks all requests of the client for that long, and they fail at once with category `maintenance`.
|
|
34
|
-
- `hooks.onDocument(event)` runs after every created or reversed document and every registered payment, with `{ kind: 'invoice' | 'receipt', action: 'created' | 'reversed' | 'payment', number, document }` (plus `reversedNumber` for reversals and `input` for created invoices). It is awaited, and
|
|
40
|
+
- `hooks.onDocument(event)` runs after every created or reversed document and every registered payment, with `{ kind: 'invoice' | 'receipt', action: 'created' | 'reversed' | 'payment', number, document }` (plus `reversedNumber` for reversals and `input` for created invoices). It is awaited. `hooks.onDocumentError` decides what happens when it throws: `'warn'` (default, the call still succeeds), `'throw'` (a `DocumentHookError` carrying `event`, `document` and `number` of the document that WAS created; never re-create it) or a handler `(error, event) => void`.
|
|
41
|
+
- `hooks.onWarning(warning)` receives the errors kassza swallows on purpose: `{ kind: 'session' | 'ledger' | 'hook' | 'document' | 'lock' | 'dedupe' | 'cache', message, error, action?, operation? }`.
|
|
42
|
+
- `hooks.onRequest`, `onResponse`, `onError` and `onComplete` events carry `{ action, attempt, requestId }`; `onResponse` adds `status`, `durationMs`, `responseBytes`, `sessionReused`; `onComplete` adds `outcome: 'success' | 'error'`, `durationMs`, `error?`, `willRetry` and fires once per attempt.
|
|
43
|
+
- Retries of safe operations wait `retryDelayMs * 2^(attempt-1)` with ±20% jitter, and honour `Retry-After` (no retry when it exceeds 60 s).
|
|
35
44
|
|
|
36
45
|
## Invoices: `kassza.invoices`
|
|
37
46
|
|
|
@@ -42,6 +51,7 @@ const kassza = createKassza({
|
|
|
42
51
|
| `preview(input: CreateInvoiceInput)` | `InvoicePreview` (PDF only, no document is created) | never |
|
|
43
52
|
| `reverse(input: string \| ReverseInvoiceOptions)` | `ReversedInvoice` | never |
|
|
44
53
|
| `registerPayment(input: RegisterPaymentInput)` | `RegisteredPayment` | only when `additive: false` |
|
|
54
|
+
| `registerPaymentOnce({ invoiceNumber, key, amount, method?, date?, description?, taxNumber? }, options?)` | `RegisteredPaymentOnce` (`{ invoiceNumber, key, marker, created, payment?, existing? }`) | never resends; looks the payment up by its marker |
|
|
45
55
|
| `clearPayments(input: string \| { invoiceNumber })` | `RegisteredPayment` | yes |
|
|
46
56
|
| `getPdf(ref: InvoiceReference)` | `InvoicePdf` | yes |
|
|
47
57
|
| `get(ref: InvoiceReference, { includePdf? })` | `InvoiceDetails` | yes |
|
|
@@ -52,7 +62,7 @@ const kassza = createKassza({
|
|
|
52
62
|
|
|
53
63
|
### createOnce
|
|
54
64
|
|
|
55
|
-
`invoices.createOnce(input, { lookupFirst?, matchOrderNumber?, recoveryDelayMs?, signal? })` makes invoicing exactly-once:
|
|
65
|
+
`invoices.createOnce(input, { lookupFirst?, matchOrderNumber?, recoveryDelayMs?, signal?, lock?, lockTtlSeconds?, lockWaitMs?, lockFailure? })` makes invoicing exactly-once:
|
|
56
66
|
|
|
57
67
|
1. It looks the invoice up by external ID (and, with `matchOrderNumber`, by order number) and returns it if it exists.
|
|
58
68
|
2. Otherwise it creates the invoice.
|
|
@@ -62,6 +72,8 @@ const kassza = createKassza({
|
|
|
62
72
|
- `lookupFirst` and `matchOrderNumber` default to `true`.
|
|
63
73
|
- It returns `InvoiceOnceResult`: `{ number, created, externalId, invoice?: CreatedInvoice, details?: InvoiceDetails }`. `created` is `false` when the invoice already existed.
|
|
64
74
|
- If the outcome stays unknown, it rethrows the original error with `details.outcome: 'unknown'`. Do not create the invoice by hand then; call `createOnce` again later.
|
|
75
|
+
- Concurrent calls for the same order in one process share one execution; the others get the result with `created: false`. Across processes `lock` (default: the client's `createOnceLock`, `false` disables) is held for `lockTtlSeconds` (600); a waiter polls up to `lockWaitMs` (10000) and then throws `in_progress` (respond 5xx in a webhook so it is redelivered). `lockFailure: 'throw'` (default) throws `store_unavailable` when the lock store is down; `'proceed'` continues without a lock and warns.
|
|
76
|
+
- `registerPaymentOnce` writes `[kassza:{key}]` into the payment description and looks for it on the invoice before registering. If the marker cannot be read back after registering, it throws `unexpected_response` with `details.registered: 'true'`: the payment exists, do not call again.
|
|
65
77
|
|
|
66
78
|
### CreateInvoiceInput
|
|
67
79
|
|
|
@@ -187,7 +199,7 @@ Notes on the fields:
|
|
|
187
199
|
|
|
188
200
|
## Taxpayer: `kassza.taxpayer`
|
|
189
201
|
|
|
190
|
-
`query(taxNumber: string): TaxpayerInfo` accepts `12345676`, `12345676-2-42` or `HU12345676`.
|
|
202
|
+
`query(taxNumber: string): TaxpayerInfo` accepts `12345676`, `12345676-2-42` or `HU12345676`. With `taxpayerCache` the result is cached by the 8-digit taxpayer ID.
|
|
191
203
|
|
|
192
204
|
`TaxpayerInfo` is `{ valid, name?, shortName?, taxNumber?: { taxpayerId, vatCode?, countyCode?, formatted? }, address?: TaxpayerAddress, addresses, incorporation?, infoDate? }`, and `TaxpayerAddress.formatted` looks like `'1031 Budapest, Záhony utca 7.'`.
|
|
193
205
|
|
|
@@ -261,13 +273,34 @@ createFakeAgentFetch(options?: FakeAgentOptions): FakeAgent
|
|
|
261
273
|
### `kassza/money`
|
|
262
274
|
|
|
263
275
|
- `calculateInvoiceItem(input, currency?)` and `calculateReceiptItem(input, currency?)` return `ItemAmounts`.
|
|
276
|
+
- `allocateRefund(items: { name, vat, grossAmount, unit?, identifier? }[], refundGross, { decimals?, refundedBefore? })` splits a refund exactly over items (Sainte-Laguë, BigInt), path-independent: refunds split into parts give the same per-item totals as one refund.
|
|
264
277
|
- `summarizeItems(items)` returns `{ netAmount, vatAmount, grossAmount, byVat }`.
|
|
265
278
|
- `roundMoney(value, decimals)`, `isVatRate(value)`, `NUMERIC_VAT_RATES`, `SPECIAL_VAT_CODES`.
|
|
266
279
|
|
|
267
|
-
### `kassza/storage`
|
|
280
|
+
### `kassza/storage`
|
|
268
281
|
|
|
269
282
|
- `storePdf(storage, key, pdf)` and `invoicePdfKey({ number })` save PDFs through adapters: `s3FetchStorage`, `s3Storage`, `r2BindingStorage`, `vercelBlobStorage`, `uploadthingStorage`, `supabaseStorage`, `memoryStorage`, and `fsStorage` from `kassza/storage/fs`.
|
|
270
|
-
|
|
283
|
+
|
|
284
|
+
### `kassza/stores` (also `kassza/cookie-stores`)
|
|
285
|
+
|
|
286
|
+
- `memoryStore()`, `upstashRedisStore(redis)`, `ioredisStore(redis)`, `nodeRedisStore(client)`, `cloudflareKvStore(namespace)`, `customStore(store)`, `resilientStore(store)`; the old `*CookieStore` names are aliases.
|
|
287
|
+
- Redis adapters get the atomic operations through Lua (`eval`) when the client has it. Cloudflare KV has none: use `durableObjectStore(stub)` with `handleDurableObjectStoreRequest(this.ctx.storage, request)` inside your Durable Object class for locks and the journal on Workers.
|
|
288
|
+
- Adapters are resilient by default: `get`/`set`/`delete` errors are reported to `onError` and swallowed, atomic operation errors are reported and rethrown. `resilient: false` rethrows everything.
|
|
289
|
+
- `diagnoseStore(store)` returns `{ ok, capabilities, suitableFor: { session, attemptLedger, createOnceLock, journal, webhookDedupe }, latencyMs, problems }` after a round-trip with a temporary key.
|
|
290
|
+
|
|
291
|
+
### `kassza/journal`
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
const journal = createJournal(kvJournal(store), { now? })
|
|
295
|
+
createKassza({ hooks: { onDocument: (event) => journal.record(event), onDocumentError: 'throw' } })
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
- `kvJournal(store, { prefix?, retentionDays? (400), reservationTtlDays? (30) })` needs a store with `increment`; `memoryJournal()` for tests; or implement `JournalStorage` for SQL.
|
|
299
|
+
- `record(event)` stores created and reversed documents (payments are ignored); idempotent by document number.
|
|
300
|
+
- `trackReceipt(orderNumber, run)` / `trackInvoice(orderNumber, run)` reserve before `run` and complete after it. Definite `SzamlazzError`s release the reservation; uncertain errors and crashes leave it pending. A failed journal write after success throws `JournalWriteError` with `result`.
|
|
301
|
+
- `pending(range?)` lists reservations (last 30 days by default); `settle(kassza, { range?, releaseNotFound? })` looks them up by order number and records what it finds.
|
|
302
|
+
- `entries({ from, to, kind? })`, `receipts({ from, to, includeTest? })` (feed into `navDailyReports`), at most 366 days per call.
|
|
303
|
+
- `reconcile(archive, { from?, to?, dryRun? })` compares with the data link receipt archive: `{ range, added, missingFromArchive, matched }`.
|
|
271
304
|
|
|
272
305
|
### `kassza/payments`
|
|
273
306
|
|
|
@@ -283,7 +316,8 @@ Webhook handlers are `(request: Request) => Promise<Response>`, usable directly
|
|
|
283
316
|
|
|
284
317
|
- Common options: `onPayment(payment)`, `onError?(error)`, `method?` (the payment method written on the document), `maxBodyBytes?`, `fetch?`; `sandbox?` where the provider has one.
|
|
285
318
|
- Responses: `400` for a bad signature or payload (never reaches `onPayment`), `200` on success (`204` for Revolut, a signed JSON for SimplePay), `500` when `onPayment` throws, so the provider redelivers.
|
|
286
|
-
- `PaymentEvent` is `{ provider, kind: 'paid' | 'refunded' | 'partially-refunded' | 'failed' | 'other', id, eventId?, eventType?, orderRef?, amount?: { value, currency }, refundedAmount?, paidAt?, method, customer?, items?, raw }`. Amounts are in major units (12700 HUF, not minor units).
|
|
319
|
+
- `PaymentEvent` is `{ provider, kind: 'paid' | 'refunded' | 'partially-refunded' | 'failed' | 'other', id, eventId?, eventType?, orderRef?, amount?: { value, currency }, refundedAmount?, refunds?: { id, amount, refundedBefore?, createdAt? }[], paidAt?, method, customer?, items?, raw }`. Amounts are in major units (12700 HUF, not minor units). `refunds` lists the individual refunds the provider reported (Barion and SimplePay: all; Revolut and PayPal: the current one; Stripe: the delta of `charge.refunded` keyed by the event ID).
|
|
320
|
+
- `dedupe?: KeyValueStore` and `dedupeTtlSeconds?` (7 days): an event that was already processed successfully is acknowledged without calling `onPayment` again. It is marked only after `onPayment` succeeds.
|
|
287
321
|
|
|
288
322
|
```ts
|
|
289
323
|
const result = await kassza.issueForPayment(payment, {
|
|
@@ -297,18 +331,36 @@ const result = await kassza.issueForPayment(payment, {
|
|
|
297
331
|
orderNumber?: string,
|
|
298
332
|
exchangeRate?, exchangeBank?,
|
|
299
333
|
allowAmountMismatch?: boolean,
|
|
334
|
+
partialRefund?: 'auto' | 'proportional' | 'skip',
|
|
335
|
+
refundItems?: ({ refund, invoiceNumber, items }) => PaymentDocumentItem[] | undefined,
|
|
300
336
|
receipt?: Partial<CreateReceiptInput>,
|
|
301
337
|
invoice?: Partial<CreateInvoiceInput>,
|
|
302
338
|
})
|
|
303
339
|
```
|
|
304
340
|
|
|
305
|
-
- `paid`: chooses receipt or invoice with `chooseDocument` (override with `document`) and issues it with `createOnce`. `refunded`: reverses that document exactly once. `
|
|
341
|
+
- `paid`: chooses receipt or invoice with `chooseDocument` (override with `document`) and issues it with `createOnce`. `refunded`: reverses that document exactly once. `failed` and `other`: skipped.
|
|
342
|
+
- `partially-refunded`: for an invoice, one corrective invoice per refund (external ID `{orderNumber}/R-{refund}`), with the refund allocated exactly over the original items (`allocateRefund`, house-monotone, never more than an item's original amount across refunds). If the invoice has several VAT rates and no `refundItems` is given, it returns `{ kind: 'refund-proposal', ... }` instead (or allocate proportionally with `partialRefund: 'proportional'`). For a receipt it always returns a `refund-proposal`. Without `payment.refunds` it is skipped with a reason.
|
|
306
343
|
- The order number defaults to `{PROVIDER}-{payment id}`, for example `STRIPE-pi_123`, so the payment and its refund share it.
|
|
307
344
|
- Items come from `items`, then the provider's line items, then one item with the paid amount (`fallbackItemName`). VAT comes from `vatFor`, the provider's per-item rate, then `vat`. Without any, it throws `validation`: kassza never guesses VAT.
|
|
308
345
|
- The document total must equal the paid amount, unless `allowAmountMismatch: true`.
|
|
309
|
-
- It returns `{ kind: 'receipt', number, created, receipt, decision, orderNumber }`, `{ kind: 'invoice', number, created, invoice, decision, orderNumber }`, `{ kind: 'reversal', document, reversedNumber, number?, created, orderNumber }` or `{ kind: 'skipped', reason, orderNumber }`.
|
|
346
|
+
- It returns `{ kind: 'receipt', number, created, receipt, decision, orderNumber }`, `{ kind: 'invoice', number, created, invoice, decision, orderNumber }`, `{ kind: 'reversal', document, reversedNumber, number?, created, orderNumber }`, `{ kind: 'correction', correctedNumber, created, corrections: { refundId, externalId, number, created, grossTotal, invoice }[], orderNumber }`, `{ kind: 'refund-proposal', document, documentNumber, refunds: { refundId, grossTotal, items }[], reason, orderNumber }` or `{ kind: 'skipped', reason, orderNumber }`.
|
|
310
347
|
- `issueForPayment(api, payment, options)` from `kassza/payments` does the same with any object that has `invoices` and `receipts` (`createOnce`, `find`, `reverse`), for example a delegated client.
|
|
311
348
|
|
|
349
|
+
### `kassza/batch`
|
|
350
|
+
|
|
351
|
+
- `runBatch(kassza, { items: { key, document: () => ({ kind: 'invoice' | 'receipt', input }) }[], concurrency? (1, max 4), ratePerMinute? (30), dryRun?, journal?, signal?, onProgress?, recoveryDelayMs? })` issues each item with `createOnce`, using `key` as the order number, so a rerun never duplicates. It stops (marking the rest `skipped`) on `rate_limit`, `auth`, `account`, `configuration`, `maintenance`, `attempt_limit` or `store_unavailable`; other item errors land in `failed`. `dryRun` previews invoices and computes receipts locally. Returns `{ dryRun, items, created, existing, previewed, failed, skipped, stopped?, grossTotal }`.
|
|
352
|
+
- `billingPeriod({ interval: 'week' | 'month' | 'quarter' | 'year', anchor, paymentDueInDays? }, index)`, `billingPeriodAt(options, date)`, `billingPeriodsBetween(options, from, to)`, `todayPeriod(options)` return `{ index, interval, start, end, dueDate?, key }` in Budapest dates; month ends never drift (Jan 31 → Feb 28/29 → Mar 31). The fulfilment date is the caller's legal decision.
|
|
353
|
+
|
|
354
|
+
### `kassza/node`
|
|
355
|
+
|
|
356
|
+
- `toNodeHandler(webHandler, { trustProxy?, onError? })` adapts any `(Request) => Response` handler to Express, NestJS and `node:http`. It streams the raw body (so signatures verify), uses `rawBody` (NestJS) or a Buffer `body` (`express.raw`), and throws `NodeBodyError` when `express.json()` already consumed the body. With Express `next`, errors go to `next`.
|
|
357
|
+
- `toWebRequest(nodeRequest)` and `writeWebResponse(response, nodeResponse)` for Fastify or custom servers.
|
|
358
|
+
|
|
359
|
+
### `kassza/observe`
|
|
360
|
+
|
|
361
|
+
- `observe({ logger?, tracer?, metrics?, redact? (true), orderRefSalt?, logRequests? })` returns hooks: structured logs without secrets (order numbers as `hmac:` refs), one span per attempt (OpenTelemetry `Tracer` compatible), and metrics. `combineHooks(...hooks)` merges hook sets.
|
|
362
|
+
- `createMetricsRegistry(buckets?)` is a dependency-free registry with `renderPrometheus()`. Metrics: `kassza_requests_total{action,outcome}`, `kassza_request_duration_ms{action}`, `kassza_retries_total`, `kassza_maintenance_total`, `kassza_unexpected_response_total`, `kassza_store_errors_total{store}`, `kassza_warnings_total{kind}`, `kassza_documents_total{kind,action}`.
|
|
363
|
+
|
|
312
364
|
### `kassza/delegation`
|
|
313
365
|
|
|
314
366
|
```ts
|
package/agents/pitfalls.md
CHANGED
|
@@ -12,7 +12,9 @@ Read this before writing any code that issues invoices or receipts. These rules
|
|
|
12
12
|
6. **Use the test account while developing.** It allows at most 500 invoices per 10 minutes (error `167`, `rate_limit`). Never run tests against a production Agent key.
|
|
13
13
|
7. **An Agent receipt is a computer-generated receipt (számítógéppel előállított nyugta).** It is not an online cash register receipt and not an e-receipt (e-nyugta). Issue it only for activities without the online cash register (OPG) obligation. Fixed-location retail (TEÁOR 47.1–47.7), restaurants and bars (56.1, 56.3, except mobile catering), accommodation (55.1–55.3), rental (77.1–77.2, 77.33), repair (95.1–95.2) and pharmacies need an online cash register or e-cash register instead. Typical valid uses: webshops, online tickets, downloadable products, food trucks and other mobile sales, services without a cash register obligation.
|
|
14
14
|
8. **A receipt may replace an invoice only if all four conditions hold:** the buyer is not a taxable person or legal entity, the total is below 900 000 HUF, it is paid in full by fulfilment, and the buyer did not ask for an invoice. `chooseDocument()` applies these rules, and `issueForPayment()` uses it. If the buyer asks for an invoice later, use `receipts.convertToInvoice()`.
|
|
15
|
-
9. **
|
|
15
|
+
9. **In serverless or multi-process setups, give `createOnce` a shared lock.** Two concurrent deliveries of the same webhook on two instances can both see "no invoice yet". Pass `createOnceLock: store` (Redis, Upstash or Durable Object from `kassza/stores`; Cloudflare KV cannot lock). Calls inside one process are merged automatically.
|
|
16
|
+
10. **If your `onDocument` hook writes a legally relevant journal, set `onDocumentError: 'throw'`.** Otherwise a failed write is only a warning and the NAV daily summary silently misses a receipt. Use `kassza/journal` for this.
|
|
17
|
+
11. **Never submit NAV receipt reports for receipts issued in Számlázz.hu.** Számlázz.hu reports them itself after the NAV connection, so a second submission is double reporting. The `kassza/nav` client is read-only unless you pass `allowWrite: true`; submit only reports of paper receipt pads.
|
|
16
18
|
|
|
17
19
|
## Behaviour worth knowing
|
|
18
20
|
|
|
@@ -42,7 +44,14 @@ Read this before writing any code that issues invoices or receipts. These rules
|
|
|
42
44
|
| Error `250` | A delegated account has not been taken over by its owner, or the delegation is not accepted | Wait for the principal; check with `probeDelegation()` rarely, never in a loop |
|
|
43
45
|
| Error `167` (`rate_limit`) | Too many documents in the test account in a short time | Wait a few minutes; never retry automatically |
|
|
44
46
|
| `attempt_limit` error | The same request already failed 5 times (counted across processes with `attemptLedger`) | A human fixes the cause, then `kassza.resetAttempts(error)` |
|
|
47
|
+
| `attemptLedger` limits | The ledger is conservative: network and timeout failures count too, and the check (read) and the count (increment) are separate store calls, so many processes sending the *same* request at the very same moment can each pass the check | Pair it with `createOnceLock` for documents, so only one process sends at a time |
|
|
45
48
|
| `maintenanceCooldownMs` | After error `1`, kassza sends nothing for the cooldown and throws `maintenance` at once | Switch to a fallback, for example a paper receipt pad |
|
|
49
|
+
| `in_progress` error | Another process holds the `createOnce` lock for this order | Do not issue by hand; call `createOnce` again later (5xx in a webhook) |
|
|
50
|
+
| `store_unavailable` error | The lock store (or a `fail-closed` attempt ledger) is down; nothing was sent | Restore the store, or choose `lockFailure: 'proceed'` / `attemptLedgerMode: 'fail-open'` deliberately |
|
|
51
|
+
| Partial refund on a mixed-VAT invoice | `issueForPayment` returns `refund-proposal`, issues nothing | Pass `refundItems` (what was returned) or `partialRefund: 'proportional'` |
|
|
52
|
+
| `registerPayment` twice | Two payments on the invoice (`additive` defaults to `true`) | Use `registerPaymentOnce({ key })` with a stable bank or payment ID |
|
|
53
|
+
| `szamlaLetoltesPld` (PDF copies) | Obsolete in the XSD; Számlázz.hu ignores it, so kassza does not offer it | Nothing to do |
|
|
54
|
+
| `express.json()` before a webhook route | The raw body is gone, signatures cannot be verified | Mount the route before `express.json()`, or use `express.raw()`; see `kassza/node` |
|
|
46
55
|
|
|
47
56
|
## Error categories
|
|
48
57
|
|
|
@@ -59,6 +68,8 @@ Read this before writing any code that issues invoices or receipts. These rules
|
|
|
59
68
|
| `maintenance` | Számlázz.hu maintenance (code 1) | kassza retries lookups automatically |
|
|
60
69
|
| `rate_limit` | Too many documents in the test account (code 167) | No, wait a few minutes |
|
|
61
70
|
| `attempt_limit` | The request already failed 5 times; kassza did not send it | No, a human must act, then `resetAttempts` |
|
|
71
|
+
| `in_progress` | Another process is issuing the same document (`createOnce` lock) | Later, by calling `createOnce` again |
|
|
72
|
+
| `store_unavailable` | A required store (lock, fail-closed ledger) is down; nothing was sent | After the store is back |
|
|
62
73
|
| `network` / `timeout` | Transport failure; the outcome is unknown for writes | Look up by `orderNumber` before trying again |
|
|
63
74
|
| `configuration` | Missing key, bad options | No |
|
|
64
75
|
| `unexpected_response` | Számlázz.hu answered in an unknown format | Report it |
|