Skip to content

Abhard Configuration Reference

Settings live in abhard.yaml. A configuration the service creates for itself holds no devices, and its whitelist is widened to the /24 of whichever network card the service could identify.

An example covering every supported device ships with the program — /usr/share/doc/abhard/examples/abhard.yaml.example on Linux, C:\Program Files\Abacus\Tools\examples\abhard.yaml.example on Windows.


The main block

Key Default Description
port 4601 Port the service listens on
whitelist 127.0.0.1 Allowed addresses, semicolon-separated. Accepts single addresses (127.0.0.1), ranges (172.27.0.2-10) and subnets (192.168.50.0/24)
event_socket true Enable the event channel
event_socket_host detected automatically The address the service hands to cash desks as the event-channel endpoint
event_socket_port 4651 Event channel port
event_socket_ping_idle 4 Seconds of silence after which the cash desk is pinged
language uk Language of the device states and errors users see. The translation is read from lang/abhard.<language>.po next to the program; an empty value means English

Log settings live in a separate log block - see Logs.

The event channel

The event channel is a permanent TCP connection over which the service pushes barcode scans and other service information to the cash desk on its own. The program that connected last gets the scanned codes. The connection is made when a program starts and when each program in the "Abacus" suite (Cashdesk, Sklad, Service, Barcom) is activated. It disconnects only when the program closes. So if you simply minimized the program, or opened another program that is not part of "Abacus" (a browser, a text editor, etc.), the program keeps receiving scanned codes. This is very convenient when you need to work in Cashdesk or Sklad and in a supplier's price list at the same time.

If the active program does not answer a ping within two seconds, it is considered gone and is disconnected. If another program was running at that point, it is not activated.

This is done specifically so that a frozen Cashdesk does not block the channel, while at the same time codes do not suddenly start being sent to a long-forgotten Sklad that is still running.

The service listens on every network card but advertises exactly event_socket_host to the cash desk. Automatic detection takes the first 192.168.* address, then any non-local one, and only then 127.0.0.1. On a machine with several network cards it can pick the wrong one: the cash desks then receive an unusable address and never connect — set it explicitly in that case.


Devices

devices is a sequence; each entry describes one device.

Key Required Description
name Yes Device name; the cash desk and the log refer to the device by it. An entry without a name is skipped
type Yes scaner, printer, scales, prro
subtype Yes See below; not needed for scales

The remaining keys depend on the type/subtype pair. Valid pairs: scaner/serial, scaner/hid, scaner/devfile, printer/escpos, printer/dummy, scales, prro/eusign, plus any type with subtype: redirect. An unknown pair is skipped with a warning in the log — the service starts, the device simply is not there.

The scanner type is spelled scaner, with one n. scanner is an unknown type.

Shared RS-232 parameters

Apply to scaner/serial and to scales.

Key Default Description
device — Serial port: /dev/ttyS0, COM1
baudrate 9600 Baud rate
bits 8 Data bits
parity N N · E · O · S · M
stopbits 1 Stop bits
softflow false XON/XOFF flow control
hardflow false RTS/CTS flow control

scaner/serial

Barcode scanner on a serial port. It takes no parameters beyond the RS-232 ones. While the device file is missing the scanner reports "Not found" and the service retries every second — a scanner unplugged and plugged back in recovers on its own.

scaner/hid — Linux only

USB scanner driven directly through libusb.

Key Default Description
vendor_id — Vendor code, hexadecimal, no 0x prefix: 0536
product_id — Model code, same form: 01b3

lsusb prints both.

scaner/devfile — Linux only

USB scanner read through a device file.

Key Default Description
device — Device file path: /dev/hidraw0

printer/escpos

ESC/POS receipt printer.

Key Default Description
device — Device file: /dev/usb/lp0, COM2
width 40 Characters per line; long lines wrap and separator rules are drawn to this width
codepage (none) Printer codepage number. If unset, the printer keeps whatever it is currently set to
softrender false true — the service draws the QR code and sends it as an image; needed for printers with no QR command of their own
feed_lines 3 Lines to feed before the receipt is cut

printer/dummy

Saves receipts as text files instead of printing them. Useful for checking the cash desk configuration where there is no printer yet.

Key Default Description
target_dir (none) Where to put the files. If unset, the receipt goes to the log
width 40 Characters per line

scales

Scales on a serial port. They need no subtype.

Key Default Description
model VTA16 VTA16 or DigiDS
timeout 5000 Milliseconds to wait for the scales before returning an error

Plus the RS-232 parameters; device defaults to /dev/ttyS0 for scales.

prro/eusign

Ukrainian software fiscal register. What the cash desk does with it is covered in the PRRO section.

Key Default Description
key_path — Private key file
key_password — Key passphrase
certs_path program directory Directory with certificates. The service creates it if missing and fills it itself — see below
lib_path /opt/abacus/lib/ Signing library directory. If it does not exist, the lib/ subdirectory of the program directory
proxy_address (none) Proxy server through which the tax service is reachable
proxy_port 0 Proxy port
proxy_user (none) Proxy user
proxy_pass (none) Proxy password
timeout_ms 30000 Milliseconds to wait for the tax service
http_retries 2 How many times to repeat a request that did not get through
http_retry_delay_ms 1000 Pause between retries

