Sari la conținut
Fisco
Manual pentru dezvoltatori

Cum vrei să scrii bonul?

Alege sintaxa. Îți arătăm doar ce ai nevoie pentru ea: primul bon, comenzile și cum afli dacă s-a tipărit. Merge la fel pe Datecs, Daisy și Tremol.

Toate trei tipăresc același bon. Referință comună: Endpoint-uri API·Coduri de eroare·POS bancar

Sintaxa
← Alege altă sintaxă
Început

Primul bon

Același bon în fiecare sintaxă: 2 cafele de 9,50 lei și o apă de 5 lei, plătite cu cardul (24 lei).

Fisco JSON, prin API HTTP

Trimiți

POST http://127.0.0.1:4040/api/v1/print?wait=30
{
  "syntax": "fisco",
  "receipt": {
    "items": [
      { "name": "Cafea", "price": 950, "quantity": 2000, "vat": "A" },
      { "name": "Apa plata", "price": 500, "vat": "B" }
    ],
    "payments": [{ "type": "card", "amount": 2400 }]
  }
}
Bon fiscal: 2 cafele × 9,50 lei pe cota A și o apă de 5,00 lei pe cota B, plătit cu cardul (24,00 lei).

Primești, după ce bonul s-a tipărit

200 OK
{
  "ok": true,
  "job_id": "http_20261020_101502_118_00001",
  "status": "printed",
  "result": {
    "SlipNumber": "1959",
    "nZrep": "42",
    "nFNum": "200",
    "DeviceSerial": "DB4100000055"
  }
}
Bonul s-a tipărit: numărul documentului (SlipNumber), Z-ul în care intră, numărul bonului în Z și seria casei.

Sintaxa simplificată, prin API HTTP

Trimiți

POST http://127.0.0.1:4040/api/v1/print?wait=30
{
  "syntax": "simplu",
  "commands": [
    "S^Cafea^950^2000^buc^1^1",
    "S^Apa plata^500^1000^buc^2^1",
    "P^2^2400"
  ]
}
Bon fiscal: 2 cafele × 9,50 lei pe cota A și o apă de 5,00 lei pe cota B, plătit cu cardul (24,00 lei).

Primești, după ce bonul s-a tipărit

200 OK
{
  "ok": true,
  "job_id": "http_20261020_101502_118_00001",
  "status": "printed",
  "result": {
    "SlipNumber": "1959",
    "nZrep": "42",
    "nFNum": "200",
    "DeviceSerial": "DB4100000055"
  }
}
Bonul s-a tipărit: numărul documentului (SlipNumber), Z-ul în care intră, numărul bonului în Z și seria casei.

Sintaxa simplificată, prin fișier

Programul scrie fișierul

C:\Fisco\Bonuri\bon_154.inp
S^Cafea^950^2000^buc^1^1
S^Apa plata^500^1000^buc^2^1
P^2^2400
Bon fiscal: 2 cafele × 9,50 lei pe cota A și o apă de 5,00 lei pe cota B, plătit cu cardul (24,00 lei).

Fisco lasă răspunsul

C:\Fisco\Bonuri\BonANSWER\bon_154.inp
[Answer]
SlipNumber=1959
nZrep=42
nFNum=200
DeviceSerial=DB4100000055
Bonul s-a tipărit: numărul documentului (SlipNumber), Z-ul în care intră, numărul bonului în Z și seria casei.

Sintaxa FPrint, prin API HTTP

Trimiți

POST http://127.0.0.1:4040/api/v1/print?wait=30
{
  "syntax": "fprint",
  "commands": [
    "S,1,______,_,__;Cafea;9.50;2.000;1;1;1;0;0;buc",
    "S,1,______,_,__;Apa plata;5.00;1.000;1;1;2;0;0;buc",
    "T,1,______,_,__;1;24.00;;;;"
  ]
}
Bon fiscal: 2 cafele × 9,50 lei pe cota A și o apă de 5,00 lei pe cota B, plătit cu cardul (24,00 lei).

Primești, după ce bonul s-a tipărit

200 OK
{
  "ok": true,
  "job_id": "http_20261020_101502_118_00001",
  "status": "printed",
  "result": {
    "SlipNumber": "1959",
    "nZrep": "42",
    "nFNum": "200",
    "DeviceSerial": "DB4100000055"
  }
}
Bonul s-a tipărit: numărul documentului (SlipNumber), Z-ul în care intră, numărul bonului în Z și seria casei.

Sintaxa FPrint, prin fișier

Programul scrie fișierul

C:\Fisco\Bonuri\bon_154.inp
S,1,______,_,__;Cafea;9.50;2.000;1;1;1;0;0;buc
S,1,______,_,__;Apa plata;5.00;1.000;1;1;2;0;0;buc
T,1,______,_,__;1;24.00;;;;
Bon fiscal: 2 cafele × 9,50 lei pe cota A și o apă de 5,00 lei pe cota B, plătit cu cardul (24,00 lei).

Fisco lasă răspunsul

C:\Fisco\Bonuri\BonANSWER\bon_154.inp
[Answer]
SlipNumber=1959
nZrep=42
nFNum=200
DeviceSerial=DB4100000055
Bonul s-a tipărit: numărul documentului (SlipNumber), Z-ul în care intră, numărul bonului în Z și seria casei.
CâmpCe este
SlipNumbernumărul general al documentului în jurnalul electronic
nZrepraportul Z în care se va regăsi bonul
nFNumnumărul bonului fiscal în cadrul Z-ului
DeviceSerialseria casei de marcat

Bonul e tipărit doar la status: "printed". La failed, arată casierului error.message. Nu retrimite automat fără să verifici starea: riști un bon dublu.

