ELV LPFR — ESIR integration guide
Who it is for: developers and technicians of ESIR software (fiscal cash registers) who bought an ELV LPFR licence and are connecting their ESIR to it.
Product: ELV LPFR, verzija 2 · Tax Administration (PURS) accreditation #1698 · manufacturer code 8S-0002 · manufacturer ELV d.o.o.
Support: [email protected]
Web version: https://allurepos.com/lpfr-api.en.html
In short
- ELV LPFR is a Windows program. It runs on the computer that has the reader with the Secure Element card.
- The ESIR sends it requests over HTTP, at
http://localhost:8888/api/v3. - After every start the card is locked. The ESIR or the operator must enter the PIN.
- An invoice is signed with
POST /api/v3/invoices. The answer contains the invoice number, the journal, the QR code and the signature. - The ESIR prints the journal and the QR code and stores the whole answer.
- Send every invoice with a
RequestIdheader. If the answer is lost, fetch the invoice withGET /api/v3/invoices/{RequestId}. Do not resend it blindly. - Read the device state from
GET /api/v3/status(fieldsgscandmssc).
1. What you need
| What | Details |
|---|---|
| A Windows computer | On the taxpayer's premises. ELV LPFR runs on Windows only (tested with a Gemalto USB reader). Linux and macOS are not supported. Nothing is installed: the whole service is one program, ELV-LPFR.exe. |
| Smart-card reader (PC/SC) | Any PC/SC reader. The built-in Windows "Smart Card" service is enough. No special driver is needed. |
| Secure Element (SE) card | Issued by the Tax Administration. For development and testing: a test (sandbox) card. For the taxpayer's real work: a production card. |
| Card PIN | Exactly four digits. Entered after every start. |
| Licence activation code | 16 characters in four groups of four (format: K7QM-2XRA-9PDT-4HW8). It arrives by e-mail and is listed in "Moje licence". 1 code = 1 card = 12 months from activation. A code works only for cards of the PIB it was bought for. A test card needs no licence. |
| The licence follows the card | The licence is bound to the card (JID and PIB), not to the computer. If you move the card to another computer (run ELV-LPFR-Setup.exe there and move the data folder C:\ProgramData\ELV LPFR\ too, with ELV LPFR stopped on the old computer), the licence stays valid. One card cannot work on two computers at the same time, because it physically exists once. |
| Program package | "Moje licence" (https://allurepos.com/lpfr.html) offers the „Produkcija" package (production; pre-configured for the live SUF environment, you change nothing). The package shows its SHA-256 fingerprint. The test package for a test card (sandbox, the package reviewed by the Tax Administration) is sent by support on request: [email protected]. |
| Access to "Moje licence" | Log in with the e-mail address the licence was bought with. A login code (6 digits) is sent to that address. If the e-mail with the activation codes did not arrive, check your spam folder, then write to support. |
| Internet | To send data to the Tax Administration (SUF), to fetch tax rates, and for the licence (https://licenca.allurepos.com, port 443). Invoices are issued without internet too. The first start, however, must fetch the tax rates from SUF. |
| Windows user account | ELV LPFR runs in the logged-in user's session, not as a Windows service. Activating a code and enabling network mode need Administrator approval (UAC). |
| Correct clock | The computer clock must be synchronised with a time server. If the clock is more than 5 minutes ahead of the correct time, signing is refused. |
| Disk space | About 21.6 KB per invoice. Below 100 MB of free space no new invoices are issued. |
2. Installation in 5 minutes
Choose the right package:
- for a production card download the „Produkcija" package in "Moje licence";
- for a test card ask support for the test package: [email protected].
Never run the test package (from support) with a production card, and never run the „Produkcija" package with a test card. ELV LPFR refuses an environment mismatch (
mssc8215) only between its own settings. It does not compare the card with the package. Choosing the package is therefore your job.Optionally check the fingerprint of the downloaded file and compare it with the value in "Moje licence":
certutil -hashfile <downloaded-package>.zip SHA256Unzip the whole ZIP into any folder, for example
Downloads. Do not run the program from inside the ZIP. This folder is only for the installation: afterwards the program and its data live in the permanent places from step 6. Important: on a first installation the Setup takes its settings, among them the SUF address (production or test), from the.envfile that sits in the same folder asELV-LPFR-Setup.exe. So run the Setup from the unzipped folder as it is and do not moveELV-LPFR-Setup.exeaway from its.env. Without that.env(the Setup started from inside the ZIP without extracting it, or copied on its own) the Setup refuses the first installation and installs nothing. An existing installation keeps its own settings on an update.Insert the card into the reader.
Double-click
ELV-LPFR-Setup.exe. Windows asks you to confirm as Administrator: confirm. This is the only prompt of this kind during the installation. Do not close the Setup window until it has finished.Windows SmartScreen may show "Windows protected your PC" once (Serbian: „Windows je zaštitio vaš računar"). Click "More info", then "Run anyway". This is needed once per computer.
The installation finishes in a few seconds. The program and its settings (
.env) are placed inC:\Program Files\ELV LPFR\, and the data (databaselpfr.sqlite, licence) inC:\ProgramData\ELV LPFR\. ELV LPFR starts by itself, without a window, every time a user logs on to Windows, and the operator page opens. Every step is written toC:\ProgramData\ELV LPFR\instalacija.log(send it to support if something goes wrong). The Setup also prints the lineSUF: … (PRODUKCIJA / production),SUF: … (TEST / sandbox)orSUF: … (nepoznato / unknown), andSUF: (nije podesen / not set)when no SUF address is set. You can also see that the environment is the right one (test or production) in thestatusanswer below: with the „Produkcija" package the"taxCoreApi"field does not containsandbox, with the test package (from support) it ishttps://api.sandbox.suf.purs.gov.rs.The operator page
http://localhost:8888/opens by itself in the browser. The top says "Enter the card PIN" („Unesite PIN kartice"). Type the PIN and click "Unlock the card" („Otključaj karticu").What you should see: the page announces "Windows will then ask for the same PIN once more."
Right after that, Windows opens its own "Smart Card" window and asks for the same PIN once more. Enter it and confirm. Without this, invoices are issued but the data does not reach the Tax Administration. If you do not see the window, check the taskbar.
What you should see: the notification „Konfiguracija preuzeta sa SUF-a: …" (configuration fetched from SUF) and, at the top, "Ready to issue invoices" („Spremno za izdavanje računa").
Licence: on the operator page open the "Licence" („Licenca") section → "Activation code from the seller" („Aktivacioni kod od prodavca"). Type the code, click "Activate" („Aktiviraj") and confirm the Windows Administrator prompt. Internet is required. With a test card the licence state is "Not required" („Nije potrebna") and you skip this step.
Automatic start is already switched on by the installation. After ELV LPFR (or the computer) is restarted, enter the PIN again (steps 7 and 8). If needed, open the operator page by hand:
http://localhost:8888/. After the installation do not usepokreni.cmd,autostart-ukljuci.cmd,autostart-iskljuci.cmdorELV-LPFR.exefrom the ZIP folder or from an old folder: ELV LPFR starts by itself fromC:\Program Files\ELV LPFR\.
Special cases of the installation:
- Update: unzip the new package and run the new
ELV-LPFR-Setup.exe. ELV LPFR is stopped in order (the receipt in progress is finished), the previous program is kept inC:\Program Files\ELV LPFR\prethodna-verzija\, the program is replaced, and data, licence and settings (.env, network and ESIR settings) stay; automatic start stays with the same Windows user. If ELV LPFR cannot be stopped, if another ELV LPFR window is open, or if a newer version than the Setup's is installed, nothing is changed and the Setup says why. If copying fails, the previous version is put back. - An earlier installation from the ZIP (0.8.2–0.8.7): the Setup finds it. That folder stays the data folder (nothing is moved or deleted), and the program then runs from
C:\Program Files\ELV LPFR\. That folder now holds ELV LPFR's fiscal data (lpfr.sqlite, licence): never delete or move it, not even when it is inDownloadsor on the desktop. Once the adoption has finished, do not run anything from that folder any more: notpokreni.cmd,autostart-ukljuci.cmd,autostart-iskljuci.cmdorELV-LPFR.exe. The oldautostart-iskljuci.cmd(0.8.2–0.8.7) deletes the „ELV LPFR“ task the Setup created, so ELV LPFR would not start after the next logon. If more than one such folder exists, the Setup stops and asks you to contact support ([email protected]). - Guard against a second installation: after the installation, an
ELV-LPFR.exe0.8.8 or newer started from any other folder does not run (exit code 5) and says where ELV LPFR is installed. So no second installation without data and licence can appear. An oldELV-LPFR.exe(0.8.2–0.8.7) in the folder the Setup took over has no such check: do not start it.autostart-ukljuci.cmdandautostart-iskljuci.cmdfrom the 0.8.8 package (the new ZIP) do not change the automatic start of the installed ELV LPFR. Only the 0.8.8 copies have this check: the old ones (0.8.2–0.8.7) do not, and the oldautostart-iskljuci.cmddeletes the task of the installed ELV LPFR. So nothing from an old folder is run. - A computer with the AllurePOS till: the Setup is not needed and installs nothing (the till has its own ELV LPFR).
When everything is fine, the operator page shows:
- at the top: "Ready to issue invoices" („Spremno za izdavanje računa");
- in the "Licence" section: state "Valid" („Važeća") and a "Valid until" date (with a test card: "Not required");
- in the "Device" („Uređaj") panel: "ESIR access" = "This computer only" („Samo ovaj računar"), unless you enabled network mode (chapters 3.2 and 3.6);
- a notification that tax rates and the verification address were fetched from SUF.
Check from the command line. On Windows always type curl.exe, not curl: in PowerShell curl is a different program that does not show the response body when an error comes back. On a new installation the first /status can take up to about 30 seconds (it waits for SUF data), hence --max-time 60.
curl.exe -i http://localhost:8888/api/v3/attention
curl.exe http://localhost:8888/api/v3/device-info
curl.exe --max-time 60 http://localhost:8888/api/v3/statusWhat you should see:
attention:HTTP/1.1 200 OK, no response body.device-info:"manufacturerCode":"8S-0002","softwareVersion":"verzija 2","productName":"ELV LPFR".status:"gsc":["0100"],"mssc":[]. With the „Produkcija" package the"taxCoreApi"field does not containsandbox.
2.1 How to edit .env
Some settings (port, reader, network mode) live in the .env file.
- The
.envfile is next to the program:C:\Program Files\ELV LPFR\.env(also for an earlier installation from the ZIP that the Setup took over; the.envin the old folder is no longer read). It already contains every line this guide mentions (PORT=8888,PCSC_READER_NAME=,LPFR_LISTEN=,ESIR_TOKEN=, and from package build 0.8.6 alsoLPFR_LAN_TRUST=). Some are empty. - Open it in Notepad started as Administrator (Windows protects the
Program Filesfolder; otherwise the change cannot be saved). - Type the value after the
=sign on the existing line. Do not add the same line a second time. - Save the file as UTF-8.
- Restart ELV LPFR (2.2). Values are read only at start-up.
Do not change any other line. The package is already configured for its environment.
2.2 Stopping and restarting
- In Task Manager find
ELV-LPFR.exeand end the task. Do this when no invoice is being issued. Then log off and on to Windows (ELV LPFR starts by itself). - After every start, enter the PIN again.
- Never delete the data folders.
2.3 A new program version
- Run the new
ELV-LPFR-Setup.exe(described in the "Special cases of the installation" part of this chapter, item "Update" / „Ažuriranje“). Do not copy files over the installation by hand. - Your data (
.env,lpfr.sqlite, thelicenca\folder) stays in place and must not be lost. - If something goes wrong, send
C:\ProgramData\ELV LPFR\instalacija.logto support ([email protected]).
3. Connecting the ESIR
ELV LPFR has three ESIR access modes. The current mode is shown on the operator page, "Device" („Uređaj") panel → "ESIR access" („Pristup za ESIR").
| Mode | Who may send requests | X-ESIR-Token | Chapter |
|---|---|---|---|
| "This computer only" („Samo ovaj računar", default) | Only programs on the ELV LPFR computer (127.0.0.1, ::1) | no | 3.1 |
| "Network (LAN)" („Mreža (LAN)") | Other computers on the network too | yes, for every request from another computer | 3.2 |
| "This computer's local network (no token)" („Lokalna mreža ovog računara (bez tokena)") | Devices in the same private subnet as this computer too, for example a phone with the „ESIR Poreska uprava RS" app | not from that subnet; yes for everyone else | 3.6 |
- For a phone or tablet with the Tax Administration's app there is one button: "Connect a phone or tablet (PURS ESIR app)" („Poveži telefon ili tablet (ESIR Poreske uprave)", 3.6). The button "Turn off network access (Administrator)" goes back to "This computer only".
- The token mode is under "Advanced: ESIR with a token" („Napredno: ESIR sa tokenom"), buttons "Allow ESIRs from the network (Administrator)" and "This computer only (Administrator)" (3.2).
- Every change asks for Windows Administrator approval (UAC) and takes effect at once, without a restart. If it cannot (for example when another program holds the port), the setting is saved and the page says "The change takes effect after ELV LPFR is restarted." („Promena važi posle ponovnog pokretanja ELV LPFR-a.") Then restart ELV LPFR (2.2).
- The same Administrator step also creates the Windows firewall rule „ELV LPFR (ESIR)": inbound TCP on the ELV LPFR port, for all network profiles. In the no-token mode the rule covers only the local subnet; in "Network (LAN)" mode it covers any address. Switching back to "This computer only" removes the rule.
- When the mode is set in
.env(LPFR_LISTEN), the page does not change it. It says: "The mode is set in .env (LPFR_LISTEN) and is changed there, not on this page." - The package build is shown in "Moje licence" ("Package build"). The single button and the change without a restart exist from build 0.8.7. Build 0.8.6 has the third mode and the firewall rule, but with separate buttons and a restart after every change. Older packages know only the first two modes.
3.1 ESIR on the same computer (default)
The base address is http://localhost:8888/api/v3 (or http://127.0.0.1:8888/api/v3). No token is needed. Nothing to configure.
- In the default mode ELV LPFR listens only on
127.0.0.1and::1. - A request to the computer's network address (e.g.
http://192.168.1.20:8888), even from the same computer, therefore gets no HTTP answer at all: the connection is refused. No token is checked at that point. The token rule applies only in network mode (3.2 and 3.6). - A request to any other name that points to
127.0.0.1gets HTTP 403. This protects against web pages that pose as a local program. Allowed arelocalhost,127.0.0.1and the computer name. - The port is changed in
.env(PORT, chapter 2.1). The operator page address then changes too.
3.2 ESIR on another computer (network mode, LAN) [ELV]
By default ELV LPFR accepts requests only from the computer it runs on. Connect an ESIR that cannot send a token (for example the „ESIR Poreska uprava RS" app on a phone) as described in chapter 3.6. For an ESIR on another computer:
- Enable network mode, in one of two ways:
- on the operator page, "Device" panel → "Advanced: ESIR with a token" → "Allow ESIRs from the network (Administrator)" („Dozvoli ESIR-e sa mreže (Administrator)"), then confirm the Windows Administrator prompt. ELV LPFR creates the token and the firewall rule itself (step 5). Up to build 0.8.6 the button is directly in the "Device" panel.
- or fill in
LPFR_LISTEN=lanandESIR_TOKEN=<at least 16 characters>in.env(chapter 2.1). The value in.envtakes precedence over the page.
- A change on the page takes effect at once (build 0.8.7 or newer). Restart ELV LPFR (2.2) after a change in
.env, with an older package, or when the page says "The change takes effect after ELV LPFR is restarted."What you should see: on the page "ESIR access" = "Network (LAN)" („Mreža (LAN)"); after a start, in the log
L-PFR on *:8888 (LAN, X-ESIR-Token; UID …, SUF …, BE pcsc). - On the ELV LPFR computer, on the operator page, click "Show" („Prikaži") next to "Shared token (X-ESIR-Token)". Copy the token into the ESIR settings.
- In the ESIR, set the address
http://<IP-address-of-the-ELV-LPFR-computer>:8888/api/v3. Every request must carry the headerX-ESIR-Token: <token>. - The Windows firewall of the ELV LPFR computer must let inbound TCP connections on port 8888 through. When you enable network mode on the page, the rule „ELV LPFR (ESIR)" already exists and you skip this step. A manual rule is needed only when the mode is set in
.env(or with a package older than 0.8.6). Example command (run as Administrator):netsh advfirewall firewall add rule name="ELV LPFR 8888" dir=in action=allow protocol=TCP localport=8888What you should see: Windows answers
Ok.
Test call from the ESIR computer:
curl.exe --max-time 60 http://192.168.1.20:8888/api/v3/status -H "X-ESIR-Token: <token>"What you should see: JSON with the fields "gsc" and "mssc". Without a token or with a wrong one: {"message":"Unauthorized"} (HTTP 401).
Several ESIRs on one ELV LPFR are allowed. Several cash registers on other computers may work with the same ELV LPFR over the network. All use the same token. RequestId must be unique across all registers together (for example with a register prefix), because ELV LPFR has one shared database.
What else you need to know:
- A request without a token or with a wrong token reaches no ELV LPFR function at all.
- If network mode is requested but no token of at least 16 characters is set, ELV LPFR stays on "This computer only". It says so on the operator page.
- Programs on the ELV LPFR computer itself keep working through
localhost, without a token. - The Windows "Smart Card" window for the second PIN entry (step 8 in chapter 2) always appears on the ELV LPFR computer. After every start someone must confirm it there.
- A PIN-entry block (chapter 6.4) can be lifted only on the operator page of that computer.
3.3 HTTP request headers
| Header | When | Source | Note |
|---|---|---|---|
Content-Type: application/json | POST /invoices, POST /local-readout, POST /local-readout/apply | PURS | Without it the request body is not read and the request is refused. |
Accept-Language | POST /invoices | PURS | en or any en-… (e.g. en-US) gives an English journal. sr, sr-… (including sr-Latn-RS), *, an unknown language or no header give Serbian in Cyrillic. There is no Latin-script journal. |
RequestId | POST /invoices (recommended: always) | PURS | Your unique request ID. It is returned in the response header. Used by GET /invoices/{RequestId}. |
X-ESIR-Token | every request from another computer | ELV | Network mode only. In "This computer's local network (no token)" mode, devices in this computer's subnet do not send it (3.6). |
Send the request body in UTF-8. Tax labels can be Cyrillic (e.g. Ж).
3.4 ESIR in a web browser or in an Electron / Tauri / WebView app [ELV]
- ELV LPFR sends no CORS headers (
Access-Control-Allow-*). A web page from another address therefore cannot read its responses directly. - Every browser-based view sends an
Originheader. This includes the renderer in Electron, Tauri and WebView. POST /pinwith a foreignOriginheader gets HTTP 403{"ok":false,"reason":"cross-origin"}.- Solution: call ELV LPFR from the back end of the ESIR (a server, the Electron main process, the Rust side of Tauri, a local service), not from JavaScript in the view.
3.5 Timeouts and resending
- ELV LPFR does not detect duplicates. The same invoice sent twice gives two fiscal invoices. Never repeat
POST /invoicesblindly. - Send every invoice with a new, unique
RequestId. - Set the ESIR timeout to at least 30–60 seconds. On a new installation the first request may wait while data is fetched from SUF (up to 15 seconds per call, two calls). Signing with the card also takes time.
- When no answer arrives (timeout, broken connection):
- call
GET /api/v3/invoices/{RequestId}; - HTTP 200: the invoice was issued. Use that answer;
- HTTP 404: the invoice was not stored. Before sending again, look at
GET /status. Ifmssccontains8204(signing interrupted, recovery in progress), wait until the code disappears and repeat step 1; - only then send the invoice again, with a new
RequestId. Keep both IDs with the same receipt in the ESIR.
- call
- Error
2220(the card stopped answering in the middle of signing) is handled the same way. GET /invoices/{RequestId}works only with the card in the reader and the PIN entered. After a restart, enter the PIN first.- Do not repeat
2400automatically. Readmsscfirst (chapter 6.3). - Do not send
POST /pinin a loop. ELV LPFR lets through at most one attempt per second. After two consecutive wrong PINs it stops further entry.
3.6 Devices on the local network without a token (the PURS ESIR app) [ELV]
The Tax Administration's app „ESIR Poreska uprava RS" (Google Play) for phones and tablets asks only for the protocol, IP address and port of the L-PFR. It cannot send the X-ESIR-Token header. Such an ESIR uses the mode "This computer's local network (no token)" („Lokalna mreža ovog računara (bez tokena)"). It needs ELV LPFR package 0.8.6 or newer. The single button and the change without a restart exist from package build 0.8.7.
How it works:
- A device whose IPv4 address is in the same private subnet (10.x.x.x, 172.16–31.x.x, 192.168.x.x) as one of this computer's network cards sends no token.
- A device from another subnet, over VPN, with a public address or over IPv6 must still send
X-ESIR-Token. That is why ELV LPFR creates a token in this mode too ("Show" next to "Shared token (X-ESIR-Token)"). Without the token such a request gets HTTP 401. Such a device, besides the token, also needs the manual firewall rule from 3.2 (step 5), because the rule the page creates in this mode admits only the local subnet. Create it after changing the mode on the page, because from build 0.8.7 every change on the page removes the rule „ELV LPFR 8888". - Programs on the ELV LPFR computer itself keep working through
localhost, without a token.
Turning it on (build 0.8.7 or newer):
- On the operator page, "Device" panel, click "Connect a phone or tablet (PURS ESIR app)" („Poveži telefon ili tablet (ESIR Poreske uprave)"). The page first asks for confirmation, with the warning "Every device on this computer's local network, and a guest on the same wireless network, will be able to issue receipts while the PIN is entered." Confirm, then confirm the one Windows Administrator prompt. That single step:
- switches to "This computer's local network (no token)";
- creates the firewall rule „ELV LPFR (ESIR)", for the local subnet only;
- removes port forwards (
netsh interface portproxy, all four kinds) on the ELV LPFR port; - removes the old hand-made rule „ELV LPFR 8888". Rules with other names are not touched.
- The change takes effect at once, without a restart.
What you should see: "Network access is on, right away, without a restart." and "ESIR access" = "This computer's local network (no token)". If the page says "The change takes effect after ELV LPFR is restarted." instead (for example when another program holds the port), the setting is saved: restart ELV LPFR (2.2).
- The page then shows what to type into the app: "In the „ESIR Poreska uprava RS" app: PFR server → L-PFR · HTTP · <address> · port <port>". The address is the private IPv4 address of a real network card of this computer. Virtual adapters (for example vEthernet or WSL) are not shown. Below it is a DHCP-reservation tip: reserve that address for this computer in the router.
- Connect the phone or tablet to the same network as the ELV LPFR computer. In the „ESIR Poreska uprava RS" app choose PFR server → L-PFR, protocol HTTP, the address from the page and port 8888. No token is entered.
- Click "Check the connection" („Proveri vezu"; no Administrator needed). A list with ✓ and ✗ shows: whether ELV LPFR accepts requests from the network (port); whether the firewall rule „ELV LPFR (ESIR)" exists (local network only, or any address); that there is no port forwarding (portproxy), because with it a phone would get error 403; this computer's address on the local network. Every ✗ says to click "Connect a phone or tablet".
Turning it off: "Turn off network access (Administrator)" („Isključi pristup sa mreže (Administrator)") goes back to "This computer only", also at once, and removes the rule „ELV LPFR (ESIR)".
Through .env, instead of the page: fill in LPFR_LISTEN=lan and LPFR_LAN_TRUST=subnet (chapter 2.1). No token is required then. The value in .env takes precedence over the page, and the page then does not change the mode. If the line LPFR_LAN_TRUST= is missing (a .env from an older package), add it once. Then restart ELV LPFR (2.2) and set up the firewall by hand (3.2, step 5).
What you should see: in the log L-PFR on *:8888 (LAN, lokalna mreža bez tokena + X-ESIR-Token; UID …, SUF …, BE pcsc).
With build 0.8.6: the button "Allow devices on the local network without a token (Administrator)", and the change takes effect only after ELV LPFR is restarted (2.2). The ipconfig command then shows the computer's address.
Test call from another computer in the same subnet, without a token:
curl.exe --max-time 60 http://192.168.1.20:8888/api/v3/statusWhat you should see: JSON with the fields "gsc" and "mssc". HTTP 401 means that this computer is not in the ELV LPFR computer's subnet (7.1).
Security:
- While the PIN is entered, every device on that network can issue receipts, a guest on the same wireless network too. Keep guests on a separate wireless network (guest Wi-Fi).
- Every device accepted without a token is written once per program run to the error report (operator page, "Errors" („Greške")), with the code
ESIR_LAN_DEVICEand the messagerequest from <ip> accepted without a token (this PC's local network). This shows you which devices send requests. - The other rules of 3.2 apply here too:
RequestIdunique across all devices together; the Windows "Smart Card" window and unlocking PIN entry only on the ELV LPFR computer.
4. API overview
Base address: http://localhost:8888/api/v3. Paths are not case-sensitive. Bodies are JSON (UTF-8). The largest accepted request body is 1 MB.
| Method | Path | Source | Purpose | Request body | Typical answer | Card / PIN |
|---|---|---|---|---|---|---|
| GET | /attention | PURS | Is ELV LPFR running | — | 200, no body | no / no |
| GET | /status | PURS (mssc field ELV) | State, codes, tax rates | — | 200 JSON (always 200) | no / no |
| POST | /pin | PURS | Unlock the card | PIN as bare text, e.g. 1234 (also accepts {"pin":"1234"}) | 200 "0100"; 423 "2100", "2110" or "1999"; 200 "1300" without a card | yes / — |
| GET | /environment-parameters | PURS | SUF environment data | — | 200 JSON; 400 {"code":"1300"} without a card; {} while no data has been fetched | yes / no |
| GET | /device-info | ELV | Manufacturer, code, version, name, serial number | — | 200 JSON | no / no |
| POST | /invoices | PURS | Sign (fiscalise) an invoice | invoice request (JSON object) | 200 result; 400 {message, modelState} | yes / yes |
| GET | /invoices/{RequestId} | PURS | Fetch an issued invoice again | — | 200 result; 404 {"error":"not found"} | yes / yes |
| POST | /local-readout | ELV | Local readout to USB/SD | {"dir":"E:/"} | 200 {folder, uid, exportedCount, ids, errorReport} | yes / yes |
| POST | /local-readout/apply | ELV | Apply {JID}.commands from the media | {"dir":"E:/"} | 200 {applied, confirmedCount, commandCount} or {"applied":false} | yes / yes |
Notes:
- The paths
/and/ui/...belong to the operator page. They are not part of the API for the ESIR. - An unknown path gets 404
{"message":"Bad Request","modelState":[{"property":"","errors":["2806"]}]}. - Local readout is easiest from the operator page (Glossary, 5 steps). The API accepts only connected removable media and paths from
LOCAL_READOUT_ROOTS. POST /invoicestechnically also accepts an array of invoices. Do not use that (5.8).
4.1 GET /status — example (illustrative — do not send)
The example is assembled from the ELV LPFR code, with the test (sandbox) package. Values shown as … depend on the card and the installation. The tax group is an example from the test environment.
{
"isPinRequired": false,
"auditRequired": false,
"sdcDateTime": "2026-10-04T14:05:09.123+02:00",
"protocolVersion": "1.0.0.0",
"softwareVersion": "verzija 2",
"secureElementVersion": "…",
"hardwareVersion": "N/A",
"deviceSerialNumber": "8S-0002-…",
"mrc": "8S-0002-…",
"make": "ELV d.o.o.",
"model": "ELV LPFR",
"uid": "…", // card JID; null when no card is in the reader
"taxCoreApi": "https://api.sandbox.suf.purs.gov.rs", // Test package; the „Produkcija" package has no "sandbox"
"lastInvoiceNumber": "…", // "" until the device has issued an invoice
"supportedLanguages": ["sr-Cyrl-RS", "en-US"],
"currentTaxRates": {
"validFrom": "2023-10-08T06:40:00Z",
"groupId": 8,
"taxCategories": [
{ "name": "VAT", "categoryType": 0, "orderId": 6,
"taxRates": [ { "rate": 10.00, "label": "A" }, { "rate": 0.00, "label": "B" }, { "rate": 19.00, "label": "Ж" } ] },
…
]
},
"allTaxRates": [ … ],
"mssc": [],
"gsc": ["0100"]
}What the ESIR uses from /status:
| Field | Meaning |
|---|---|
gsc | Array of status codes, ordered by importance: card first, then PIN, then readout, informational codes (0xxx) last. Chapter 6.2. |
mssc | [ELV] Reason of the licence or card-protection state. Empty array = all fine. Chapter 6.3. |
isPinRequired | true while the PIN has not been entered (or the last attempt was wrong). |
auditRequired | true once unaudited turnover reaches 75% of the card limit (1400 is then in gsc too). |
uid | JID of the card that is in the reader now. |
currentTaxRates | The tax group valid now. Take the labels (label) for your articles from it. |
allTaxRates | All tax groups SUF delivered, with their validity dates. |
taxCoreApi | SUF address from the package. With the „Produkcija" package it does not contain sandbox. |
lastInvoiceNumber | Number of the last invoice this device signed. |
mrc, deviceSerialNumber | The device MRC: 8S-0002-<installation serial number>. |
sdcDateTime | Local time of the device, ISO 8601 with the time-zone offset. |
4.2 GET /device-info — example [ELV]
{
"manufacturer": "ELV d.o.o.",
"manufacturerCode": "8S-0002",
"softwareVersion": "verzija 2",
"productName": "ELV LPFR",
"serialNumber": "<card JID>"
}Works without a card and without the PIN. serialNumber is the card JID read when the program started. If no card was in the reader at start-up, serialNumber does not show the real card (it can be empty or a value from the configuration). Always read the JID of the inserted card from GET /status → uid.
4.3 GET /environment-parameters — example (test environment)
The answer is exactly what SUF delivers. The example is from the test (sandbox) environment:
{
"organizationName": "Министарство финансија - Пореска управа - Централа",
"serverTimeZone": "Central Europe Standard Time",
"street": "Саве Машковића 3-5",
"city": "Београд",
"country": "RS",
"endpoints": {
"taxpayerAdminPortal": "https://tap.sandbox.suf.purs.gov.rs:443/",
"taxCoreApi": "https://api.sandbox.suf.purs.gov.rs:443/",
"vsdc": "https://vsdc.sandbox.suf.purs.gov.rs:443/",
"root": "https://sandbox.suf.purs.gov.rs:443/v/?vl="
},
"environmentName": "СУФ Развој",
"logo": "https://sandbox.suf.purs.gov.rs:443/DownloadContent/TAlogo.png",
"ntpServer": "http://0.pool.ntp.org:80/",
"supportedLanguages": ["sr-Cyrl-RS", "en-US"]
}5. Issuing an invoice step by step
5.1 Recommended flow
- When the ESIR starts:
GET /attention(200 = ELV LPFR is running), thenGET /status. - If
gsccontains1300: tell the cashier "Insert the card into the reader". Wait until1300disappears. - If
gsccontains1500, look atmsscfirst:- if
mssccontains8201or8202: do not send the PIN through the API. The answer would be 423"1999", even with the correct PIN. Tell the cashier to enter the PIN on the operator page (6.4); - otherwise ask the cashier for the PIN and send it with
POST /pin. On"0100", remind the cashier that Windows on the ELV LPFR computer asks for the same PIN once more.
- if
- Read the valid tax labels from
currentTaxRates. Check that every article has a label that exists. - For every invoice:
POST /invoices, with the headersContent-Type,RequestIdand (optionally)Accept-Language. One invoice per request. - Print the journal and the QR code from the answer. Store the whole answer with your receipt.
- While running: call
GET /statusperiodically, for example once a minute. Show warnings (1400,mssc) to the cashier.
Entering the PIN through the API (for testing; in daily work enter the PIN through the ESIR or on the operator page):
curl.exe -X POST http://localhost:8888/api/v3/pin -H "Content-Type: application/json" -d "CARD-PIN"- Replace
CARD-PINwith the real PIN. - Caution: a PIN typed on the command line may stay in the command history. After the test close the window and do not share screenshots.
- The body can also be JSON:
{"pin":"1234"}. That is how an ESIR usually sends it from its code. - The answer is a bare JSON string:
"0100"(accepted),"2100"(wrong PIN),"2110"(card locked),"1999"(PIN entry blocked, 6.4).
5.2 Request: normal invoice, cash [PURS]
Example A — copy-paste. The smallest valid request (a real request from the PURS reference capture):
{
"invoiceType": 0,
"transactionType": 0,
"payment": [
{ "amount": 110, "paymentType": 1 }
],
"items": [
{ "name": "Hleb", "unitPrice": 110, "quantity": 1, "labels": ["A"], "totalAmount": 110 }
]
}Save it as racun.json (UTF-8) and send it. Sending from a file works the same in cmd and in PowerShell and does not break Cyrillic labels:
curl.exe -i --max-time 60 -X POST http://localhost:8888/api/v3/invoices -H "Content-Type: application/json" -H "Accept-Language: sr-Cyrl-RS" -H "RequestId: esir-000123" --data-binary "@racun.json"What you should see: HTTP/1.1 200 OK, the header RequestId: esir-000123 and a body starting with {"requestedBy":"<JID>". The body contains invoiceNumber, verificationUrl, verificationQRCode and journal.
The same kind of invoice with optional fields (illustrative — do not send; shortened with …):
{
"invoiceType": 0,
"transactionType": 0,
"cashier": "Milica Kovačević",
"buyerId": "10:105255401",
"buyerCostCenterId": "20:01234567",
"invoiceNumber": "<ESIR number>",
"dateAndTimeOfIssue": "2026-09-16T08:00:00.000+02:00",
"payment": [ { "amount": 13958.02, "paymentType": 1 } ],
"items": [
{ "name": "Cedeni Sok/l", "unitPrice": 349.99, "quantity": 1.5, "labels": ["Ж"], "totalAmount": 524.99, "gtin": "12345678" },
…
]
}5.3 Request fields
The rules in the "Check" column are enforced by ELV LPFR itself. The error code is in parentheses.
| Field | Required | Check | Note |
|---|---|---|---|
invoiceType | yes | 0 Normal, 1 ProForma, 2 Copy, 3 Training, 4 Advance. Number or name, any letter case (otherwise 2805). | |
transactionType | yes | 0 Sale, 1 Refund. Number or name (otherwise 2805). | |
payment | yes | At least one element (2800). paymentType: 0 Other, 1 Cash, 2 Card, 3 Check, 4 WireTransfer, 5 Voucher, 6 MobileMoney — number or name. | amount is the amount of that payment method. |
items | yes | Each item has name, quantity, unitPrice, labels, totalAmount. 2800: any of these fields is missing. 2805: name longer than 2048 characters or not text; quantity not a number, below 0.001 or more than 3 decimals; unitPrice not a number, 10^15 or more, or more than 4 decimals; totalAmount not a number. 2804: totalAmount negative, more than 4 decimals, or too large for the card. | ELV LPFR computes the tax from totalAmount and the label, not the ESIR. |
items[].labels | yes | Non-empty array (2800). Every label must exist in the valid tax group (2310). Letter case does not matter. The same label twice on one item: 2805. | At most 12 tax categories per invoice (2808). |
items[].gtin | no | 8 to 14 characters (2803). | |
cashier | no | At most 50 characters (2803). | Printed as „Касир". |
buyerId | no | If sent, must not be empty (2805). At most 20 characters (2803). Printable ASCII only (2805). | Format <type code>:<number>, e.g. 10:105255401. |
buyerCostCenterId | no | At most 50 characters (2801). Requires buyerId too (2800). | „Опционо поље купца". |
invoiceNumber | no | If sent, must not be empty (2805). At most 60 characters (2803). | Printed as „ЕСИР број". Its content is defined by PURS for your ESIR. |
dateAndTimeOfIssue | no | ISO 8601, years 1900 to 9999 (2805). | The ESIR time („ЕСИР време"). It does not set the fiscal time of the invoice: that is always the ELV LPFR clock (sdcDateTime). |
referentDocumentNumber | for copy and every refund | Format XXXXXXXX-XXXXXXXX-N (2806), at most 60 characters. Missing when required: 2800. | Number of the original invoice (invoiceNumber from its answer). |
referentDocumentDT | no | A valid date (2805), not in the future (2804). If sent, referentDocumentNumber is required too. | Tax is computed with the rates valid at that moment. Printed as „Реф. време". |
options.omitQRCodeGen | no | 0 or 1 (2805). | 1 = verificationQRCode: null in the answer. |
options.omitTextualRepresentation | no | 0 or 1 (2805). | 1 = journal: null in the answer. |
A field error comes back with the exact path of the field. Example (unknown tax label):
{ "message": "Bad Request", "modelState": [ { "property": "items[0].labels[0]", "errors": ["2310"] } ] }5.4 The answer: what the ESIR prints and stores
The answer to Example A (illustrative — do not send). Values come from the PURS reference capture, with tax rate A = 10% as in example 4.1. The shape and the list of fields are those of ELV LPFR. Long values are shortened with ….
{
"requestedBy": "K6Y3AGSV",
"signedBy": "K6Y3AGSV",
"sdcDateTime": "2026-09-15T22:31:52.000Z",
"invoiceCounter": "184/749ПП",
"invoiceCounterExtension": "ПП",
"invoiceNumber": "K6Y3AGSV-K6Y3AGSV-749",
"taxItems": [
{ "categoryType": 0, "label": "A", "amount": 10, "rate": 10, "categoryName": "VAT" }
],
"totalCounter": 749,
"transactionTypeCounter": 184,
"totalAmount": 110,
"businessName": "ELV d.o.o.",
"tin": "RS114111400",
"locationName": "ELV d.o.o.",
"address": "Beogradska 235c",
"district": "NOT APPLICABLE",
"taxGroupRevision": …,
"mrc": "8S-0002-…",
"messages": "Success",
"signature": "…",
"encryptedInternalData": "…",
"verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=…",
"verificationQRCode": "…",
"journal": "============ ФИСКАЛНИ РАЧУН ============\r\n…"
}| Field | What it is | What the ESIR does |
|---|---|---|
invoiceNumber | Fiscal invoice number („ПФР број рачуна"), format JID-JID-ordinal | Print and store. Needed for refunds and copies. |
sdcDateTime | Fiscal signing time („ПФР време") | Store. ELV LPFR returns it in UTC (…Z). Convert it to local time for printing; the journal already contains it in Belgrade time. For a refund, send it as referentDocumentDT. |
invoiceCounter | Invoice counter („Бројач рачуна"), e.g. 184/749ПП | Print (it is already in the journal). |
invoiceCounterExtension, totalCounter, transactionTypeCounter | Parts of the counter | Store. |
totalAmount, taxItems | Total and tax per label, as computed by ELV LPFR | Store. Use these amounts for reports, not your own calculation. |
requestedBy, signedBy | Card JID | Store. |
businessName, tin, locationName, address, district | Taxpayer data from the card certificate | Print (already in the journal header). |
taxGroupRevision, mrc, messages | Tax group revision, device MRC, "Success" | Store. |
signature, encryptedInternalData | Signature and encrypted internal data of the card (base64) | Store. |
verificationUrl | Address for checking the invoice at the Tax Administration | Store. This is the content of the QR code. With a production card the address must not contain sandbox. |
verificationQRCode | The QR code as a GIF image, base64, without a data: prefix | Print as an image. For display, prepend data:image/gif;base64,. |
journal | Invoice text: 40 characters per line, lines separated by \r\n | Print verbatim in a fixed-width font. Elements required on the ESIR's printed receipt (e.g. „За уплату", „Повраћај", buyer signature on a refund copy) are added by the ESIR. |
The journal for the example above (Serbian):
============ ФИСКАЛНИ РАЧУН ============
RS114111400
ELV d.o.o.
ELV d.o.o.
Beogradska 235c
NOT APPLICABLE
Касир:
-------------ПРОМЕТ ПРОДАЈА-------------
Артикли
========================================
Назив Цена Кол. Укупно
Hleb (A)
110,00 1 110,00
----------------------------------------
Укупан износ: 110,00
Готовина: 110,00
========================================
Ознака Име Стопа Порез
A VAT 10,00% 10,00
----------------------------------------
Укупан износ пореза: 10,00
========================================
ПФР време: 16.9.2026. 00:31:52
ПФР број рачуна: K6Y3AGSV-K6Y3AGSV-749
Бројач рачуна: 184/749ПП
========================================
======== КРАЈ ФИСКАЛНОГ РАЧУНА =========(Shown without trailing spaces. In the real answer the lines keep their alignment spaces and are separated by \r\n.)
5.5 Journal language (Accept-Language) [PURS]
enor anyen-…(e.g.en-US): English journal ("FISCAL INVOICE", "Total Purchase", "SDC Time"…).sr, anysr-…(includingsr-Latn-RS),*, an unknown language or no header: Serbian journal, in Cyrillic. There is no Latin-script journal.- When the header lists several languages, the first supported one wins (
qvalues are respected). - Amounts, quantities and time (Belgrade time) are written the same way in both languages.
- The languages supported by the environment are in
GET /status→supportedLanguages.
5.6 Refund, copy, advance, pro forma, training [PURS]
| Kind | invoiceType / transactionType | What is different | Counter suffix |
|---|---|---|---|
| Normal sale | 0 / 0 | Ordinary invoice. | ПП |
| Normal refund | 0 / 1 | referentDocumentNumber = invoiceNumber of the original is required. Recommended: also referentDocumentDT = sdcDateTime of the original (tax at the rates valid then, „Реф. време" in the journal). In the journal the item amounts are negative and the total line reads „Укупна рефундација". | ПР |
| Copy | 2 / 0 or 1 | referentDocumentNumber is required. The journal starts and ends with „ОВО НИЈЕ ФИСКАЛНИ РАЧУН". | КП / КР |
| Pro forma | 1 / 0 or 1 | Not a fiscal invoice (same caption). For a sale ELV LPFR does not require a reference. | РП / РР |
| Training | 3 / 0 or 1 | Not a fiscal invoice (same caption). For a sale ELV LPFR does not require a reference. | ОП / ОР |
| Advance sale | 4 / 0 | Advance invoice. | АП |
| Advance refund | 4 / 1 | referentDocumentNumber of the advance invoice is required. | АР |
Every refund (transactionType 1), of any kind, requires referentDocumentNumber.
Example B — copy-paste after changing two fields. A refund of the invoice from Example A (a real request from the PURS reference capture). Before sending, replace referentDocumentNumber with the invoiceNumber, and referentDocumentDT with the sdcDateTime, from your answer to Example A. Send it the same way as Example A, with a new RequestId.
{
"invoiceType": 0,
"transactionType": 1,
"cashier": "Tosha",
"buyerId": "10:105255401",
"referentDocumentNumber": "K6Y3AGSV-K6Y3AGSV-749",
"referentDocumentDT": "2026-09-16T00:31:52+02:00",
"payment": [ { "amount": 110, "paymentType": 1 } ],
"items": [ { "name": "Hleb", "unitPrice": 110, "quantity": 1, "labels": ["A"], "totalAmount": 110 } ]
}Important [ELV]:
- The licence never stops a refund, copy, training or pro forma invoice. When the licence is not valid, only new Normal sale and Advance sale invoices are refused (code
2400). - How the final invoice after an advance is composed is defined by PURS for the ESIR. It is not specific to ELV LPFR and is not described here.
5.7 Fetching an invoice again: GET /invoices/{RequestId} [PURS]
curl.exe http://localhost:8888/api/v3/invoices/esir-000123What you should see: the same JSON as in the first answer to Example A. For an unknown RequestId: HTTP 404 {"error":"not found"}.
- Returns the same result as the first answer, with the QR code and the journal.
- It is looked up by the
RequestIdthe ESIR sent, not by the invoice number. A call withinvoiceNumberreturns 404. - If the same
RequestIdwas sent more than once by mistake, only the latest invoice is returned. - Works only with the card in the reader and the PIN entered (otherwise 400
{"code":"1300"}or{"code":"1500"}). POST /invoiceswith the sameRequestIddoes not return the old invoice. It creates a new one.
5.8 Never send several invoices in one request
POST /invoices technically also accepts an array of requests and returns an array of results. Do not use it:
- all invoices in the array share the same
RequestId, so after a lost answerGET /invoices/{RequestId}returns only the last invoice of the array. You cannot fetch the others; - if one request in the array fails, earlier ones may already be signed while the answer is only an error.
Send one invoice per request, each with its own RequestId.
6. Status codes and errors
6.1 Where codes appear
| Place | Form |
|---|---|
GET /status | "gsc": ["1500","0210"] — an array, by importance. Next to it "mssc": [...] [ELV]. Always HTTP 200. |
POST /invoices (error) | HTTP 400: {"message":"Bad Request","modelState":[{"property":"<field or empty>","errors":["<code>"]}]}. property is empty when the error is not tied to a field (e.g. PIN not entered). |
POST /pin | A bare JSON string, e.g. "0100", with the header Content-Type: application/json. |
GET /environment-parameters without a card | HTTP 400 {"code":"1300"}. No PIN is needed here, so 1500 never comes. |
GET /invoices/{RequestId}, /local-readout, /local-readout/apply (device not ready) | HTTP 400 {"code":"1300"} or {"code":"1500"}. |
An error answer never carries message text, only the code. The [ELV] reason of a state is shown in mssc, on the operator page and in the error report.
6.2 Catalogue codes [PURS]
| Code | Meaning | Where | What the ESIR does |
|---|---|---|---|
0100 | PIN accepted; device ready | /status, /pin | Nothing. |
0210 | Informational code ("Internet Available") | /status, when the card is not in the reader or the PIN is not entered | Ignore it. Do not use it as an internet indicator. |
1100 | Disk almost full (warning) | /status | Tell the operator to free space. |
1300 | Card not in the reader | /status; /pin (HTTP 200); /invoices, /environment-parameters (HTTP 400) | "Insert the card", then ask for the PIN. |
1400 | Readout required (75% of the card limit) | /status | Invoices are still issued. Warn: check the internet and the Windows PIN window, or do a local readout. |
1500 | PIN not entered | /status; /invoices (HTTP 400) | Look at mssc, then ask for the PIN (5.1, step 3). |
1999 | General warning [used by ELV] | /status (licence grace period, card-protection warnings); /pin (HTTP 423) | Read mssc. On /pin: the PIN can now be entered only on the operator page (6.4). |
2100 | Wrong PIN | /pin (HTTP 423) | Show the error. Do not retry automatically. |
2110 | Card locked (all PIN tries used) | /pin (HTTP 423) | The card is permanently locked. Contact the card issuer. |
2210 | Secure Element locked: turnover limit reached | /invoices (HTTP 400) | No new invoices until a Proof of Audit: internet or local readout. |
2220 | The card stopped answering in the middle of signing | /invoices (HTTP 400) | Do not resend blindly. Follow chapter 3.5. |
2310 | Invalid tax label | /invoices (HTTP 400), property = items[i].labels[j] | Fix the article label using currentTaxRates. |
2400 | Device not ready for signing | /invoices (HTTP 400); /status | Do not retry automatically. The cause is in mssc: 81xx = licence; 82xx = card protection; without mssc the most common cause is that tax rates or the verification address have not been fetched yet (new installation without internet). |
2800 | Required field missing | /invoices | Fix the request (the field is in property). |
2801 | Field value too long | /invoices | Fix the request. |
2803 | Invalid field length | /invoices | Fix the request. |
2804 | Field value out of range | /invoices | Fix the request. |
2805 | Invalid field value | /invoices | Fix the request. If property is empty: the computer clock is wrong (ahead of the correct time or set back). |
2806 | Invalid data format | /invoices; unknown path (HTTP 404); malformed JSON | Check the JSON and the path. |
2808 | More than 12 tax categories on one invoice (ELV LPFR uses this code for that case) | /invoices | Split the invoice. |
2809 | The card certificate has expired | /invoices | The card must be replaced. |
6.3 mssc — reason of the state [ELV]
mssc (Manufacturer Specific Status Codes) is an official field of the "Get Status" answer. ELV LPFR puts the reason in it. It is empty in a healthy state.
The gsc column shows what is then added to gsc:
2400— new invoices are refused;1999— warning only;(1500)— nothing is added:1500is already ingscbecause the PIN is requested. This is not an invoice block;—— no change.
Licence (81xx):
mssc | Meaning | gsc |
|---|---|---|
8101 | The licence expires within the warning window set in the licence (usually 14 days) | — |
8102 | The licence has not been renewed for at least 7 days (no connection to the licence server) | — |
8103 | Grace period: new invoices stop on the date shown on the operator page | 1999 |
8104 | The licence has expired | 2400 |
8105 | The licence is revoked (1999 until it takes effect, 2400 after) | 1999 / 2400 |
8106 | No valid licence for this card | 2400 |
8107 | The computer clock is off (warning only) | — |
8108 | Installation integrity check failed (blocks together with 8110) | — |
8109 | JID/PIB not read from the card certificate | 2400 |
8110 | The licence check could not be performed | 2400 |
Card protection (82xx):
mssc | Meaning | gsc |
|---|---|---|
8201 | PIN entry blocked after 2 wrong PINs; unlock on the operator page | (1500) |
8202 | The card has at most 2 PIN tries left; the PIN is entered only on the operator page | (1500) |
8203 | The store lacks invoices the card signed | 2400 |
8204 | Signing interrupted (power loss, card removed); recovery in progress | 2400 |
8205 | The card counter jumped (card used on another device); confirmation needed | 2400 |
8206 | The Tax Administration rejected at least one package (kept, not resent) | 1999 |
8207 | A tax label is blocked after a rejection (such items get 2310) | 1999 |
8208 | Systemic rejection (PIB, signature, MRC or certificate); every new invoice is refused | 2400 |
8209 | Tax rates from SUF failed the check; the other, correct table is used | 1999 |
8210 | The computer clock is more than 3 minutes off | 1999 |
8211 | The computer clock is ahead of the correct time; signing refused | 2400 |
8212 | The store cannot be written or has no space (less than 100 MB) | 2400 |
8213 | The backup copy of at least one package was not written | 1999 |
8214 | Another store or another instance holds this card | 2400 |
8215 | Environment mismatch (SUF settings / verification address / MRC) | 2400 |
8216 | PIB/JID not read from the card certificate | 2400 |
8217 | Packages are not being delivered to the Tax Administration | 1999 |
8218 | The card certificate expires within 30 days | — |
8219 | The PIN in the Windows window was not accepted | 1999 |
8220 | The card-protection check could not be performed | 2400 |
Recommendation for the ESIR: when mssc is not empty, show the cashier a short message and point to the ELV LPFR operator page. The page has the explanation and the button for the action needed.
6.4 PIN flow
[no card] gsc 1300,1500,0210
| card inserted
v
[card, PIN not entered] gsc 1500,0210 <-- after every start and every re-insertion
| POST /pin -> "0100"
v
[ready] gsc 0100
| card removed -> back to [no card], the PIN is forgottenELV LPFR rules for POST /pin [ELV]:
- Send exactly 4 digits. A digits-only PIN that is not exactly 4 digits long (and an empty body) gets 423
"2100", and the card is not asked (no try is spent). - At least 1 second passes between two attempts. A faster request is only delayed, not refused.
- After 2 consecutive wrong PINs ELV LPFR stops further attempts: every next
POST /pingets 423"1999"(mssc8201), even with the correct PIN. It is unlocked only on the operator page, with "Unlock PIN entry" („Otključaj unos PIN-a"). This protects the card from a permanent lock (2110). - When the card has at most 2 tries left, a PIN sent from the ESIR gets 423
"1999"(mssc8202). The PIN is then entered only on the operator page. - After
"0100", Windows on the ELV LPFR computer asks once for the same PIN in the "Smart Card" window. That window must be confirmed.
6.5 HTTP statuses
| HTTP | Body | When |
|---|---|---|
| 200 | JSON | Success. Always for /status and /attention (no body). For /pin with both "0100" and "1300". |
| 400 | {message, modelState} | Error on POST /invoices, malformed JSON. |
| 400 | {"code":"…"} | Device not ready: /environment-parameters (only 1300), GET /invoices/{RequestId} and /local-readout* (1300 or 1500). |
| 400 | {"error":"…"} | /local-readout: dir missing or not allowed. |
| 401 | {"message":"Unauthorized"} | [ELV] Request from another computer in network mode without a valid X-ESIR-Token. In "This computer's local network (no token)" mode: a request without a token from a device outside this computer's subnet (3.6). |
| 403 | {"message":"Forbidden"} | [ELV] Request from this computer addressed to a foreign name (Host). |
| 403 | {"ok":false,"reason":"cross-origin"} | [ELV] POST /pin with a foreign Origin header (browser, renderer). |
| 404 | {message, modelState} with 2806 | Unknown path or wrong method. |
| 404 | {"error":"not found"} | GET /invoices/{RequestId}: no invoice with that RequestId. |
| 423 | "2100", "2110", "1999" | POST /pin refused. |
| no answer | — | Connection refused or timeout: ELV LPFR is not running, the request comes from the network while "This computer only" is on, or ELV LPFR was not restarted after a mode change that needs it (3.6). |
| 5xx | — | The /api/v3 API does not return them on purpose. A 5xx means: ELV LPFR is not available. |
7. Troubleshooting
7.1 The program does not run or the ESIR cannot connect
| Symptom | Cause | Fix |
|---|---|---|
| "Windows protected your PC" at the first start | The program is not yet signed with a code-signing certificate | "More info" → "Run anyway", once per computer. Verify the file with the SHA-256 fingerprint from "Moje licence". |
| The window says „ELV-LPFR.exe nije pronadjen pored ovog fajla" (ELV-LPFR.exe not found next to this file) | The ZIP was not fully extracted, or it was started from inside the ZIP | Extract the whole package into one folder and run ELV-LPFR-Setup.exe from there. |
The window shows a port-in-use error (EADDRINUSE), then „Servis je zaustavljen." (service stopped) | Port 8888 is already used by another program, most often another copy of an L-PFR | Close the other copy (2.2; after the installation do not start ELV-LPFR.exe from another folder), or change PORT in .env (2.1) and put that address into the ESIR. |
ELV LPFR does not answer after logging on to Windows (http://localhost:8888/ does not open, not even when you open it by hand) | The start was refused, for example because the port is busy (code 3 or 4) | The reason, in Serbian and English, is written to poslednja-greska.txt in the data folder C:\ProgramData\ELV LPFR\ (for an earlier installation from the ZIP that the Setup took over: in that folder). Send it to support if the reason is not clear. |
| Message „Drugi L-PFR proces (PID …) već koristi ovaj folder podataka" (another L-PFR process already uses this data folder) | Two copies on the same folder | Close the other copy. Signing resumes by itself. |
| ESIR on another computer or device: connection refused or timeout | "This computer only" is on; ELV LPFR was not restarted after a change in .env, with build 0.8.6 or older, or when the page said "The change takes effect after ELV LPFR is restarted."; the token is shorter than 16 characters; or the firewall blocks port 8888 (mode set in .env, or a package older than 0.8.6) | Click "Check the connection" (from build 0.8.7) and do what each ✗ says. Check the "Device" panel → "ESIR access" and the log line L-PFR on *:8888 (LAN, …). Restart ELV LPFR (2.2) if needed. With a mode from .env or a package older than 0.8.6, allow TCP 8888 in the firewall (3.2, step 5). |
ESIR on the same computer: connection refused on http://<IP-address>:8888 | In "This computer only" mode ELV LPFR does not listen on the network address | Use http://localhost:8888/api/v3. |
| ESIR on another computer: HTTP 401 | No X-ESIR-Token header or a wrong token | Copy the token from the operator page ("Show"). The header name must be exact. |
| Device in "This computer's local network (no token)" mode: HTTP 401 | The device is not in the ELV LPFR computer's subnet (another subnet, VPN, a public address or IPv6) | Connect the device to the same network as the ELV LPFR computer, or let it send X-ESIR-Token (3.6). |
HTTP 403 Forbidden on the same computer | The ESIR uses a name that is not localhost, 127.0.0.1 or the computer name | Use http://localhost:8888/api/v3. |
| The phone gets HTTP 403, or "Check the connection" shows port forwarding (portproxy) | There is a netsh interface portproxy on the ELV LPFR port. Port forwarding is no substitute for a network mode | Click "Connect a phone or tablet (PURS ESIR app)": that step removes the forwarding (3.6). |
HTTP 403 cross-origin on /pin | /pin is called from a browser or a renderer (Electron, Tauri, WebView) | Call ELV LPFR from the ESIR back end (3.4). |
curl in PowerShell does not show the error body | In PowerShell curl is a different program | Type curl.exe. |
No answer to POST /invoices | Network, timeout | Do not resend. GET /invoices/{RequestId} (3.5). |
7.2 The API returns an error code
| Symptom | Cause | Fix |
|---|---|---|
2400 on a new installation, mssc empty | Tax rates or the verification address have not been fetched yet (no internet) | Provide internet. The reason is in the operator page notifications. ELV LPFR tries again with the next invoice (at most once a minute). |
2400, mssc 8215 | ELV LPFR's own environment settings do not agree with each other | Do not edit .env by hand. Write to support; if needed, download and unzip the right package again (2.3). |
2310 for a label that exists on the register | The label is not in the device's currentTaxRates, or it is blocked (mssc 8207) | Align the article labels with currentTaxRates. With 8207 check the operator page. |
Cyrillic labels (Ж) give 2310 | The body is not UTF-8 | Send UTF-8. |
400 with property invoiceType and 2805, although the field was sent | Content-Type: application/json is missing, so the body was not read | Add the header. |
2805 with an empty property | The computer clock is more than 5 minutes ahead (mssc 8211) or was set back | Turn on time synchronisation in Windows and correct the time. |
2210 | The card turnover limit is reached | Proof of Audit: over the internet (needs a confirmed Windows window) or by local readout (Glossary, 5 steps). |
Invoices are issued but packages wait; later 1400, then 2210 | The Windows "Smart Card" window was not confirmed, or there is no internet | Confirm the window (check the taskbar). The window appears once per start: if it was closed, restart ELV LPFR (2.2) and enter the PIN. Check the internet. |
| SUF unreachable (operator page, "Sending to the Tax Administration": "SUF: unavailable (offline)") | No internet or SUF is down | Invoices are still issued; packages wait safely. Restore the internet. If it lasts long: mssc 8217, then 1400 and 2210. Then do a local readout. |
7.3 Card, PIN and licence
| Symptom | Cause | Fix |
|---|---|---|
| "Card not in the reader" („Kartica nije u čitaču") although the card is inserted | The reader is not connected, another reader is selected, or the card is in another reader | "Device" panel → "Card reader": choose "Automatic (the reader holding the card)". Leave PCSC_READER_NAME in .env empty (2.1). |
/pin returns "2100" | Wrong PIN (or not exactly 4 digits) | Check the PIN. Do not try again and again blindly. |
/pin returns "1999" | PIN entry blocked after 2 wrong PINs (8201) or the card has at most 2 tries left (8202) | Check the correct PIN, then on the operator page click "Unlock PIN entry" and enter the PIN there. |
/pin returns "2110" | The card is permanently locked | Contact the card issuer. |
Production card, but verificationUrl or taxCoreApi contains sandbox | The test package (from support) is running with a production card | Stop issuing invoices at once. Write to support. Install the „Produkcija" package from "Moje licence" (2.3). |
2400, mssc 8104 or 8106 | The licence has expired or there is none | "Licence" → "Check now" („Proveri sada"), or activate a new code. Refunds, copies, training and pro forma invoices still work. |
1999, mssc 8103 | Licence grace period (no renewal over the internet) | Restore the internet and click "Check now", or import the licence file (.lic) from USB. |
2400, mssc 8110 (with 8108) | A program file was changed or the licence module is not working | A reinstall from the original package from "Moje licence" is needed. Write to support first. Do not delete the data folder. |
| Activation code rejected | Typo (16 characters, 4×4), the code was already used for another card, it has expired, or the card belongs to another PIB | Check the code and its status in "Moje licence". Internet and Administrator approval are required. Write to support. |
| „Potvrda Administratora Windows-a nije data — kod nije poslat." (Administrator approval not given — code not sent) | The UAC prompt was refused or the user is not an Administrator | Try again and confirm the prompt as an Administrator. |
| The e-mail with the activation codes did not arrive | The message is in spam, or the purchase was made with another e-mail address | Check the spam folder. Log in to "Moje licence" with the buyer's e-mail address. If the code is not there either, write to support. |
8. Before you go to production
9. Support and useful links
| What | Where |
|---|---|
| Technical support (and the test package, on request) | [email protected] |
| Moje licence (codes, cards, download of the „Produkcija" package) | https://allurepos.com/lpfr.html — log in with the buyer's e-mail address and the 6-digit code sent to it |
| ELV LPFR operator page | http://localhost:8888/ (only on the ELV LPFR computer; Serbian Latin, Cyrillic, English) |
| Documentation in the package | folder dokumentacija\: 01-Opis-proizvoda-ELV-LPFR.pdf, 02-Korisnicko-uputstvo-ELV-LPFR.pdf, 03-Uputstvo-za-instalaciju-ELV-LPFR.pdf; file PROCITAJ-ME.md (all in Serbian) |
| PURS Technical Guide (sandbox) | https://tap.sandbox.suf.purs.gov.rs/help |
When you write to support, send:
- the error code and the exact time;
- which package you use („Produkcija" or the test package from support);
- the output of
curl.exe --max-time 60 http://localhost:8888/api/v3/statusandcurl.exe http://localhost:8888/api/v3/device-info; - if needed, the error report: a local readout writes
{JID}-errors.jsonto the media, and the latest entries are also on the operator page ("Error report", „Izveštaj o greškama").
Never send the card PIN to support.