Srpski (latinica)PDF version

Contents

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 RequestId header. If the answer is lost, fetch the invoice with GET /api/v3/invoices/{RequestId}. Do not resend it blindly.
  • Read the device state from GET /api/v3/status (fields gsc and mssc).

1. What you need

WhatDetails
A Windows computerOn 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) cardIssued by the Tax Administration. For development and testing: a test (sandbox) card. For the taxpayer's real work: a production card.
Card PINExactly four digits. Entered after every start.
Licence activation code16 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 cardThe 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.
InternetTo 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 accountELV 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 clockThe 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 spaceAbout 21.6 KB per invoice. Below 100 MB of free space no new invoices are issued.

2. Installation in 5 minutes

  1. 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 (mssc 8215) 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 SHA256
  2. Unzip 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 .env file that sits in the same folder as ELV-LPFR-Setup.exe. So run the Setup from the unzipped folder as it is and do not move ELV-LPFR-Setup.exe away 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.

  3. Insert the card into the reader.

  4. 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.

  5. 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.

  6. The installation finishes in a few seconds. The program and its settings (.env) are placed in C:\Program Files\ELV LPFR\, and the data (database lpfr.sqlite, licence) in C:\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 to C:\ProgramData\ELV LPFR\instalacija.log (send it to support if something goes wrong). The Setup also prints the line SUF: … (PRODUKCIJA / production), SUF: … (TEST / sandbox) or SUF: … (nepoznato / unknown), and SUF: (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 the status answer below: with the „Produkcija" package the "taxCoreApi" field does not contain sandbox, with the test package (from support) it is https://api.sandbox.suf.purs.gov.rs.

  7. 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."

  8. 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").

  9. 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.

  10. 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 use pokreni.cmd, autostart-ukljuci.cmd, autostart-iskljuci.cmd or ELV-LPFR.exe from the ZIP folder or from an old folder: ELV LPFR starts by itself from C:\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 in C:\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 in Downloads or on the desktop. Once the adoption has finished, do not run anything from that folder any more: not pokreni.cmd, autostart-ukljuci.cmd, autostart-iskljuci.cmd or ELV-LPFR.exe. The old autostart-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.exe 0.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 old ELV-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.cmd and autostart-iskljuci.cmd from 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 old autostart-iskljuci.cmd deletes 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/status

What 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 contain sandbox.

2.1 How to edit .env

Some settings (port, reader, network mode) live in the .env file.

  1. The .env file 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 .env in 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 also LPFR_LAN_TRUST=). Some are empty.
  2. Open it in Notepad started as Administrator (Windows protects the Program Files folder; otherwise the change cannot be saved).
  3. Type the value after the = sign on the existing line. Do not add the same line a second time.
  4. Save the file as UTF-8.
  5. 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.exe and 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, the licenca\ folder) stays in place and must not be lost.
  • If something goes wrong, send C:\ProgramData\ELV LPFR\instalacija.log to 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").

ModeWho may send requestsX-ESIR-TokenChapter
"This computer only" („Samo ovaj računar", default)Only programs on the ELV LPFR computer (127.0.0.1, ::1)no3.1
"Network (LAN)" („Mreža (LAN)")Other computers on the network tooyes, for every request from another computer3.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" appnot from that subnet; yes for everyone else3.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.1 and ::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.1 gets HTTP 403. This protects against web pages that pose as a local program. Allowed are localhost, 127.0.0.1 and 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:

  1. 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=lan and ESIR_TOKEN=<at least 16 characters> in .env (chapter 2.1). The value in .env takes precedence over the page.
  2. 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).

  3. 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.
  4. In the ESIR, set the address http://<IP-address-of-the-ELV-LPFR-computer>:8888/api/v3. Every request must carry the header X-ESIR-Token: <token>.
  5. 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=8888

    What 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

HeaderWhenSourceNote
Content-Type: application/jsonPOST /invoices, POST /local-readout, POST /local-readout/applyPURSWithout it the request body is not read and the request is refused.
Accept-LanguagePOST /invoicesPURSen 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.
RequestIdPOST /invoices (recommended: always)PURSYour unique request ID. It is returned in the response header. Used by GET /invoices/{RequestId}.
X-ESIR-Tokenevery request from another computerELVNetwork 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 Origin header. This includes the renderer in Electron, Tauri and WebView.
  • POST /pin with a foreign Origin header 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 /invoices blindly.
  • 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):
    1. call GET /api/v3/invoices/{RequestId};
    2. HTTP 200: the invoice was issued. Use that answer;
    3. HTTP 404: the invoice was not stored. Before sending again, look at GET /status. If mssc contains 8204 (signing interrupted, recovery in progress), wait until the code disappears and repeat step 1;
    4. only then send the invoice again, with a new RequestId. Keep both IDs with the same receipt in the ESIR.
  • 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 2400 automatically. Read mssc first (chapter 6.3).
  • Do not send POST /pin in 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):

  1. 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.
  2. 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).

  3. 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.
  4. 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.
  5. 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/status