Bonul e tipărit doar când apare în BonANSWER; la eroare apare în BonERR. Scrie fișierul ca .tmp și redenumește-l la final.

Formatul bonului

Fisco JSON RECOMANDAT

Doar pentru Fisco JSON

Descrii bonul ca obiect, fără să cunoști formatul de linie al casei. Toate valorile sunt numere întregi: sumele în bani, cantitățile în miimi, procentele în sutimi. Numerele întregi evită erorile de reprezentare a zecimalelor. O valoare cu zecimale (9.5) e respinsă, dar un preț întreg scris în lei (10 în loc de 1000) e acceptat ca 0,10 lei: verifică unitatea în program.

Ai în programTrimițiExemplu
preț / sumă în leiround(lei × 100)9,50 lei → 950
cantitateround(cant × 1000)2 buc → 2000 · 0,350 kg → 350
procentround(% × 100)10% → 1000 · 2,5% → 250

Bonul (receipt)

CâmpDescriere
itemsobligatoriuarticolele, cel puțin unul
paymentsopționalplățile; dacă lipsesc, tot totalul se încasează în numerar
client_cifopționalCIF-ul clientului, tipărit pe bon
textsopționallistă de texte, tipărite înaintea articolelor: ["Comanda 154", "Masa 20"]

Articol (items[])

CâmpDescriere
nameobligatoriudenumirea; diacriticele se transformă automat (ă→a, ș→s)
priceobligatoriupreț unitar cu TVA, în bani (950 = 9,50 lei)
vatobligatoriucota TVA: A…E sau 1…5, ca text sau număr ("A", 1 sau "1")
quantityopționalîn miimi; implicit 1000 (1 buc); negativă = retur (vezi mai jos)
unitopționalunitatea de măsură, max. 6 caractere; implicit buc
departmentopționaldepartamentul, 1…99; implicit 1
discountopționalreducerea sau majorarea articolului: { "type": "percent", "value": 1000 }. type (obligatoriu): percent sau value; value (obligatoriu): la percent în sutimi (1000 = 10%), la value în bani; surcharge (opțional, implicit false): true = majorare. Nu poate depăși valoarea articolului.

Plată (payments[])

typePlatătypePlată
cashnumerargift_tickettichete valorice
cardcardvouchervoucher
creditcreditmodernplată modernă
meal_tickettichete de masăotheralte

amount e în bani și e obligatoriu la fiecare plată.

  • Plățile trebuie să facă exact totalul bonului; altfel bonul e respins.
  • Restul se dă doar când bonul e plătit numai în numerar. La un total de 1900: cash 5000 → rest 31,00 lei; cash 1950 → rest 0,50 lei. Dacă pe bon e și altă plată (card, tichete…), nu se dă rest: numerarul trebuie să fie exact diferența (card 900 + cash 1000), iar card 900 + cash 2000 e respins.
  • Diferențe mici. Dacă plățile diferă de total cu mai puțin de 1 leu, Fisco corectează plata (de preferat pe numerar), ca bonul să se tipărească; o diferență mai mare respinge bonul. Corecția se face doar dacă e bifată „Corectează automat totaluri incorecte cu diferență mai mică de 1 leu” în setările driverului. Din experiență, diferențele vin din reduceri și din prețuri ținute în program fără TVA: casa tipărește prețul cu TVA rotunjit la ban, pe când programul de vânzare îl poate calcula cu trei sau mai multe zecimale.

Cum calculează casa: fiecare articol e price × quantity / 1000, rotunjit la ban, minus reducerea (tot rotunjită). Calculează totalul la fel în program și nu vei avea diferențe de un ban.

Retur

Un articol cu quantity negativă e un retur. Returul nu poate depăși vânzările de pe aceeași cotă de pe bon: nu poți storna 100 de lei pe cota A fără cel puțin 100 de lei vânduți pe A. Un retur pus înaintea vânzării de care are nevoie e mutat automat după ea, iar un bon cu totalul zero e permis (schimbul unui produs). Daisy nu suportă storno: acolo returul se tipărește ca reducere valorică pe articolele de pe aceeași cotă.

Bon nefiscal

JSON
{ "syntax": "fisco", "nonfiscal": { "texts": ["Comanda 154", "Masa 20", "2 x Cafea"] } }
Bon nefiscal cu trei rânduri de text.
Formatul bonului

Sintaxa simplificată

Doar pentru sintaxa simplificată

O comandă pe linie, câmpurile separate cu ^ (care nu poate apărea în texte). Sumele în bani, cantitățile în miimi, procentele în sutimi, la fel ca în JSON.

OperațieComandăExemplu
VânzareS^denumire^preț^cant^UM^TVA^depS^Ceai cu miere^350^1000^buc^1^1 (vezi Linia de vânzare; cantitate negativă = retur)
Retur (storno)VS^denumire^preț^cant^UM^TVA^depVS^Retur lampa^4500^1000^buc^1^1 (vezi Retur)
Reducere % / valoricăDP^val · DV^valDP^1000 = 10% · DV^250 = 2,50 lei (vezi Reduceri și majorări)
Majorare % / valoricăMP^val · MV^valMP^500 = 5% (vezi Reduceri și majorări)
SubtotalST^
PlatăP^tip^sumăP^1^350 numerar 3,50 (vezi Plata)
CIF clientCF^cifCF^RO22352741, pe prima linie a bonului
TextTL^textTL^Va multumim
Numerar intrat / scosI^sumă · O^sumăI^10000 = 100 lei
Raport X / ZX^ · Z^
Totalurile zilei, fără tipărire 1.4TOTALURI^singură în fișier (vezi Totalurile zilei)
Deschidere sertar 1.4DS^singură sau în bon (vezi Sertarul de bani)
Cod de bare / QRCB^date^tipCB^5940000000820^2 EAN13 (vezi Coduri de bare)
Cotă TVAÎnseamnă
1cota A
2cota B
3cota C
4cota D
5cota E (scutit / neplătitor de TVA)

