Everything it does

Printol is two things in one install: a print server your web app drives over loopback, and a small point-of-sale application the shop can use on its own. They share one local database, so neither has to be kept in sync with the other.

One payload, any paper

The single design decision the whole product rests on: your app sends business data, never layout. The bridge owns the layout, so a shop that swaps a 58mm roll for an 80mm one, or starts printing A4 for B2B customers, does not need you to ship anything.

the same bill, two papers
// The same object, the same call. Only the printer differs.
await printol.print({ templateId: 'pos.receipt.retail', printerId: thermal, data: bill });
await printol.print({ templateId: 'a4.invoice.gst',     printerId: laser,   data: bill });

Printing

Thermal ESC/POS
58mm and 80mm rolls, at 32 and 48 columns. Alignment, bold, double height and width, native QR and barcode commands, partial and full cut.
A4 and A5 documents
Rendered to PDF inside the bridge and spooled. The PDF is kept, so your app can also offer it as a download without regenerating anything.
Cash drawer
The drawer pulse, on either pin, with a tunable duration for solenoids that need a longer kick.
Copies and duplicates
Ask for two copies and get two, with the second marked DUPLICATE if the template says so.
Raw passthrough
Already have ESC/POS or ZPL from somewhere else? Send it base64 and the bridge will spool it untouched.

Transports

System spooler
Whatever the OS already knows about: USB thermal printers, shared printers, the office laser. Raw byte streams go through the spooler in RAW mode so nothing is re-rendered.
Network (port 9100)
JetDirect-style raw TCP, for a printer sitting on the shop LAN with its own IP.
File
Writes the byte stream to disk instead of a printer. This is how you develop a template on a laptop with no hardware attached.

Templates

Block trees, not markup
A template is a JSON list of blocks — text, rule, table, key/value, QR, cut. The same tree drives the thermal renderer, the PDF renderer and the HTML preview.
One expression syntax
Values are {{ handlebars-style }} expressions over your payload, with filters for money, dates, uppercase and amount-in-words.
Column widths that hold
Table columns are weights, not character counts, so the same table lays out at 32, 48 or 96 columns without editing.
Override a built-in
Push a custom template with a built-in`s id and it shadows it. Delete the custom one and the built-in comes back.

The desktop app

Catalog and stock
Items with SKU, unit, tax rate, MRP and rate. Stock is a movement ledger with a reason on every row, so a discrepancy can be traced rather than argued about.
Billing
Keyboard-first sale screen, split payments, held bills, reprint. Everything it writes is visible through the API immediately.
Reports and export
Day book, item-wise and payment-wise totals, and a CSV export of the raw billing data — the shop owns their numbers.
Runs at login, lives in the tray
Installed as a startup item. Closing the window leaves the bridge running; quitting is a deliberate act from the tray menu.

Integration

Port-range discovery
No configuration screen. The bridge takes the first free port in 47600–47619 and the SDK finds it.
OpenAPI, served locally
The running bridge serves its own OpenAPI 3.1 document, so you can generate a client against the exact build in front of you.
Server-sent events
Subscribe to job transitions and printer changes instead of polling.
Idempotency keys
Send the same key twice and the second call returns the first job. A retry after a flaky response does not print the bill twice.

What it deliberately does not do

  • No cloud sync. The shop's data stays on the shop's machine. If you need it in the cloud, your web app already has it — you sent it.
  • No remote access. The listener never binds anything but loopback, so there is no way to reach it from another computer, by design.
  • No driver bundling. Printers are reached through the OS spooler or raw TCP. If Windows can print to it, so can Printol.
  • No confirmation that ink hit paper. A job reports done when the spooler accepted it. Consumer printers do not tell anybody more than that, and pretending otherwise would be a lie in your UI.