What 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_DEVICE and the message request 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: RequestId unique 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.

MethodPathSourcePurposeRequest bodyTypical answerCard / PIN
GET/attentionPURSIs ELV LPFR running—200, no bodyno / no
GET/statusPURS (mssc field ELV)State, codes, tax rates—200 JSON (always 200)no / no
POST/pinPURSUnlock the cardPIN as bare text, e.g. 1234 (also accepts {"pin":"1234"})200 "0100"; 423 "2100", "2110" or "1999"; 200 "1300" without a cardyes / —
GET/environment-parametersPURSSUF environment data—200 JSON; 400 {"code":"1300"} without a card; {} while no data has been fetchedyes / no
GET/device-infoELVManufacturer, code, version, name, serial number—200 JSONno / no
POST/invoicesPURSSign (fiscalise) an invoiceinvoice request (JSON object)200 result; 400 {message, modelState}yes / yes
GET/invoices/{RequestId}PURSFetch an issued invoice again—200 result; 404 {"error":"not found"}yes / yes
POST/local-readoutELVLocal readout to USB/SD{"dir":"E:/"}200 {folder, uid, exportedCount, ids, errorReport}yes / yes
POST/local-readout/applyELVApply {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 /invoices technically 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.

jsonc
{
  "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:

FieldMeaning
gscArray 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.
isPinRequiredtrue while the PIN has not been entered (or the last attempt was wrong).
auditRequiredtrue once unaudited turnover reaches 75% of the card limit (1400 is then in gsc too).
uidJID of the card that is in the reader now.
currentTaxRatesThe tax group valid now. Take the labels (label) for your articles from it.
allTaxRatesAll tax groups SUF delivered, with their validity dates.
taxCoreApiSUF address from the package. With the „Produkcija" package it does not contain sandbox.
lastInvoiceNumberNumber of the last invoice this device signed.
mrc, deviceSerialNumberThe device MRC: 8S-0002-<installation serial number>.
sdcDateTimeLocal time of the device, ISO 8601 with the time-zone offset.

4.2 GET /device-info — example [ELV]

json
{
  "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:

json
{
  "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

  1. When the ESIR starts: GET /attention (200 = ELV LPFR is running), then GET /status.
  2. If gsc contains 1300: tell the cashier "Insert the card into the reader". Wait until 1300 disappears.
  3. If gsc contains 1500, look at mssc first:
    • if mssc contains 8201 or 8202: 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.
  4. Read the valid tax labels from currentTaxRates. Check that every article has a label that exists.
  5. For every invoice: POST /invoices, with the headers Content-Type, RequestId and (optionally) Accept-Language. One invoice per request.
  6. Print the journal and the QR code from the answer. Store the whole answer with your receipt.
  7. While running: call GET /status periodically, 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-PIN with 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):

json
{
  "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 …):

jsonc
{
  "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.

FieldRequiredCheckNote
invoiceTypeyes0 Normal, 1 ProForma, 2 Copy, 3 Training, 4 Advance. Number or name, any letter case (otherwise 2805).
transactionTypeyes0 Sale, 1 Refund. Number or name (otherwise 2805).
paymentyesAt 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.
itemsyesEach 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[].labelsyesNon-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[].gtinno8 to 14 characters (2803).
cashiernoAt most 50 characters (2803).Printed as „Касир".
buyerIdnoIf sent, must not be empty (2805). At most 20 characters (2803). Printable ASCII only (2805).Format <type code>:<number>, e.g. 10:105255401.
buyerCostCenterIdnoAt most 50 characters (2801). Requires buyerId too (2800).„Опционо поље купца".
invoiceNumbernoIf sent, must not be empty (2805). At most 60 characters (2803).Printed as „ЕСИР број". Its content is defined by PURS for your ESIR.
dateAndTimeOfIssuenoISO 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).
referentDocumentNumberfor copy and every refundFormat XXXXXXXX-XXXXXXXX-N (2806), at most 60 characters. Missing when required: 2800.Number of the original invoice (invoiceNumber from its answer).
referentDocumentDTnoA 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.omitQRCodeGenno0 or 1 (2805).1 = verificationQRCode: null in the answer.
options.omitTextualRepresentationno0 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):

json
{ "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 ….

jsonc
{
  "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…"
}
FieldWhat it isWhat the ESIR does
invoiceNumberFiscal invoice number („ПФР број рачуна"), format JID-JID-ordinalPrint and store. Needed for refunds and copies.
sdcDateTimeFiscal 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.
invoiceCounterInvoice counter („Бројач рачуна"), e.g. 184/749ППPrint (it is already in the journal).
invoiceCounterExtension, totalCounter, transactionTypeCounterParts of the counterStore.
totalAmount, taxItemsTotal and tax per label, as computed by ELV LPFRStore. Use these amounts for reports, not your own calculation.
requestedBy, signedByCard JIDStore.
businessName, tin, locationName, address, districtTaxpayer data from the card certificatePrint (already in the journal header).
taxGroupRevision, mrc, messagesTax group revision, device MRC, "Success"Store.
signature, encryptedInternalDataSignature and encrypted internal data of the card (base64)Store.
verificationUrlAddress for checking the invoice at the Tax AdministrationStore. This is the content of the QR code. With a production card the address must not contain sandbox.
verificationQRCodeThe QR code as a GIF image, base64, without a data: prefixPrint as an image. For display, prepend data:image/gif;base64,.
journalInvoice text: 40 characters per line, lines separated by \r\nPrint 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]

  • en or any en-… (e.g. en-US): English journal ("FISCAL INVOICE", "Total Purchase", "SDC Time"…).
  • sr, any sr-… (including sr-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 (q values 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]

KindinvoiceType / transactionTypeWhat is differentCounter suffix
Normal sale0 / 0Ordinary invoice.ПП
Normal refund0 / 1referentDocumentNumber = 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 „Укупна рефундација".ПР
Copy2 / 0 or 1referentDocumentNumber is required. The journal starts and ends with „ОВО НИЈЕ ФИСКАЛНИ РАЧУН".КП / КР
Pro forma1 / 0 or 1Not a fiscal invoice (same caption). For a sale ELV LPFR does not require a reference.РП / РР
Training3 / 0 or 1Not a fiscal invoice (same caption). For a sale ELV LPFR does not require a reference.ОП / ОР
Advance sale4 / 0Advance invoice.АП
Advance refund4 / 1referentDocumentNumber 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.

json
{
  "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-000123

What 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 RequestId the ESIR sent, not by the invoice number. A call with invoiceNumber returns 404.
  • If the same RequestId was 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 /invoices with the same RequestId does 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 answer GET /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

PlaceForm
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 /pinA bare JSON string, e.g. "0100", with the header Content-Type: application/json.
GET /environment-parameters without a cardHTTP 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]

CodeMeaningWhereWhat the ESIR does
0100PIN accepted; device ready/status, /pinNothing.
0210Informational code ("Internet Available")/status, when the card is not in the reader or the PIN is not enteredIgnore it. Do not use it as an internet indicator.
1100Disk almost full (warning)/statusTell the operator to free space.
1300Card not in the reader/status; /pin (HTTP 200); /invoices, /environment-parameters (HTTP 400)"Insert the card", then ask for the PIN.
1400Readout required (75% of the card limit)/statusInvoices are still issued. Warn: check the internet and the Windows PIN window, or do a local readout.
1500PIN not entered/status; /invoices (HTTP 400)Look at mssc, then ask for the PIN (5.1, step 3).
1999General 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).
2100Wrong PIN/pin (HTTP 423)Show the error. Do not retry automatically.
2110Card locked (all PIN tries used)/pin (HTTP 423)The card is permanently locked. Contact the card issuer.
2210Secure Element locked: turnover limit reached/invoices (HTTP 400)No new invoices until a Proof of Audit: internet or local readout.
2220The card stopped answering in the middle of signing/invoices (HTTP 400)Do not resend blindly. Follow chapter 3.5.
2310Invalid tax label/invoices (HTTP 400), property = items[i].labels[j]Fix the article label using currentTaxRates.
2400Device not ready for signing/invoices (HTTP 400); /statusDo 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).
2800Required field missing/invoicesFix the request (the field is in property).
2801Field value too long/invoicesFix the request.
2803Invalid field length/invoicesFix the request.
2804Field value out of range/invoicesFix the request.
2805Invalid field value/invoicesFix the request. If property is empty: the computer clock is wrong (ahead of the correct time or set back).
2806Invalid data format/invoices; unknown path (HTTP 404); malformed JSONCheck the JSON and the path.
2808More than 12 tax categories on one invoice (ELV LPFR uses this code for that case)/invoicesSplit the invoice.
2809The card certificate has expired/invoicesThe 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: 1500 is already in gsc because the PIN is requested. This is not an invoice block;
  • — — no change.

Licence (81xx):

msscMeaninggsc
8101The licence expires within the warning window set in the licence (usually 14 days)—
8102The licence has not been renewed for at least 7 days (no connection to the licence server)—
8103Grace period: new invoices stop on the date shown on the operator page1999
8104The licence has expired2400
8105The licence is revoked (1999 until it takes effect, 2400 after)1999 / 2400
8106No valid licence for this card2400
8107The computer clock is off (warning only)—
8108Installation integrity check failed (blocks together with 8110)—
8109JID/PIB not read from the card certificate2400
8110The licence check could not be performed2400

Card protection (82xx):

msscMeaninggsc
8201PIN entry blocked after 2 wrong PINs; unlock on the operator page(1500)
8202The card has at most 2 PIN tries left; the PIN is entered only on the operator page(1500)
8203The store lacks invoices the card signed2400
8204Signing interrupted (power loss, card removed); recovery in progress2400
8205The card counter jumped (card used on another device); confirmation needed2400
8206The Tax Administration rejected at least one package (kept, not resent)1999
8207A tax label is blocked after a rejection (such items get 2310)1999
8208Systemic rejection (PIB, signature, MRC or certificate); every new invoice is refused2400
8209Tax rates from SUF failed the check; the other, correct table is used1999
8210The computer clock is more than 3 minutes off1999
8211The computer clock is ahead of the correct time; signing refused2400
8212The store cannot be written or has no space (less than 100 MB)2400
8213The backup copy of at least one package was not written1999
8214Another store or another instance holds this card2400
8215Environment mismatch (SUF settings / verification address / MRC)2400
8216PIB/JID not read from the card certificate2400
8217Packages are not being delivered to the Tax Administration1999
8218The card certificate expires within 30 days—
8219The PIN in the Windows window was not accepted1999
8220The card-protection check could not be performed2400

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 forgotten

ELV 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 /pin gets 423 "1999" (mssc 8201), 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" (mssc 8202). 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

HTTPBodyWhen
200JSONSuccess. 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 2806Unknown 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

SymptomCauseFix
"Windows protected your PC" at the first startThe 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 ZIPExtract 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-PFRClose 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 folderClose 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>:8888In "This computer only" mode ELV LPFR does not listen on the network addressUse http://localhost:8888/api/v3.
ESIR on another computer: HTTP 401No X-ESIR-Token header or a wrong tokenCopy the token from the operator page ("Show"). The header name must be exact.
Device in "This computer's local network (no token)" mode: HTTP 401The 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 computerThe ESIR uses a name that is not localhost, 127.0.0.1 or the computer nameUse 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 modeClick "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 bodyIn PowerShell curl is a different programType curl.exe.
No answer to POST /invoicesNetwork, timeoutDo not resend. GET /invoices/{RequestId} (3.5).

7.2 The API returns an error code

SymptomCauseFix
2400 on a new installation, mssc emptyTax 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 8215ELV LPFR's own environment settings do not agree with each otherDo 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 registerThe 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 2310The body is not UTF-8Send UTF-8.
400 with property invoiceType and 2805, although the field was sentContent-Type: application/json is missing, so the body was not readAdd the header.
2805 with an empty propertyThe computer clock is more than 5 minutes ahead (mssc 8211) or was set backTurn on time synchronisation in Windows and correct the time.
2210The card turnover limit is reachedProof 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 2210The Windows "Smart Card" window was not confirmed, or there is no internetConfirm 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 downInvoices 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

SymptomCauseFix
"Card not in the reader" („Kartica nije u čitaču") although the card is insertedThe 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 lockedContact the card issuer.
Production card, but verificationUrl or taxCoreApi contains sandboxThe test package (from support) is running with a production cardStop issuing invoices at once. Write to support. Install the „Produkcija" package from "Moje licence" (2.3).
2400, mssc 8104 or 8106The 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 8103Licence 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 workingA reinstall from the original package from "Moje licence" is needed. Write to support first. Do not delete the data folder.
Activation code rejectedTypo (16 characters, 4×4), the code was already used for another card, it has expired, or the card belongs to another PIBCheck 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 AdministratorTry again and confirm the prompt as an Administrator.
The e-mail with the activation codes did not arriveThe message is in spam, or the purchase was made with another e-mail addressCheck 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

WhatWhere
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 pagehttp://localhost:8888/ (only on the ELV LPFR computer; Serbian Latin, Cyrillic, English)
Documentation in the packagefolder 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/status and curl.exe http://localhost:8888/api/v3/device-info;
  • if needed, the error report: a local readout writes {JID}-errors.json to 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.