jtlsrv
Built on libuv (event loop), OpenSSL (TLS), llhttp (HTTP parsing), unixODBC + ODBC Driver 18 for SQL Server (database), and libvips (image thumbnails). Blocking work (ODBC queries, image processing) runs on libuv worker threads.
Requirements
| Dependency | Purpose |
|---|---|
| C++17 compiler | gcc or clang |
| GNU Make | Build |
| pkg-config | Dependency flags |
| libuv | Async I/O and thread pool |
| OpenSSL | TLS |
| libvips | Product/category image resizing |
| unixODBC + dev headers | ODBC runtime |
| ODBC Driver 18 for SQL Server | Connect to JTL-Wawi (MSSQL) |
Vendored in vendor/: llhttp, nlohmann/json (no install needed).
Install on Ubuntu / Debian
sudo apt install \
build-essential make pkg-config \
libuv1-dev libssl-dev libvips-dev unixodbc-dev
Install Microsoft's ODBC driver (required for MSSQL):
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | \
sudo gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-prod.gpg] \
https://packages.microsoft.com/ubuntu/$(lsb_release -rs)/prod $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/mssql-release.list
sudo apt update
sudo ACCEPT_EULA=Y apt install msodbcsql18
Build
make
The binary is written to ./jtlsrv. After code changes always run make before starting the server.
Debug build:
make debug
Configuration
Copy the example env file from the repo root and edit as needed:
cp ../.env.example .env
Key settings:
| Variable | Default | Description |
|---|---|---|
PORT |
4443 |
HTTPS listen port |
PAIRING_CODE |
307018 |
Code shown to the POS during pairing |
AUTH_TOKEN |
(built-in default) | Device auth token after pairing |
MSSQL_* |
— | JTL-Wawi database connection |
MANDANT_* |
— | Mandant metadata returned to the client |
ROOT_CATEGORY_ID |
1 |
Root category for sync |
TAX_ZONE_NAME |
Zone-EU |
Tax zone for product prices |
LOG_FILE |
logs/requests.log |
Request log path |
ORDER_LOG_FILE |
logs/orders.log |
Order log path |
The server starts without MSSQL if MSSQL_USER is unset or the connection fails — pairing and handshake still work, but catalog sync from the database is unavailable.
TLS certificates
From the repo root (preferred — picks up LAN IPs automatically):
npm run cert
# optional extras:
npm run cert -- 192.168.188.22 sync.quixpos.com
Or manually:
mkdir -p certs
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
-keyout certs/key.pem -out certs/cert.pem -days 3650 \
-subj '/CN=localhost/O=JTL POS Sync/C=DE' \
-addext 'subjectAltName=DNS:localhost,DNS:sync.quixpos.com,IP:127.0.0.1,IP:0.0.0.0,IP:192.168.188.22'
Place certs/cert.pem and certs/key.pem relative to the working directory when you run the binary. The browser hostname check requires the address you open (192.168.x.x or a DNS name) to appear in the certificate SAN — trusting a CA alone is not enough.
API endpoints
| Method | Path | Description |
|---|---|---|
| GET | /v1/client |
Client discovery / pairing |
| GET | /v1/init |
Init handshake |
| GET | /v1/category |
Category sync |
| GET | /v1/product |
Product sync |
| GET | /v1/productcomposite |
Composite product sync |
| GET | /v1/deletedentity |
Deleted entity sync |
| GET | /v1/customergroup |
Customer group sync |
| POST | /v1/order |
Submit orders |
| GET | /v1/pimage |
Product image (resized) |
| GET | /v1/cimage |
Category image (resized) |
Project layout
Makefile
src/
main.cpp Entry point, route registration, startup
config.hpp .env loader
tls_server.{hpp,cpp} HTTPS over libuv + OpenSSL
http.{hpp,cpp} llhttp request/response handling
router.{hpp,cpp} Route dispatch
pairing.{hpp,cpp} In-memory pairing store
endpoints/ HTTP handlers
queries/ SQL query builders (header-only)
db/pool.{hpp,cpp} ODBC connection pool
vendor/ llhttp, nlohmann/json