Templates

Every install ships with these. Each one is a block tree — no HTML, no CSS, no print stylesheet that behaves differently in one browser. Copy any of them, change what you need, and push it back with a new id.

ANAND TRADERS 14 Nehru Road, Coimbatore 641001 GSTIN 33ABCDE1234F1Z5 +91 98400 11223 ------------------------------------------------ Bill INV-2043 22-08-2026 18:41 Cust Ravi Kumar +91 90000 55555 ------------------------------------------------ Item Qty Rate Amount ------------------------------------------------ Masala Dosa 2 90.00 180.00 Filter Coffee 3 40.00 120.00 Curd Rice 1 110.00 110.00 ------------------------------------------------ Subtotal 410.00 incl. CGST 2.5% 9.76 incl. SGST 2.5% 9.76 TOTAL 410.00 ------------------------------------------------ Paid by UPI YBL2209 [ QR: upi://pay?pa=anandtraders@ybl ] Thank you. Visit again. - - - - - - - - - - - - - - - - - - - - - - - -

Retail receipt

pos80 · 48col
pos.receipt.retail

The default counter receipt: items, tax summary, payment mode, QR.

Item names wrap onto a second line rather than being truncated, because a customer who cannot read what they bought will ask, and asking costs more counter time than the extra line of paper.

Reads
sellernumberdatecustomerlines[]discountpaymentfooter
THE FILTER ROOM Race Course, Coimbatore GSTIN 33ABCDE1234F1Z5 ------------------------------------------------ Table 7 Covers 4 Bill R-1189 22-08-2026 21:07 Steward Suresh ------------------------------------------------ Item Qty Rate Amount ------------------------------------------------ Paneer Tikka 1 320.00 320.00 Butter Naan 4 55.00 220.00 Dal Makhani 1 280.00 280.00 Gulab Jamun (2) 2 90.00 180.00 ------------------------------------------------ Subtotal 1,000.00 Service charge 50.00 incl. CGST 2.5% 23.81 incl. SGST 2.5% 23.81 TOTAL 1,050.00 ------------------------------------------------ Service charge is optional. Ask to remove. Thank you. - - - - - - - - - - - - - - - - - - - - - - - -

Restaurant bill

pos80 · 48col
pos.receipt.restaurant

Table, server, covers, and a service-charge line above tax.

Service charge sits above the tax lines and is labelled as optional, which is both the legal position in India and the thing guests query most often at the table.

Reads
sellertableservercoverslines[]service_chargepayment
================================================ TABLE 7 KOT 4412 Steward Suresh 21:07 Course: MAIN ================================================ 2 PANEER TIKKA - less spicy 4 BUTTER NAAN 1 DAL MAKHANI ================================================ *** NEW ORDER *** - - - - - - - - - - - - - - - - - - - - - - - -

Kitchen order ticket

pos80 · 48col
pos.kot.kitchen

Double-height items, no prices, one ticket per course.

Prices are deliberately absent and item names print at double height: a KOT is read at arm’s length across a hot pass, by somebody who does not care what it costs.

Reads
tableservercourselines[]notes
THE FILTER ROOM TOKEN A-47 Counter 2 21:09 Please wait for your number to be called - - - - - - - - - - - - - - - -

Token slip

pos58 · 32col
pos.token.queue

One enormous number, and nothing else that matters.

The number prints at quadruple height and is the only thing above the fold, because the slip is read from a queue three metres away.

Reads
tokencounterissued_atnote
MASALA DOSA MIX 500G SKU DOSA-MSL MRP 145.00 99.00 per pack [|||| |||| ||| ||||||] 8901234567890 - - - - - - - - - - - - - - - -

Shelf / price label

pos58 · 32col
pos.label.price

Name, MRP, your price and a barcode, sized for a shelf edge.

Prints the barcode with the ESC/POS native command rather than as an image, so it comes out at the printer’s own resolution and actually scans.

Reads
nameskumrprateunitbarcode

GST tax invoice

a4 · 96col
a4.invoice.gst

Two copies, HSN-wise tax breakup, amount in words, signature block.

Lays out CGST/SGST for an intra-state sale and IGST for inter-state, chosen from the two GSTINs rather than from a flag you have to remember to set.

Reads
sellercustomernumberdateplace_of_supplylines[]termsbanksignature

Simple invoice

a4 · 96col
a4.invoice.simple

No tax columns. For anyone not registered, or billing abroad.

Same block tree as the GST invoice with the tax section removed, so a shop that registers later keeps its layout and only changes the template id.

Reads
sellercustomernumberdatelines[]notes

Quotation

a4 · 96col
a4.quotation

Validity, lead time and terms, with prices marked as an estimate.

Carries a validity date in the header rather than the footer: a quotation whose expiry is buried under the terms is a quotation that gets honoured six months later.

Reads
sellercustomernumberdatevalid_untillines[]terms

Delivery challan

a4 · 96col
a4.challan.delivery

Goods, quantities and a receiver’s signature. No money.

Amount columns are omitted entirely rather than zeroed, because a challan showing values invites the exact argument at the gate that a challan exists to avoid.

Reads
sellerconsigneenumberdatevehiclelines[]reason

A5 invoice

a5 · 68col
a5.invoice.compact

The GST invoice folded onto half a sheet, for a dot-matrix tray.

A5 is what a lot of Indian counters actually keep loaded, so this is a first-class layout rather than an A4 scaled down until the tax table stops being readable.

Reads
sellercustomernumberdatelines[]

Writing your own

A template is a JSON document with a list of blocks. Every string may contain {{ expression }} over the payload you send, with filters for money, dates and amount-in-words. The renderer walks the same tree three ways — to ESC/POS bytes, to a PDF page, and to an HTML preview — so a layout that looks right in the preview is right on paper.

Push one from your web app and it lands on that machine only. Push it with a built-in's id and it shadows the built-in, which is how a single shop gets its own receipt without you forking anything.

Every block type and filter →
a custom 80mm receipt
await printol.saveTemplate({
  id: 'pos.receipt.mine',
  name: 'My receipt',
  paper: 'pos80',
  kind: 'pos',
  blocks: [
    { type: 'text', value: '{{ seller.name }}', align: 'center', bold: true, size: 'double' },
    { type: 'text', value: '{{ seller.address }}', align: 'center' },
    { type: 'rule' },
    { type: 'keyvalue', pairs: [
        { label: 'Bill', value: '{{ number }}' },
        { label: 'Date', value: '{{ date | date("dd-MM-yyyy HH:mm") }}' }
    ] },
    { type: 'table', rows: '{{ lines }}', columns: [
        { key: 'name',   label: 'Item',   weight: 5 },
        { key: 'qty',    label: 'Qty',    weight: 1, align: 'right' },
        { key: 'amount', label: 'Amount', weight: 2, align: 'right', money: true }
    ] },
    { type: 'rule' },
    { type: 'total', label: 'TOTAL', value: '{{ total | money }}' },
    { type: 'qr', value: '{{ pay_url }}', size: 6 },
    { type: 'text', value: '{{ footer }}', align: 'center' },
    { type: 'feed', lines: 2 },
    { type: 'cut' }
  ]
});