Linia de vânzare, retururile și reducerile, pe larg: Vânzări, retururi, reduceri și plăți.

Formatul bonului

Sintaxa FPrint

Doar pentru sintaxa FPrint

Formatul clasic, păstrat pentru programele care îl generează deja. Fiecare linie începe cu un cod și antetul fix ,1,______,_,__, apoi câmpurile separate cu ;. Sumele și cantitățile se scriu cu punct zecimal: 3.50, 1.000.

OperațieComandă
VânzareS,1,______,_,__;denumire;preț;cant;dep;1;TVA;0;0;UM (vezi Linia de vânzare; cantitate negativă = retur)
Reducere / majorareC,1,______,_,__;tip;valoare;;;; · 0 majorare %, 1 reducere %, 2 majorare valorică, 3 reducere valorică (vezi Reduceri și majorări)
SubtotalT,1,______,_,__;4;;;;; sau L,1,______,_,__;;;;;;
PlatăT,1,______,_,__;tip;sumă;;;; · fără sumă = suma rămasă de plată, în afară de tipul 4 (vezi Plata)
CIF clientK,1,______,_,__;RO22352741;
Text (până la 3 rânduri)P,1,______,_,__;rând1;rând2;rând3;;
Numerar intrat / scosI,1,______,_,__;0;100.00;;;; · …;1;50.00;;;;
RaportZ,1,______,_,__;0; X · 1; Z · 3; X pe departamente (nu închide ziua)
Totalurile zilei, fără tipărire 1.4TOTALURI^ · aceeași linie în ambele sintaxe, singură în fișier (vezi Totalurile zilei)
Deschidere sertar 1.4DS^ · aceeași linie în ambele sintaxe; FPrint nu are o comandă pentru sertar (vezi Sertarul de bani)
Cotă TVAÎnseamnă
1cota A
2cota B
3cota C
4cota D
5cota E (scutit / neplătitor de TVA)
21%prima cotă din casă cu 21%; dacă nu există, bonul e respins

Limite

CâmpLimită
denumiremax. 72 de caractere
departamentmax. 99
unitate de măsurămax. 6 caractere; lipsă = buc
Formatul bonului

Vânzări, retururi, reduceri și plăți

Pentru sintaxa simplificată și FPrint

Linia de vânzare

Fiecare articol e o linie. Valoarea lui este prețul unitar înmulțit cu cantitatea (3,50 lei × 2 buc = 7,00 lei), rotunjită la ban.

S^denumire^preț^cant^UM^TVA^dep
S^Ceai cu miere^350^2000^buc^1^1
S^Branza^4000^350^kg^1^2
2 ceaiuri × 3,50 = 7,00 lei pe cota A; 0,350 kg brânză × 40,00 = 14,00 lei pe cota A, departamentul 2.
CâmpCe scriiExemplu
denumiremax. 72 de caractere, fără ^; diacriticele se transformă automat (ă→a)Ceai cu miere
prețprețul unitar cu TVA, în bani, fără zecimale350 = 3,50 lei
cantîn miimi; negativă = retur (vezi Retur)2000 = 2 buc · 350 = 0,350 kg
UMunitatea de măsură, max. 6 caractere; gol = buckg
TVAcota: 1…5 = A…E1 = cota A
depdepartamentul, 1…99; lipsă = 11
S,1,______,_,__;denumire;preț;cant;dep;1;TVA;0;0;UM
S,1,______,_,__;Ceai cu miere;3.50;2.000;1;1;1;0;0;buc
S,1,______,_,__;Branza;40.00;0.350;2;1;1;0;0;kg
2 ceaiuri × 3,50 = 7,00 lei pe cota A; 0,350 kg brânză × 40,00 = 14,00 lei pe cota A, departamentul 2.
CâmpCe scriiExemplu
denumiremax. 72 de caractere, fără ;; diacriticele se transformă automat (ă→a)Ceai cu miere
prețprețul unitar cu TVA, în lei, cu punct zecimal3.50
cantcu punct zecimal; negativă = retur (vezi Retur)2.000 · 0.350
depdepartamentul, 1…991
1fix
TVA1…5 = A…E, sau procentul (21% = prima cotă din casă cu 21%)1
0;0fixe
UMunitatea de măsură, max. 6 caractere; gol = buckg

Retur (storno)

Un retur e o linie de vânzare cu cantitatea negativă; prețul rămâne pozitiv. Returul scade din bon valoarea lui, pe cota lui.

  • Returul nu poate depăși vânzările de pe aceeași cotă de deasupra lui (după reducerile lor), nici totalul bonului. Egal e permis. Nu poți storna 100 de lei pe cota A dacă pe bon nu sunt vânzări de cel puțin 100 de lei pe cota A, chiar dacă bonul are vânzări pe alte cote.
  • Un retur trimis înaintea vânzării de care are nevoie e mutat automat după ea.
  • Un bon cu totalul zero e permis (ex. schimbul unui produs: returul egal cu vânzarea).
  • O reducere pusă după un retur nu are efect.

Daisy nu suportă storno (vinde pe PLU și nu acceptă un preț negativ). Ca bonul să se poată tipări, Fisco aplică returul ca reducere valorică pe articolele de pe aceeași cotă, împărțită proporțional între ele: pe bon apare REDUCERE -2.00 sub articol, iar denumirea returului nu se tipărește. Totalul, TVA-ul pe cotă și regulile de mai sus sunt aceleași ca pe celelalte case.