A path that does not start at the root or a drive letter is resolved against the program directory.

Proxy. The service passes the same proxy_address/proxy_port to two different clients: its own, for the tax service, and the signing library, for the providers' servers. The first expects SOCKS, the second HTTP. So a single entry must point at a proxy that understands both protocols; otherwise only one of the two directions works. If you don't need a proxy, don't set it at all: an empty value explicitly turns it off in the library's settings, so an old value doesn't stay in effect.

Which certificates go into certs_path

None. The key file and its password are enough.

The service creates the directory itself if it is missing, and downloads everything it needs from the provider's server on first start. Verified with keys from three different providers: empty directory, and in 7-50 seconds the key is read and the device works.

  - name: 'main_prro'
    type: 'prro'
    subtype: 'eusign'
    key_path: 'keys/pb_0123456789.jks'
    key_password: 'Password1234'
    certs_path: 'cert/'          # the directory need not exist yet

How it works: if the key fails to read, the service takes the provider directory (CAs.json) and queries the CMP servers of every accredited provider until one of them returns certificates for this specific container. The certificates received are stored in certs_path, and reading the key is retried. If that still doesn't help, the shared CACertificates.p7b bundle is downloaded and reading is retried once more.

This happens only when the key fails to read. A working device with a filled directory never touches the network at all.

For this to work the service must be able to reach the providers' servers (iit.com.ua and the provider's own site) over plain HTTP. The certs_path directory must be writable by the service.

This section used to require placing three files by hand. That is no longer needed, but it doesn't hurt either: if the certificates are already in the directory, the service downloads nothing.

If the key still doesn't read

Steps in order, cheapest first.

1. Check the password. Error 24 or 36 is a password or a corrupted key file. Certificates have nothing to do with it, and the service doesn't even try to download anything: the log shows Not repairing the store ... the key container itself did not open.

2. Check the age of the signing library. This is the most common cause of error 50 in 2026. Providers switched to a new signature algorithm (DSTU 7564), and a 2020-vintage library doesn't know it — and reports this not as "unsupported algorithm" but as an ordinary "certificate is corrupted". The tell: keys from some providers work while freshly issued keys from others don't.

strings /opt/abacus/lib/euscp.so | grep -c '1\.2\.804\.2\.1\.1\.1\.1\.3\.6\.'

0 means the library is old and needs updating; any other number means the library isn't the issue. How to update it is covered in the technical docs (daemons/docs/eusign_library.md, "Updating the library" section).

3. Check network access. Could not fetch certificates ... error 5 in the log means the CMP servers are unreachable: no internet, or a proxy is set that the library doesn't understand (see the proxy note above).

Checking the owner's certificate

Owner, issuer and validity — for when you need to know whose certificate this is and whether it is still valid:

$c = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 'C:\Abacus\Tools\cert\FILE.crt'
$c.Subject; $c.Issuer; $c.NotBefore; $c.NotAfter
openssl x509 -inform DER -in /opt/abacus/etc/cert/FILE.crt \
  -noout -subject -issuer -dates

To look inside a bundle:

openssl pkcs7 -inform DER -in CACertificates.p7b -print_certs -noout

What the log shows during PRRO startup

The lines appear in this exact order. A successful device startup is about a dozen lines; if there are more, look for an error among them.

Log line What has already happened
Created cert store <path> for <name> the certificate directory didn't exist, the service created it
PRRO <name> using key <path> (<N> bytes), certs <path>, lib <path> paths parsed; shows exactly which key file was picked
EUSign proxy set to <address>:<port> ... the library's proxy is configured; the line is absent if no proxy is set
EUSign for <name>: offline <on/off>, check CRLs <on/off>, auto download CRLs <on/off>, OCSP <on/off>, CMP <on/off> the library's mode of operation; OCSP and CMP server addresses are shown only when they are enabled
Cert store <path>: <N> files, library accepted <M> end-user certificates two different numbers: files in the directory, and end-user certificates the library accepted. They don't match — CA and server certificates are counted separately, and one .p7b bundle holds many certificates
Key container <path> opens on its own, <N> bytes of key info the container is intact and the password is correct
Reading the private key for <name> reading the key together with the certificates. If the log stops right here, the library has hung on this call, not the service crashing
Key certificate <N>: serial <number>, issued by "<issuer>" certificates the library matched to the key; use the issuer to find the provider
Key loaded for <name>: <owner>, expires <date>, earliest of <N> own certificates key read successfully; the date is the earliest expiry among its certificates
Device <name> initialized successfully. the device is ready

If the key fails to read, instead of the last two lines there is an error, followed by a list of every end-user certificate the library can see:

