Pénztári nyugta Egy bolt vagy büfé pénztárprogramja minden eladás után nyugtát kér. A vevő kérheti e-mailben is. A hálózat itt sem megbízható: ha a kérés elakad, a pénztáros újra megnyomja a gombot, és ebből nem lehet két nyugta.
Nyugtánál ezt a hívásazonosító (callId) oldja meg. Ugyanazzal a callId-val a Számlázz.hu nem készít második nyugtát, hanem 338-as hibát ad, amelyet a kassza duplicate kategóriájú hibává alakít. Emiatt a kassza hálózati hiba után a nyugtát magától is újrapróbálja, ha van callId.
A nyugtakészítő függvény#
A nyugta előtagját és alapértelmezett fizetési módját a Közös kliens defaults.receipt beállítása adja.
lib/penztar.ts import { isSzamlazzError , type Kassza , type Receipt , type ReceiptItemInput } from 'kassza'
import { kassza as alapKliens } from '@/lib/kassza'
export interface Eladas {
readonly id : string
readonly fizetesiMod : 'készpénz' | 'bankkártya'
readonly tetelek : readonly ReceiptItemInput []
}
export async function nyugtaEladasrol (
eladas : Eladas ,
kliens : Kassza = alapKliens ,
) : Promise < Receipt > {
const azonosito = `POS- ${ eladas .id } `
try {
return await kliens . receipts .create ({
callId : azonosito ,
orderNumber : azonosito ,
paymentMethod : eladas .fizetesiMod ,
downloadPdf : false ,
items : eladas .tetelek ,
})
} catch (error) {
if ( ! isSzamlazzError (error) || ! error .isDuplicate) throw error
const meglevo = await kliens . receipts .find ({ orderNumber : azonosito , downloadPdf : false })
if (meglevo) return meglevo
throw error
}
}
A callId és a rendelésszám ugyanaz. A Számla Agent hívásazonosító alapján nem ad lekérdezést, ezért a dupla nyugta hibája után a rendelésszám alapján keressük meg a már elkészült nyugtát.
A tételeknél bruttó egységárat adj meg, a nettó és az áfa összegét a kassza számolja ki a nyugtákra vonatkozó kerekítéssel:
lib/penztar-tetelek.ts import type { ReceiptItemInput } from 'kassza'
export const KAVE : ReceiptItemInput = { name : 'Kávé' , grossUnitPrice : 890 , vat : 27 }
export const KIFLI : ReceiptItemInput = { name : 'Kifli' , grossUnitPrice : 250 , vat : 5 }
Nyugta kiállítása
Pénztári nyugta hívásazonosítóval, két áfakulccsal, alapbeállításokkal.
Futtatás a sandboxbanKód Elküldött XML Válasz Konzol
nyugta.ts import { createKassza } from 'kassza'
const kassza = createKassza ({
defaults : { receipt : { prefix : 'NYGT' , paymentMethod : 'készpénz' } } ,
})
const nyugta = await kassza . receipts . create ({
callId : 'PENZTAR-2026-0001' ,
orderNumber : 'PENZTAR-2026-0001' ,
items : [
{ name : 'Kávé' , quantity : 2 , grossUnitPrice : 890 , vat : 27 } ,
{ name : 'Kifli' , grossUnitPrice : 250 , vat : 5 } ,
] ,
})
console . log ( nyugta . number , nyugta . type , nyugta . issueDate )
console . log ( nyugta . totals )
console . log (
nyugta . items . map (
( tetel ) => ` ${ tetel . name } : ${ tetel . netAmount } + ${ tetel . vatAmount } = ${ tetel . grossAmount } ` ,
) ,
) Nyugta létrehozás · action-szamla_agent_nyugta_create <? xml version = "1.0" encoding = "UTF-8" ?>
< xmlnyugtacreate xmlns = "http://www.szamlazz.hu/xmlnyugtacreate" xmlns : xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi : schemaLocation = "http://www.szamlazz.hu/xmlnyugtacreate https://www.szamlazz.hu/szamla/docs/xsds/nyugtacreate/xmlnyugtacreate.xsd" >
< beallitasok >
< szamlaagentkulcs >••••••••</ szamlaagentkulcs >
< pdfLetoltes >true</ pdfLetoltes >
</ beallitasok >
< fejlec >
< hivasAzonosito >PENZTAR-2026-0001</ hivasAzonosito >
< elotag >NYGT</ elotag >
< fizmod >készpénz</ fizmod >
< penznem >HUF</ penznem >
< rendelesSzam >PENZTAR-2026-0001</ rendelesSzam >
</ fejlec >
< tetelek >
< tetel >
< megnevezes >Kávé</ megnevezes >
< mennyiseg >2</ mennyiseg >
< mennyisegiEgyseg >db</ mennyisegiEgyseg >
< nettoEgysegar >700.785</ nettoEgysegar >
< afakulcs >27</ afakulcs >
< netto >1401.57</ netto >
< afa >378.43</ afa >
< brutto >1780</ brutto >
</ tetel >
< tetel >
< megnevezes >Kifli</ megnevezes >
< mennyiseg >1</ mennyiseg >
< mennyisegiEgyseg >db</ mennyisegiEgyseg >
< nettoEgysegar >238.1</ nettoEgysegar >
< afakulcs >5</ afakulcs >
< netto >238.10</ netto >
< afa >11.90</ afa >
< brutto >250</ brutto >
</ tetel >
</ tetelek >
</ xmlnyugtacreate >
Nyugta létrehozás · válasz, HTTP 200 content-type: application/xml; charset=UTF-8
set-cookie: JSESSIONID=51AD9DB082F41D932FFFB360; Path=/szamla; Secure; HttpOnly
<? xml version = "1.0" encoding = "UTF-8" ?>
< xmlnyugtavalasz xmlns = "http://www.szamlazz.hu/xmlnyugtavalasz" >
< sikeres >true</ sikeres >
< hibakod ></ hibakod >
< hibauzenet ></ hibauzenet >
< nyugtaPdf >JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5k… (base64 PDF, rövidítve)</ nyugtaPdf >
< nyugta >
< alap >
< id >1001</ id >
< hivasAzonosito >PENZTAR-2026-0001</ hivasAzonosito >
< nyugtaszam >NYGT-2026-1</ nyugtaszam >
< tipus >NY</ tipus >
< stornozott >false</ stornozott >
< kelt >2026-09-19</ kelt >
< fizmod >készpénz</ fizmod >
< penznem >HUF</ penznem >
< teszt >true</ teszt >
< rendelesSzam >PENZTAR-2026-0001</ rendelesSzam >
</ alap >
< tetelek >
< tetel >
< megnevezes >Kávé</ megnevezes >
< mennyiseg >2</ mennyiseg >
< mennyisegiEgyseg >db</ mennyisegiEgyseg >
< nettoEgysegar >700.785</ nettoEgysegar >
< netto >1401.57</ netto >
< afakulcs >27</ afakulcs >
< afa >378.43</ afa >
< brutto >1780</ brutto >
</ tetel >
< tetel >
< megnevezes >Kifli</ megnevezes >
< mennyiseg >1</ mennyiseg >
< mennyisegiEgyseg >db</ mennyisegiEgyseg >
< nettoEgysegar >238.1</ nettoEgysegar >
< netto >238.1</ netto >
< afakulcs >5</ afakulcs >
< afa >11.9</ afa >
< brutto >250</ brutto >
</ tetel >
</ tetelek >
< osszegek >
< afakulcsossz >
< afakulcs >27</ afakulcs >
< netto >1401.57</ netto >
< afa >378.43</ afa >
< brutto >1780</ brutto >
</ afakulcsossz >
< afakulcsossz >
< afakulcs >5</ afakulcs >
< netto >238.1</ netto >
< afa >11.9</ afa >
< brutto >250</ brutto >
</ afakulcsossz >
< totalossz >
< netto >1639.67</ netto >
< afa >390.33</ afa >
< brutto >2030</ brutto >
</ totalossz >
</ osszegek >
</ nyugta >
</ xmlnyugtavalasz >
Konzol NYGT-2026-1 receipt 2026-09-19
{
netAmount: 1639.67,
vatAmount: 390.33,
grossAmount: 2030,
byVat: [
{
vat: 27,
vatPercentage: 27,
netAmount: 1401.57,
vatAmount: 378.43,
grossAmount: 1780
},
{
vat: 5,
vatPercentage: 5,
netAmount: 238.1,
vatAmount: 11.9,
grossAmount: 250
}
]
}
[
'Kávé: 1401.57 + 378.43 = 1780',
'Kifli: 238.1 + 11.9 = 250'
]
Route handler#
A pénztárprogram az eladás mentése után hívja ezt a végpontot, opcionálisan a vevő e-mail címével. Az eladasBetoltese() és a nyugtaszamMentese() a saját adatbázis-függvényeid, az adminKeres() a Nevezés díjbekérővel recept belső token ellenőrzése.
app/api/penztar/eladasok/[id]/nyugta/route.ts import { isSzamlazzError , type Receipt } from 'kassza'
import { isValidEmail } from 'kassza/validators'
import { adminKeres } from '@/lib/admin'
import { eladasBetoltese , nyugtaszamMentese } from '@/lib/eladasok'
import { kassza } from '@/lib/kassza'
import { nyugtaEladasrol } from '@/lib/penztar'
async function nyugtaKuldese (receiptNumber : string , email : string ) : Promise < boolean > {
try {
await kassza . receipts .send ({
receiptNumber ,
emails : email ,
subject : `Nyugtád: ${ receiptNumber } ` ,
})
return true
} catch (error) {
if ( ! isSzamlazzError (error)) throw error
console .error ( 'A nyugta kiküldése nem sikerült' , receiptNumber , error .category)
return false
}
}
export async function POST (request : Request , { params } : { params : Promise <{ id : string }> }) {
if ( ! adminKeres (request)) return new Response ( 'Nincs jogosultság' , { status : 401 })
const { id } = await params
const eladas = await eladasBetoltese (id)
if ( ! eladas) return Response .json ({ hiba : 'Nincs ilyen eladás.' } , { status : 404 })
const { email } = ( await request .json () .catch (() => ({}))) as { email ?: unknown }
if (email !== undefined && ( typeof email !== 'string' || ! isValidEmail (email))) {
return Response .json ({ hiba : 'Érvénytelen e-mail cím.' } , { status : 400 })
}
let nyugta : Receipt
try {
nyugta = await nyugtaEladasrol (eladas)
} catch (error) {
if ( ! isSzamlazzError (error)) throw error
return Response .json (
{ hiba : error .message , tipp : error .hint } ,
{ status : error .retryable ? 503 : 422 } ,
)
}
await nyugtaszamMentese ( eladas .id , nyugta .number)
const kikuldve = typeof email === 'string' ? await nyugtaKuldese ( nyugta .number , email) : false
return Response .json ({
nyugtaszam : nyugta .number ,
brutto : nyugta . totals .grossAmount ,
kikuldve ,
})
}
Ha a végpont 503-mal válaszol, a pénztáros nyugodtan újrapróbálhatja: ugyanaz a callId megy el, így legfeljebb a már elkészült nyugtát kapja vissza.
Nyugta kiküldése e-mailben
Nyugta elküldése a vevőnek saját tárggyal és válaszcímmel.
Futtatás a sandboxbanKód Elküldött XML Válasz Konzol
nyugta-kikuldes.ts import { createKassza } from 'kassza'
import { simulator } from 'kassza-sandbox'
const kassza = createKassza ({
defaults : { receipt : { prefix : 'NYGT' , paymentMethod : 'bankkártya' } } ,
})
const nyugta = await kassza . receipts . create ({
callId : 'WEB-2026-0391' ,
items : [{ name : 'Online kurzus, 1 hónap' , grossUnitPrice : 7_990 , vat : 27 }] ,
})
await kassza . receipts . send ({
receiptNumber : nyugta . number ,
emails : [ 'vevo@example.hu' , 'konyveles@example.hu' ] ,
replyTo : 'ugyfelszolgalat@example.hu' ,
subject : `Nyugta a vásárlásodról ( ${ nyugta . number } )` ,
text : 'Köszönjük a vásárlást! A nyugtát csatolva küldjük.' ,
})
console . log ( 'Címzettek:' , simulator .account ().receipts[ 0 ]?.sentTo) 1. Nyugta létrehozás · action-szamla_agent_nyugta_create <? xml version = "1.0" encoding = "UTF-8" ?>
< xmlnyugtacreate xmlns = "http://www.szamlazz.hu/xmlnyugtacreate" xmlns : xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi : schemaLocation = "http://www.szamlazz.hu/xmlnyugtacreate https://www.szamlazz.hu/szamla/docs/xsds/nyugtacreate/xmlnyugtacreate.xsd" >
< beallitasok >
< szamlaagentkulcs >••••••••</ szamlaagentkulcs >
< pdfLetoltes >true</ pdfLetoltes >
</ beallitasok >
< fejlec >
< hivasAzonosito >WEB-2026-0391</ hivasAzonosito >
< elotag >NYGT</ elotag >
< fizmod >bankkártya</ fizmod >
< penznem >HUF</ penznem >
</ fejlec >
< tetelek >
< tetel >
< megnevezes >Online kurzus, 1 hónap</ megnevezes >
< mennyiseg >1</ mennyiseg >
< mennyisegiEgyseg >db</ mennyisegiEgyseg >
< nettoEgysegar >6291.34</ nettoEgysegar >
< afakulcs >27</ afakulcs >
< netto >6291.34</ netto >
< afa >1698.66</ afa >
< brutto >7990</ brutto >
</ tetel >
</ tetelek >
</ xmlnyugtacreate >
2. Nyugta kiküldés · action-szamla_agent_nyugta_send <? xml version = "1.0" encoding = "UTF-8" ?>
< xmlnyugtasend xmlns = "http://www.szamlazz.hu/xmlnyugtasend" xmlns : xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi : schemaLocation = "http://www.szamlazz.hu/xmlnyugtasend https://www.szamlazz.hu/szamla/docs/xsds/nyugtasend/xmlnyugtasend.xsd" >
< beallitasok >
< szamlaagentkulcs >••••••••</ szamlaagentkulcs >
</ beallitasok >
< fejlec >
< nyugtaszam >NYGT-2026-1</ nyugtaszam >
</ fejlec >
< emailKuldes >
< email >vevo@example.hu,konyveles@example.hu</ email >
< emailReplyto >ugyfelszolgalat@example.hu</ emailReplyto >
< emailTargy >Nyugta a vásárlásodról (NYGT-2026-1)</ emailTargy >
< emailSzoveg >Köszönjük a vásárlást! A nyugtát csatolva küldjük.</ emailSzoveg >
</ emailKuldes >
</ xmlnyugtasend >
1. Nyugta létrehozás · válasz, HTTP 200 content-type: application/xml; charset=UTF-8
set-cookie: JSESSIONID=3F9C1FC528B1F35F3F527362; Path=/szamla; Secure; HttpOnly
<? xml version = "1.0" encoding = "UTF-8" ?>
< xmlnyugtavalasz xmlns = "http://www.szamlazz.hu/xmlnyugtavalasz" >
< sikeres >true</ sikeres >
< hibakod ></ hibakod >
< hibauzenet ></ hibauzenet >
< nyugtaPdf >JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5k… (base64 PDF, rövidítve)</ nyugtaPdf >
< nyugta >
< alap >
< id >1001</ id >
< hivasAzonosito >WEB-2026-0391</ hivasAzonosito >
< nyugtaszam >NYGT-2026-1</ nyugtaszam >
< tipus >NY</ tipus >
< stornozott >false</ stornozott >
< kelt >2026-09-19</ kelt >
< fizmod >bankkártya</ fizmod >
< penznem >HUF</ penznem >
< teszt >true</ teszt >
</ alap >
< tetelek >
< tetel >
< megnevezes >Online kurzus, 1 hónap</ megnevezes >
< mennyiseg >1</ mennyiseg >
< mennyisegiEgyseg >db</ mennyisegiEgyseg >
< nettoEgysegar >6291.34</ nettoEgysegar >
< netto >6291.34</ netto >
< afakulcs >27</ afakulcs >
< afa >1698.66</ afa >
< brutto >7990</ brutto >
</ tetel >
</ tetelek >
< osszegek >
< afakulcsossz >
< afakulcs >27</ afakulcs >
< netto >6291.34</ netto >
< afa >1698.66</ afa >
< brutto >7990</ brutto >
</ afakulcsossz >
< totalossz >
< netto >6291.34</ netto >
< afa >1698.66</ afa >
< brutto >7990</ brutto >
</ totalossz >
</ osszegek >
</ nyugta >
</ xmlnyugtavalasz >
2. Nyugta kiküldés · válasz, HTTP 200 content-type: application/xml; charset=UTF-8
<? xml version = "1.0" encoding = "UTF-8" ?>
< xmlnyugtasendvalasz xmlns = "http://www.szamlazz.hu/xmlnyugtasendvalasz" >
< sikeres >true</ sikeres >
< hibakod ></ hibakod >
< hibauzenet ></ hibauzenet >
</ xmlnyugtasendvalasz >
Konzol Címzettek: [ 'vevo@example.hu', 'konyveles@example.hu' ]
Buktatók#
A callId legyen állandó
A hívásazonosító az eladás azonosítójából készüljön, soha ne véletlen értékből vagy
időbélyegből. Új callId-val minden újrapróbálás új nyugtát állít ki. Egy kérést itt is
legfeljebb ötször szabad elküldeni, utána embernek kell ránéznie.
Nyugta előtag és fizetési mód
A nyugta előtagja csak nagybetűt és számot tartalmazhat, és nem lehet olyan, amelyet számlán már
használtál (336, 337). A fizetési módnak nyugtán nincs beépített alapértéke: add meg a hívásban
vagy a defaults.receipt.paymentMethod beállításban, különben a kassza validation hibát ad.
A kiküldés külön lépés
A receipts.send() hibája nem érinti a már elkészült nyugtát, ezért a recept csak jelzi a
kikuldve: false mezőben. A kiküldést a kassza nem próbálja újra magától. Egy admin felületről
később újra elküldheted a nyugtaszám alapján.
NAV adatszolgáltatás
A nyugtákról 2026. szeptember 1-jétől adatot kell szolgáltatni a NAV felé, de 2026. december
31-ig türelmi idő van. A Számlázz.hu leírása szerint ezzel egyelőre nincs teendőd, a kassza
változásait a changelogban követheted.
Ne számold ki az összegeket
Forintos nyugtán a bruttó összeg egész szám, a nettó és az áfa legfeljebb két tizedesjegy, és a
kettő összege pontosan a bruttó. Ha a grossUnitPrice mezőt adod meg, a kassza ezt betartja,
a kézzel számolt összegek viszont könnyen 261-es vagy 363–365-ös hibát okoznak.
Kapcsolódó#