Vânzări A 150 lei, retur A 100 lei → 50,00 lei
S^Televizor^15000^1000^buc^1^1
S^Retur cablu^10000^-1000^buc^1^1
P^1^5000
Vânzări A 150 lei, retur A 100 lei → 50,00 lei
S,1,______,_,__;Televizor;150.00;1.000;1;1;1;0;0;buc
S,1,______,_,__;Retur cablu;100.00;-1.000;1;1;1;0;0;buc
T,1,______,_,__;0;50.00;;;;

Merge și comanda VS^denumire^preț^cant^UM^TVA^dep, cu aceleași câmpuri ca S^ și cantitatea pozitivă: e același retur.

Reduceri și majorări

O reducere sau o majorare se aplică liniei de deasupra ei: unui articol, dacă vine imediat după linia lui, sau întregului bon de până atunci, dacă vine după un subtotal.

CeSimplificatFPrint
Reducere procentualăDP^1000 = 10% (în sutimi)C,1,______,_,__;1;10.00;;;;
Reducere valoricăDV^250 = 2,50 lei (în bani)C,1,______,_,__;3;2.50;;;;
Majorare procentualăMP^500 = 5%C,1,______,_,__;0;5.00;;;;
Majorare valoricăMV^100 = 1,00 leuC,1,______,_,__;2;1.00;;;;
SubtotalST^T,1,______,_,__;4;;;;; sau L,1,______,_,__;;;;;;

Pe articol

  • Linia de reducere vine imediat după articol. Procentul se calculează din valoarea articolului și se rotunjește la ban.
  • Pune cel mult o reducere sau majorare pe articol: la a doua, rezultatul diferă de la o casă la alta.
  • Reducerea nu poate depăși valoarea articolului: Discountul (6.00) este mai mare decât valoarea produsului (5.00).
  • Reducerea pusă înaintea primului articol, după un retur sau după plată nu are efect. Bonul se tipărește fără ea, iar dacă ai calculat plata cu reducerea, plata nu mai e egală cu totalul și bonul e respins.

Pe subtotal

  • Se aplică pe tot ce e deasupra subtotalului: articole, reducerile lor, retururi.
  • Procentul se calculează și se rotunjește pe fiecare cotă TVA, ca la casă. Suma poate diferi cu un ban de procentul din total: 10% din A 1,15 + B 1,15 = 0,12 + 0,12 = 0,24, deci totalul e 2,06, nu 2,07.
  • O reducere valorică se împarte pe cote proporțional cu vânzările lor.
  • Poți pune mai multe subtotaluri cu reduceri: fiecare se aplică pe totalul de până la el. A 10 + B 10, −10% → 18,00, apoi −2,00 lei → 16,00.
  • Reducerea nu poate depăși totalul, iar pe un subtotal zero nu se poate aplica nimic.
10% doar la ceai: 10,00 → 9,00; cafeaua rămâne 20,00; total 29,00 lei
S^Ceai^1000^1000^buc^1^1
DP^1000
S^Cafea^2000^1000^buc^1^1
P^1^2900
10% doar la ceai: 10,00 → 9,00; cafeaua rămâne 20,00; total 29,00 lei
S,1,______,_,__;Ceai;10.00;1.000;1;1;1;0;0;buc
C,1,______,_,__;1;10.00;;;;
S,1,______,_,__;Cafea;20.00;1.000;1;1;1;0;0;buc
T,1,______,_,__;0;29.00;;;;

Calculează totalul în program exact ca mai sus (rotunjire la ban pe articol, procentul pe subtotal pe fiecare cotă) și trimite plata cu suma rezultată. O diferență sub 1 leu e corectată automat (vezi Plata); una mai mare respinge bonul.

Plata

Plățile vin după articole, la sfârșitul bonului. Poți pune mai multe, de tipuri diferite.

P^tip^sumă
P^2^900
P^1^0
9,00 lei pe card, diferența în numerar.
CâmpCe scriiExemplu
tiptipul plății, din tabelul de mai jos2 = card
sumăîn bani, fără zecimale; 0 = suma rămasă de plată900 = 9,00 lei
Tip platăPlată
1numerar
2card
3credit
4tichete de masă
5tichete valorice
6voucher
7plată modernă
8, 9alte
T,1,______,_,__;tip;sumă;;;;
T,1,______,_,__;1;9.00;;;;
T,1,______,_,__;0;;;;;
9,00 lei pe card, diferența în numerar.
CâmpCe scriiExemplu
tiptipul plății, din tabelul de mai jos1 = card
sumăîn lei, cu punct zecimal; goală = suma rămasă de plată (la tipul 4, goală = subtotal)9.00
Tip platăPlată
0numerar
1card
2credit
3tichete de masă
4tichete valorice
5voucher
6plată modernă
8alte