Log line What it means
ReadPrivateKeyFile failed for <name>, error <code>: <description> the error code from the library; the most important ones are below
Store certificate <N>: subject "<owner>", serial <number>, issued by "<issuer>" what's actually in the store; look here for the key's owner
Not repairing the store for <name>: the key container itself did not open wrong password or corrupted key file — there's no point downloading certificates
Fetching CAs.json for <name> from <address> the provider directory is being downloaded
Skipping <N> unreachable CMP servers for <name> this many provider servers didn't answer the connection; the rest will be queried
Fetching certificates for <name> from <N> CMP servers querying provider servers; takes up to half a minute
Installed <N> bytes of certificates for <name> from the issuer certificates received and saved to certs_path
Retrying key read for <name> after repair step <N> retrying the key read: 1 after the provider's certificates, 2 after the shared bundle
Could not fetch certificates for <name> from the issuer, error 5 the provider servers are unreachable — network or proxy
Not fetching certificates for <name>: EUSign is offline certificates were not downloaded because the library is running offline
Device <name> is still initialising after 30 s and is not usable the library never returned control; the device is marked failed, the service keeps running

Two error codes come up most often, and they must not be confused:

Code Description from the library What to do
51 Certificate not found a directory problem, not a key problem: the issuer chain doesn't resolve. The service usually fixes this on its own; if not, the provider servers are unreachable
50 Certificate is corrupted or cannot be used the certificate was found but is rejected. The most common cause in 2026 is an old signing library that doesn't know the provider's new algorithm; see step 2 above. Less often, the validity period has expired or the certificate was issued for a different key
24, 36 invalid password or corrupted key password or key file. Certificates are irrelevant

The word "certificate" in both descriptions refers to the certificate, not the key file — yet the service's own message says "Failed to read private key", and because of this a working container has been swapped out for nothing more than once. Two keys long believed corrupted turned out to be entirely fine: they just needed a fresh library.

subtype: redirect

A device physically attached to another cash desk — scanner, printer, scales or PRRO. Instead of working with hardware the service returns the address of that abhard, and the request is carried out there.

Key Default Description
redirect_url — Base address of the remote abhard
redirect_name — Name of the device on it
redirect_token — Token code of the remote abhard. Without it the request goes unauthenticated

subtype: redirect overrides type, so the rest of that type's parameters have no effect here. What this requires on the Launcher side is covered in the Launcher section.


Access tokens

Neither the installer nor the administrator creates the abhard.json token file. The service starts out unclaimed, and the first admin client takes it over: activating the services in the Sklad configuration editor (or initialising from the Launcher) receives an administrator token from the service, then issues one token per role and stores them in the database under mnemonic codes. No key is ever copied by hand.

Sklad lists every issued token with its code: the employee reference, "Токени" tab. That is where the code for redirect_token comes from.

A service can only be claimed while the token file is absent. After that a previously issued administrator token is required, and a repeated initialisation answers "already initialised".

Role Permissions
administrator Everything, including issuing and revoking tokens
worker All hardware operations; cannot issue or revoke tokens
probationer Same as worker, but cannot produce a Z-report

A token with no expiry date never expires. An expired token is rejected and removed from the file at once.


Example

main:
  port: 4601
  whitelist: '127.0.0.1;192.168.50.0/24;172.27.0.2-10'
  event_socket: true
  event_socket_host: '192.168.50.10'
  event_socket_port: 4651
  event_socket_ping_idle: 4

log:
  file: 'abhard.log'
  level: 3
  maxsizekb: 10240
  keepfiles: 10

devices:
  - name: 'main_scaner'
    type: 'scaner'
    subtype: 'serial'
    device: '/dev/ttyS0'
    baudrate: 9600

  - name: 'usb_scaner'
    type: 'scaner'
    subtype: 'hid'
    vendor_id: '0536'
    product_id: '01b3'

  - name: 'main_printer'
    type: 'printer'
    subtype: 'escpos'
    device: '/dev/usb/lp0'
    width: 42
    feed_lines: 3

  - name: 'shared_printer'
    type: 'printer'
    subtype: 'redirect'
    redirect_url: 'http://192.168.50.4:4601'
    redirect_name: 'main_printer'
    redirect_token: 'abhard_<neighbour profile>_worker'

  - name: 'main_scales'
    type: 'scales'
    device: '/dev/ttyS1'
    model: 'DigiDS'
    timeout: 5000

  - name: 'main_prro'
    type: 'prro'
    subtype: 'eusign'
    key_path: 'keys/pb_0123456789.jks'
    key_password: 'Password1234'
    certs_path: 'cert/'

The cert/ directory need not exist yet — the service creates and fills it itself.


Checking it works

$KEY is any valid token of the service.

curl -H "X-API-KEY: $KEY" http://192.168.50.10:4601/api/status

One record per device: name, type, state and last error. A device missing from the answer was never created — look for the warning in the log. /api/list returns every available request.

PRRO has a connectivity check of its own:

# check now (the numbers in the answer are per-stage timings)
curl -H "X-API-KEY: $KEY" http://192.168.50.10:4601/api/prro/main_prro/selftest/run

# recent document submission attempts
curl -H "X-API-KEY: $KEY" "http://192.168.50.10:4601/api/prro/main_prro/history?limit=20"

After three consecutive failures the service runs that check by itself; the result stays available at /api/prro/<name>/selftest.

A 401 means a missing or invalid token; a 403 means an address absent from the whitelist, or an action this token's role may not perform.