Tipul 4 (tichete valorice) are nevoie de sumă: T,1,______,_,__;4;20.00;;;;. Fără sumă, T,1,______,_,__;4;;;;; e subtotalul (vezi Reduceri și majorări), nu o plată. Ca să încasezi restul bonului în tichete valorice, calculează suma și trimite-o explicit.

  • Plățile trebuie să facă exact totalul bonului; altfel bonul e respins: Suma produselor este 19.00 dar suma de plată este 10.00.
  • Diferențe mici. Dacă plățile diferă de total cu mai puțin de 1 leu, Fisco corectează plata (de preferat pe numerar), ca bonul să se tipărească; o diferență mai mare respinge bonul. Corecția se face doar dacă e bifată „Corectează automat totaluri incorecte cu diferență mai mică de 1 leu” în setările driverului. Din experiență, diferențele vin din reduceri și din prețuri ținute în program fără TVA: casa tipărește prețul cu TVA rotunjit la ban, pe când programul de vânzare îl poate calcula cu trei sau mai multe zecimale.
  • Restul se dă doar când bonul e plătit numai în numerar. La un total de 19,00: numerar 50,00 → rest 31,00; numerar 19,50 → rest 0,50. Dacă pe bon e și altă plată (card, tichete…), nu se dă rest: numerarul trebuie să fie exact diferența (card 9,00 + numerar 10,00), iar card 9,00 + numerar 20,00 e respins.
  • Cel mult o plată poate fi cu suma 0fără sumă: ea primește suma rămasă de plată. Două astfel de plăți resping bonul.
  • Fără nicio plată, tot totalul se încasează în numerar.
  • După plată nu mai poți adăuga articole; o reducere pusă după plată nu are efect.
Tot pe card: 19,00 lei
S^Cafea^950^2000^buc^1^1
P^2^1900
Tot pe card: 19,00 lei
S,1,______,_,__;Cafea;9.50;2.000;1;1;1;0;0;buc
T,1,______,_,__;1;19.00;;;;
Formatul bonului

Text formatat și coduri de bare

Pentru sintaxa simplificată și FPrint (nu pentru Fisco JSON)

Se pot pune în bonuri scrise cu sintaxa simplificată sau FPrint. Nu modifică totalul.

ComandăFormatExemplu
Text formatat54,text^bold^italic^dublu^subliniat^aliniere^54,Multumim^1^^1^^1^ bold, dublu, centrat
Text pe bon nefiscal42,text^bold^italic^dublu^subliniat^aliniere^42,Masa 20^1^^^^1^
Cod de bare / QR84,tip^date^mărime QR^84,4^https://exemplu.ro^7^
Cod de bare / QR, formă scurtăCB^date^tipCB^5940000000820^2 EAN13

La text, câmpurile de format sunt 1 (da) sau gol (nu), iar alinierea e 0 stânga, 1 centru, 2 dreapta. Formatarea textului se aplică doar pe Datecs. Pe Daisy și Tremol se tipărește textul, fără formatare. Fisco alege singur bonul: un fișier care are doar linii de text (54,, 42,) devine bon nefiscal, iar împreună cu articole ambele se tipăresc pe bonul fiscal.

Tipuri: 1 EAN8 (8 cifre), 2 EAN13 (13 cifre), 3 Code128 (3–31 caractere), 4 QR (3–279 caractere, mărime 3–10, implicit 5), 5 Interleaved 2 of 5 (3–22 cifre).

Ambele forme (84, și CB^) merg în ambele sintaxe, pe bon fiscal sau nefiscal. Un cod greșit (tip necunoscut, lungime sau caractere greșite) e respins pe orice casă, înainte de tipărire. Un cod corect pe care casa nu îl poate tipări nu blochează bonul: în locul lui se tipăresc datele, ca text.

CasăCod de bareCa text
Datecstoate tipurile–
TremolEAN8, EAN13, Interleaved 2 of 5 cu număr par de cifre (până la 18)Code128, QR, Interleaved 2 of 5 cu număr impar de cifre sau peste 18
Daisy–toate tipurile
Cum trimiți bonul

Prin fișiere

Pentru sintaxa simplificată și FPrint (nu pentru Fisco JSON)

Programul scrie un fișier text în folderul scanat, iar Fisco îl preia, îl tipărește și mută rezultatul în subfoldere.

Folderul scanat implicit este <director instalare>\Bonuri, de exemplu C:\Fisco\Bonuri. Se schimbă din Setări driver, unde se aleg și extensiile acceptate (implicit *.bon, *.inp, *.txt).

C:\Fisco\Bonuri\bon_154.inp
S^Cafea^950^2000^buc^1^1
S^Apa plata^500^1000^buc^2^1
P^2^2400
Bon fiscal: 2 cafele × 9,50 lei pe cota A și o apă de 5,00 lei pe cota B, plătit cu cardul (24,00 lei).
C:\Fisco\Bonuri\bon_154.inp
S,1,______,_,__;Cafea;9.50;2.000;1;1;1;0;0;buc
S,1,______,_,__;Apa plata;5.00;1.000;1;1;2;0;0;buc
T,1,______,_,__;1;24.00;;;;
Bon fiscal: 2 cafele × 9,50 lei pe cota A și o apă de 5,00 lei pe cota B, plătit cu cardul (24,00 lei).

Fișierul poate fi UTF-8 (cu sau fără BOM) sau ANSI (Windows-1250).

Înainte de fiecare fișier, Fisco verifică starea casei: conexiunea, hârtia, memoria, raportul Z din ultimele 24 de ore. Dacă ceva nu e în regulă, fișierul rămâne în folder, driverul afișează problema și reia tipărirea după ce problema e rezolvată.

Rezultatul procesării

BonOK\
copia fișierelor tipărite
BonANSWER\
răspunsul pentru operațiile reușite (bon tipărit, raport, totaluri), cu același nume
BonERR\
fișierul cu eroare; explicațiile încep cu #

Faptul că fișierul a dispărut din folder nu înseamnă că s-a tipărit. Caută fișierul cu același nume în BonANSWER (reușit; la un bon, tipărit) sau în BonERR (eroare).

BonANSWER\bon_154.inp
[Answer]
SlipNumber=1959
nZrep=42
nFNum=200
DeviceSerial=DB4100000055
Bonul s-a tipărit: numărul documentului (SlipNumber), Z-ul în care intră, numărul bonului în Z și seria casei.
CâmpCe este
SlipNumbernumărul general al documentului în jurnalul electronic
nZrepraportul Z în care se va regăsi bonul
nFNumnumărul bonului fiscal în cadrul Z-ului
DeviceSerialseria casei de marcat

Totalurile zilei, fără raport X 1.4

Un fișier cu o singură linie, TOTALURI^, cere totalurile zilei curente (de la ultimul Z) pe tipuri de plată. Linia e aceeași în sintaxa simplificată și în FPrint. Fisco doar citește totalurile din casă: nu se tipărește nimic și nu se modifică nimic. Dacă linia e împreună cu alte comenzi sau are ceva după ^, fișierul ajunge în BonERR.

C:\Fisco\Bonuri\totaluri.inp
TOTALURI^
Cere totalurile zilei, fără să tipărească nimic.
BonANSWER\totaluri.inp
[Answer]
CommandName=daily_totals
nZrep=146
Cash=1350.00
PayCash=1200.00
PayCard=1150.50
PayCredit=0.00
PayMealTicket=0.00
PayGiftTicket=0.00
PayVoucher=100.00
PayModern=0.00
PayOther=0.00
TotalSales=2450.50
DeviceSerial=DB4100000055
Totalurile zilei de la ultimul Z: numerarul din casă (Cash), încasările pe tipuri de plată și vânzările.

Denumirile totalurilor în fiecare format:

Ce esteAPI /daily-totalsBonANSWERRomână: Raspuns\
numerarpayments.cashPayCashNUMERAR
cardpayments.cardPayCardCARD
creditpayments.creditPayCreditCREDIT
tichete de masăpayments.meal_ticketPayMealTicketTICHETE_MASA
tichete valoricepayments.gift_ticketPayGiftTicketTICHETE_VALORICE
voucherpayments.voucherPayVoucherVOUCHER
plată modernăpayments.modernPayModernPLATA_MODERNA
alte metodepayments.otherPayOtherALTE_METODE
vânzările pe cotele TVAtotal_salesTotalSalesTOTAL_VANZARI
numerarul din casă (sold)cash_drawerCashSOLD_NUMERAR
Z-ul care va închide sumelez_numbernZrepNRZ
tipul răspunsului–CommandName=daily_totalsBONOK=1

În fișiere sumele sunt în lei, cu două zecimale; în API, în bani. După un raport Z, toate totalurile, inclusiv numerarul din casă, pornesc de la zero. Pentru totalurile unui Z, citește răspunsul la raportul Z: are aceleași câmpuri.

Sertarul de bani 1.4

Linia DS^ deschide sertarul de bani, în ambele sintaxe.

  • Singură în fișier: deschide sertarul, fără să tipărească nimic.
  • Împreună cu un bon: poate fi oriunde în fișier.
  • Dacă sertarul nu se deschide, bonul e tipărit oricum și apare în BonANSWER: nu îl retrimite.
C:\Fisco\Bonuri\bon_156.inp
S^Ceai cu miere^350^1000^buc^1^1
P^1^500
DS^
Bon de 3,50 lei plătit cu 5,00 lei numerar (rest 1,50), apoi se deschide sertarul.
C:\Fisco\Bonuri\bon_156.inp
S,1,______,_,__;Ceai cu miere;3.50;1.000;1;1;1;0;0;buc
T,1,______,_,__;0;5.00;;;;
DS^
Bon de 3,50 lei plătit cu 5,00 lei numerar (rest 1,50), apoi se deschide sertarul.

Recomandări

Nume unice

Folosește numărul comenzii sau data cu milisecunde: bon_20261020_154512_031.inp. Nu suprascrie un fișier existent.

Scrie, apoi redenumește

Scrie bon_154.tmp și redenumește-l în .inp doar după ce e complet, ca Fisco să nu citească un fișier pe jumătate.

Salvează răspunsul

Păstrează SlipNumber, nZrep și seria casei lângă comanda din programul tău.

Cum trimiți bonul

Prin API HTTP

Comun pentru toate sintaxele

Fisco pornește un server HTTP local. Trimiți bonul cu POST; cu ?wait= primești rezultatul tipăririi în același răspuns.

Adresa de bază
http://127.0.0.1:4040/api/v1
Setare (settings.ini, [General])ImplicitDescriere
HttpApiEnabled10 oprește serverul
HttpApiHost127.0.0.1adresa pe care ascultă; las-o pe local
HttpApiPort4040portul

Din browser: răspunsurile au Access-Control-Allow-Origin: * și Access-Control-Allow-Private-Network: true, deci o pagină web poate apela API-ul direct din JavaScript.

Specificația OpenAPI 3 e la GET /api/v1/openapi.json. O poți importa în Postman, Insomnia sau într-un generator de clienți.

Flux recomandat

Adaugă ?wait=30: răspunsul vine când bonul s-a tipărit sau a eșuat, cel mult 30 de secunde.

pseudocod
r = POST /api/v1/print?wait=30   { bonul }

if !r.ok                          → respins, nu a intrat în coadă: arată r.error.message
else if r.status == "printed"     → salvează r.result.SlipNumber
else if r.status == "failed"      → arată r.error.message; bonul NU e tipărit
else                              → "queued" / "processing": nu s-a terminat în 30 s;
                                    păstrează r.job_id și întreabă /status?job_id=…
Trimite bonul și așteaptă cel mult 30 de secunde rezultatul.

ok e false doar când cererea e respinsă (400, 409, 503…) și bonul nu intră în coadă. Un bon refuzat la tipărire are ok: true și status: "failed". Expirarea așteptării nu anulează bonul: el rămâne în coadă și se tipărește.

Răspuns pierdut

Dacă răspunsul HTTP se pierde (rețea, timeout), nu știi dacă bonul a intrat în coadă, iar o cerere retrimisă ar putea tipări bonul de două ori. Pune în corp un idempotency_key unic pentru fiecare bon (un UUID sau numărul comenzii cu data, max. 128 de caractere) și retrimite cererea cu aceeași cheie: în 24 de ore, aceeași cheie nu mai tipărește, ci întoarce jobul existent, cu starea lui ("duplicate": true). Aceeași cheie cu alt bon primește 409 IDEMPOTENCY_KEY_REUSED.

POST /api/v1/print?wait=30
{ "syntax": "fisco", "idempotency_key": "comanda-2026-10-24-0042",
  "receipt": { "items": [{ "name": "Paine", "price": 250, "vat": "A" }] } }
Bonul comenzii 42; trimis din nou cu aceeași cheie, nu se tipărește a doua oară.

Joburile se pot întreba cu /status?job_id=… cât timp fișierele lor sunt în BonOK / BonERR; fără job_id, /status?limit=10 dă ultimele joburi.

statusÎnseamnă
queuedîn coadă, încă netrimis la casă
processingcasa a terminat; rezultatul vine imediat
printedtipărit; result conține răspunsul casei
failederoare; error.message spune de ce
not_foundjob necunoscut (HTTP 404)

Verificare înainte de coadă. Un bon greșit (de exemplu o cotă TVA inexistentă sau, în Fisco JSON, un preț cu zecimale) e respins pe loc cu 400 CONVERSION_ERROR și un mesaj care spune câmpul (Fisco JSON: items[1]: price must be an integer >= 0, in bani) sau linia (simplificată și FPrint: Linia 2 | …). Erorile de sume (plățile diferite de total, o reducere mai mare decât articolul) nu au un câmp anume: mesajul spune sumele, de exemplu Suma produselor este 19.00 dar suma de plată este 29.00. Dacă procesarea e oprită sau casa e în eroare, primești 409 PRINTER_NOT_READY cu motivul.

Referință

Exemple de cod

Doar pentru Fisco JSON

Un bon cu 2 cafele, plătit cu cardul, trimis prin API cu așteptarea rezultatului.

bash
curl -X POST "http://127.0.0.1:4040/api/v1/print?wait=30" \
  -H "Content-Type: application/json" \
  -d '{"syntax":"fisco","receipt":{"items":[{"name":"Cafea","price":950,"quantity":2000,"vat":"A"}],"payments":[{"type":"card","amount":1900}]}}'
Trimite bonul (2 cafele, 19,00 lei cu cardul) și așteaptă cel mult 30 de secunde rezultatul.
Referință

Endpoint-uri API

Comun pentru toate sintaxele

Toate căile pornesc de la http://127.0.0.1:4040. Fiecare răspuns are ok.

POST/api/v1/printtrimite un bon

Corpul folosește una dintre sintaxe. ?wait=N (0–60 s) așteaptă tipărirea. idempotency_key (opțional) împiedică tipărirea de două ori a unei cereri retrimise (vezi Răspuns pierdut).

fprint / simplu
{ "syntax": "simplu", "commands": ["S^Paine^250^1000^buc^1^1", "P^1^250"] }
O pâine de 2,50 lei, plătită în numerar, în sintaxa simplificată.
GET/api/v1/statusstarea unui job sau ultimele joburi

?job_id=… (acceptă și &wait=N) sau, fără job, ultimele joburi: ?limit=10 (1–100).

GET/api/v1/healthpoate primi bonuri?
200
{ "ok": true, "server": "running", "printer": { "ready": false, "status": "not_ready", "error": "Lipsa hartie" } }
Serverul merge, dar casa nu poate primi bonuri acum: lipsește hârtia.
GET/api/v1/last-receiptultimul job terminat

Tipărit sau eșuat; 404 LAST_RECEIPT_NOT_FOUND dacă nu există.

POST/api/v1/reportraport X sau Z 1.1

{ "type": "x" } sau "z". Trece prin coadă, acceptă ?wait=N. ⚠️ Z închide ziua fiscală.

În result, toate ca text:

  • SlipNumber, nZrep, nRep: numerele documentului și ale raportului. nRep la Daisy e ultima înregistrare din memoria fiscală (la X, ultimul Z închis; la Z, Z-ul nou); la celelalte case e egal cu nZrep.
  • PayCash…PayOther, TotalSales 1.4: încasările și vânzările zilei, citite chiar înainte de raport, în lei ("47.00"); la un Z, sumele închise de el.
  • doar la Daisy, TotEXEPTAT, TaxA…TaxD: sumele pe cote, 12 cifre în bani ("000000006050" = 60,50 lei).
POST/api/v1/drawerdeschide sertarul de bani 1.4

Deschide sertarul de bani: trece prin coadă și acceptă ?wait=N. Corpul e opțional.

opțional
{ "pulse_duration_ms": 200 }
Durata impulsului trimis sertarului, în milisecunde (implicit 200).

pulse_duration_ms (opțional) e durata impulsului trimis sertarului, în milisecunde, între 5 și 1000. Implicit e 200. La Tremol durata o stabilește casa, iar valoarea e ignorată.

GET/api/v1/daily-totalstotalurile zilei pe tipuri de plată, fără tipărire 1.4

Ziua curentă, de la ultimul Z, citită din casă fără raport X. Sumele sunt în bani. z_number e Z-ul care va închide sumele.

200
{ "ok": true, "z_number": 146, "total_sales": 245050,
  "payments": { "cash": 120000, "card": 115050, "credit": 0, "meal_ticket": 0,
                "gift_ticket": 0, "voucher": 10000, "modern": 0, "other": 0 },
  "cash_drawer": 135000 }
În bani: vânzări 2450,50 lei, din care numerar 1200,00, card 1150,50 și voucher 100,00; în casă sunt 1350,00 lei.

cash_drawer e numerarul din casă, cu depunerile și retragerile. O casă care nu poate citi totalurile răspunde cu 501 NOT_SUPPORTED.

GET POST/api/v1/cashnumerar în casă / depunere, retragere 1.1

GET → { "cash": 152050 } (1520,50 lei). POST → { "operation": "in" | "out", "amount": 10000 }. În result, după operație: Cash (în lei), CashIn / CashOut: depunerile și retragerile de numerar ale zilei.

GET/api/v1/devicemodel, serie, CIF, ultimul bon 1.1

Câmpul last (receipt_number, document_number, z_number) se citește direct din casă.

GET/api/v1/device/statushârtie, conexiune, erori 1.1

Nu trimite comenzi la casă, poate fi apelat des. error_kind: no_paper, no_connection, port_busy, port_missing, wrong_mode, other.

GET/api/v1/vat-ratescotele TVA din casă 1.1

{ "vat": { "A": 21, "B": 11, "C": 5, "D": 0, "E": 0, "F": 100.01 } } (o casă Datecs). Valorile de 100 sau peste apar doar la Datecs: 100 = scutit, 100.01 = neimpozabil (alte taxe), 100.02 = cotă dezactivată. Tremol și Daisy dau doar procente. Daisy are doar cotele A–D (E și F sunt mereu 0); cota E (5) din bon e grupa de scutite a casei.

GET/api/v1/receipt-copytextul unui bon din jurnal 1.1

?job_id=… sau ?document=N. Nu tipărește nimic; întoarce textul și tipul (fiscal, fiscal_cif, nonfiscal, cash, z_report).

GET POST/api/v1/processing[/start|/stop]pornește / oprește procesarea 1.1

Ca butonul din fereastra driverului. processing: started, stopping, stopped.

GET/api/v1/version · /api/v1/openapi.jsonversiuni, specificație 1.1

{ "api_version": "1.4", "driver_version": "2.3.0.15" }

Referință

Erori

Comun pentru toate sintaxele

cerere respinsă
{ "ok": false, "error": { "code": "CONVERSION_ERROR", "message": "items[0]: price must be an integer >= 0, in bani (250 = 2.50 lei)" } }

Un bon refuzat la tipărire nu e o cerere respinsă: răspunsul are ok: true, status: "failed" și error.code = PRINT_FAILED, cu mesajul casei.

HTTPcodeCe faci
400CONVERSION_ERRORcorectează bonul; mesajul spune câmpul sau linia
400EMPTY_BODY, INVALID_JSONtrimite un obiect JSON valid
409PRINTER_NOT_READYarată motivul casierului (hârtie, Z depășit, procesare oprită)
409IDEMPOTENCY_KEY_REUSEDidempotency_key a fost folosit în ultimele 24 de ore pentru alt bon
404JOB_NOT_FOUND, LAST_RECEIPT_NOT_FOUND, DOCUMENT_NOT_FOUNDjobul / documentul nu există
503PRINTER_BUSY, APP_BUSYreîncearcă peste câteva secunde
502DEVICE_ERRORcasa a răspuns cu eroare la o citire
500QUEUE_ERROR, SETTINGS_ERRORverifică folderul scanat din setări
—PRINT_FAILEDîn status: "failed": casa a refuzat bonul; mesajul e al casei
Referință

POS bancar 1.2

Comun pentru toate sintaxele

Încasezi cu cardul pe terminalul bancar legat de calculator, apoi trimiți bonul cu plata card. Necesită licența Fisco POSBancar (14 zile de probă).

POST /api/v1/card/sale
{ "terminal": 1, "amount": 2400 }
Încasează 24,00 lei pe terminalul 1.
200 · după ce clientul a terminat cu cardul
{ "ok": true, "approved": true, "amount": 2400, "auth_code": "C1HH0Z",
  "rrn": "412138851873", "card_number": "454793XXXXXX0683", "text": "…" }
Plata a fost aprobată: codul de autorizare, RRN-ul și cardul mascat.

Răspunsul poate întârzia câteva minute: setează timeout-ul clientului HTTP la cel puțin 6 minute. Dacă răspunsul se pierde, verifică plata pe POS sau în Fisco înainte să încerci din nou. approved: false vine tot cu HTTP 200 și motivul în message.

GET /api/v1/card/terminals listează terminalele configurate. Programele care apelau FiscoCard pe portul 40123 (?operation=sale&value=1050) merg fără schimbări.

Referință

Istoric versiuni

Comun pentru toate sintaxele

APICe s-a schimbat
1.4daily-totals: totalurile zilei pe tipuri de plată, fără tipărire; aceleași totaluri la report și în fișiere (TOTALURI^, rapoarte X / Z); drawer și linia DS^: deschiderea sertarului, în ambele sintaxe. Reparat: nRep / TaxA… la rapoartele trimise prin API și Cash la POST /cash lipseau din result
1.3print: idempotency_key opțional (bonul retrimis cu aceeași cheie nu se tipărește din nou)
1.2POS-uri bancare: card/terminals, card/sale
1.1sintaxa fisco (JSON); ?wait=N; version, openapi.json, device, device/status, vat-rates, cash, report, receipt-copy, processing
1.0health, print (fprint, simplu), status, last-receipt

Ai nevoie de ajutor la integrare? Contactează-ne →