Skip to main content
Version: 1.x

Receipt Data Reference

WCPOS logicless HTML templates and thermal XML templates render from the same canonical receipt payload. Use Mustache dot paths such as {{order.number}}, {{store.name}}, and {{totals.total_display}}. Arrays are rendered with sections:

{{#lines}}
{{name}} x {{qty}} — {{line_total_display}}
{{/lines}}

The canonical contract is produced by the WCPOS receipt data builder on the server and mirrored by the offline receipt renderer in the app. Receipts open immediately from local data, then upgrade to the server response when it is available, so custom templates should use the fields below rather than PHP order methods.

Receipt Data v1.1 adds recorded regular-price, pre-coupon selling-price, and savings fields for each product line. It also provides order-level savings totals, including a Total saved value that combines regular-price savings with WooCommerce discounts without changing order totals or reports.

The receipt, mapped

Every part of a printed receipt comes from one section of the data contract. Hover either side to see the match; click to jump to that section's fields. All examples on this page use the same sample order.

Common recipes

Most template edits are one of these three. Each card shows the printed result first, then the exact markup — copy it into any logicless HTML or thermal XML template. The third card shows a pre-v1.9 legacy order rather than the sample order above.

2 × Espresso Beans29.00
34.00 · Savings −5.00
Strike through the regular price
{{#lines}}
{{#line_savings}}
  <s>{{line_regular_total_display}}</s>
  {{i18n.savings}}: -{{line_savings_display}}
{{/line_savings}}
{{/lines}}
The section guard hides everything on orders without recorded price history.
TOTAL59.97
Total saved10.28
Add a Total saved row
{{#totals.total_saved_complete}}
{{#totals.total_saved}}
  {{i18n.total_saved}}:
  {{totals.total_saved_display}}
{{/totals.total_saved}}
{{/totals.total_saved_complete}}
Two guards: the row disappears when price history is incomplete or nothing was saved.
1 × Espresso Beans14.50
17.00 Discount −2.50
Reprint a pre-v1.9 order safely
{{#lines}}
{{#line_savings}}
  {{^savings_in_discounts}}
    {{i18n.savings}}: -{{line_savings_display}}
  {{/savings_in_discounts}}
{{/line_savings}}
{{/lines}}
Old orders carry the saving inside the discount — this stops it printing twice.

Rendering rules

Currency fields

Numeric money fields are preserved as numbers and the renderer adds locale-aware _display fields for template output:

Numeric fieldDisplay field
totals.totaltotals.total_display
lines[].line_totallines[].line_total_display
payments[].amountpayments[].amount_display
tax_summary[].tax_amounttax_summary[].tax_amount_display

Prefer _display fields when printing receipts. Use numeric fields only for conditional sections or machine-readable output.

Tax display-aware fields

Several fields have inclusive and exclusive variants plus a display-side convenience value. The convenience value follows the store's cart tax display setting.

Convenience fieldInclusive fieldExclusive field
lines[].regular_pricelines[].regular_price_incllines[].regular_price_excl
lines[].selling_pricelines[].selling_price_incllines[].selling_price_excl
lines[].unit_savingslines[].unit_savings_incllines[].unit_savings_excl
lines[].line_regular_totallines[].line_regular_total_incllines[].line_regular_total_excl
lines[].line_selling_totallines[].line_selling_total_incllines[].line_selling_total_excl
lines[].line_savingslines[].line_savings_incllines[].line_savings_excl
lines[].unit_pricelines[].unit_price_incllines[].unit_price_excl
lines[].unit_subtotallines[].unit_subtotal_incllines[].unit_subtotal_excl
lines[].line_subtotallines[].line_subtotal_incllines[].line_subtotal_excl
lines[].discountslines[].discounts_incllines[].discounts_excl
lines[].line_totallines[].line_total_incllines[].line_total_excl
fees[].totalfees[].total_inclfees[].total_excl
shipping[].totalshipping[].total_inclshipping[].total_excl
discounts[].totaldiscounts[].total_incldiscounts[].total_excl
totals.subtotaltotals.subtotal_incltotals.subtotal_excl
totals.discount_totaltotals.discount_total_incltotals.discount_total_excl
totals.sale_savings_totaltotals.sale_savings_total_incltotals.sale_savings_total_excl
totals.total_savedtotals.total_saved_incltotals.total_saved_excl
totals.totaltotals.total_incltotals.total_excl

Date objects

Date fields are objects with multiple preformatted variants. This avoids doing date formatting inside Mustache.

FieldDescription
datetime, date, timeDefault date/time strings
datetime_short, datetime_long, datetime_fullLocale-aware combined formats
date_short, date_long, date_fullLocale-aware date-only formats
date_ymd, date_dmy, date_mdyFixed-order date formats
weekday_short, weekday_longDay names
day, month, month_short, month_long, yearIndividual date parts

Available date objects: order.created, order.paid, order.completed, order.printed, and refunds[].date. order.printed is refreshed at render time, which is useful for reprints.

Top-level sections

SectionTypeDescription
orderobjectOrder identity, status, dates, note, and payment URL information
storeobjectStore identity, address, contact details, tax IDs, logo, hours, and footer text
cashierobjectUser who processed the order
customerobjectCustomer display name, addresses, and tax IDs
linesarrayProduct line items
feesarrayFee rows
shippingarrayShipping rows
discountsarrayCoupon/discount rows
totalsobjectOrder totals, payment totals, refund summary, and item counts
taxobjectTax display mode flags for section guards
tax_summaryarrayPer-rate tax summary rows
has_tax_summarybooleanConvenience guard for tax_summary
paymentsarrayPayment rows
refundsarrayRefund records applied to the order
fiscalobjectFiscal snapshot fields populated by fiscal integrations
presentation_hintsobjectFormatting and renderer hints
i18nobjectTranslated labels for bundled and custom templates

How the prices relate

One product line carries several prices, and the names make sense once you see them on the money itself. This is the espresso line from the sample order — a $17.00 product on sale for $14.50, with a 10% coupon on top:

Espresso Beans — one unit (the order has two)
0regular price 17.00
What the customer paysunit_price → 13.05 · line_total → 26.10
Coupon discount (SUMMER10)lines[].discounts → 2.90 on this line
Savings vs regular priceunit_savings → 2.50 · line_savings → 5.00
Sale savings across the ordertotals.sale_savings_total = 5.00
All coupon discounts across the ordertotals.discount_total = 5.28
Savings + discounts, legacy overlap removedtotals.total_saved = 10.28

Sale savings and coupon discounts are different things: sale savings compare the selling price with the recorded regular price, while discounts is WooCommerce's own coupon arithmetic. WooCommerce order totals and reports only ever contain the coupon part — which is why total_saved exists as the one customer-facing figure that combines both.

Field reference

The full field reference is grouped by section below. Everything is collapsed by default — expand the group you need.

order — identity, status, dates

order

FieldTypeExample / description
order.idnumber1042
order.numberstringHuman-facing order number, e.g. "1042"
order.currencystringISO currency code, e.g. "USD"
order.customer_notestringCustomer/order note
order.wc_statusstringRaw WooCommerce status slug, e.g. "processing"
order.status_labelstringLocalised status label, including custom statuses
order.created_viastringSource/channel, e.g. "woocommerce-pos"
order.needs_paymentbooleanWhether a payment section should be shown
order.payment_urlstringOrder payment URL when available
order.createddate objectOrder creation date
order.paiddate objectPaid date, empty strings when not paid
order.completeddate objectCompleted date, empty strings when incomplete
order.printeddate objectRender-time print/reprint timestamp
store — identity, address, contact, hours

store

FieldTypeExample / description
store.idnumberStore ID, or historical ID for deleted stores
store.namestringStore display name
store.address.address_1stringStreet address line 1
store.address.address_2stringSuite/unit line
store.address.citystringCity/locality
store.address.statestringState/region
store.address.postcodestringPostal code
store.address.countrystringISO country code
store.address_linesarrayPreformatted address lines; recommended for most templates
store.tax_idsarrayStructured business tax IDs; loop this instead of using a single tax ID
store.phonestringStore phone
store.emailstringStore email
store.logostring/nullStore logo URL or data URI
store.opening_hoursstring/nullCompact opening-hours text
store.opening_hours_verticalstring/nullMulti-line opening-hours block
store.opening_hours_inlinestring/nullComma-separated opening-hours text
store.opening_hours_notesstring/nullFree-text opening-hours notes
store.personal_notesstring/nullReceipt footer/personal note
store.policies_and_conditionsstring/nullRefund, returns, or terms text
store.footer_imprintstring/nullLegal footer imprint

Tax ID objects

store.tax_ids and customer.tax_ids contain objects with the same shape:

FieldTypeDescription
typestringIdentifier such as eu_vat, de_steuernummer, au_abn, br_cpf, us_ein, or other
valuestringTax ID value to print
countrystring/nullISO country code when known
labelstring/nullLocalised display label, resolved before rendering

Example:

{{#store.tax_ids}}
{{label}}: {{value}}
{{/store.tax_ids}}
cashier — user who processed the order

cashier

FieldTypeExample / description
cashier.idnumberWordPress user ID, 0 when unknown
cashier.namestringCashier display name
customer — name, addresses, tax IDs

customer

FieldTypeExample / description
customer.idnumber/nullCustomer ID, or null for guests
customer.namestringCustomer display name, or guest label
customer.billing_address.*objectWooCommerce billing address fields
customer.shipping_address.*objectWooCommerce shipping address fields
customer.tax_idsarrayStructured customer tax IDs snapshotted from the order

Common address keys include first_name, last_name, company, address_1, address_2, city, state, postcode, country, email, and phone.

lines — product line items

lines

Loop with {{#lines}}...{{/lines}}. Sample values are the espresso line from the sample order.

Every money field comes as a pair: the number (use it in {{#…}} guards — zero and null hide the section, and a null field has no _display twin at all) and its _display string (use it to print). Fields marked incl/excl also ship _incl and _excl variants, each with its own _display.

keystring
Stable line key / order item ID.
key"412"
skustring
Product SKU.
sku"ESP-500"
namestring
Product or line display name.
name"Espresso Beans"
qtynumber
Quantity sold.
qty2
qty_refundednumber
Quantity refunded for this line.
qty_refunded0
regular_pricenumbermoneynullableincl/excl
Recorded regular unit price. null on orders without POS price history — wrap it in a section.
regular_price17
regular_price_display"$17.00"
selling_pricenumbermoneynullableincl/excl
Pre-coupon selling unit price — the recorded POS price when available, otherwise derived from the stored line subtotal.
selling_price14.5
selling_price_display"$14.50"
unit_savingsnumbermoneynullableincl/excl
Regular minus selling, clamped to zero. Zero is falsy, so guarded rows hide themselves.
unit_savings2.5
unit_savings_display"$2.50"
line_regular_totalnumbermoneynullableincl/excl
Recorded regular price multiplied by quantity.
line_regular_total34
line_regular_total_display"$34.00"
line_selling_totalnumbermoneynullableincl/excl
Pre-coupon selling price multiplied by quantity.
line_selling_total29
line_selling_total_display"$29.00"
line_savingsnumbermoneynullableincl/excl
Total regular-to-selling-price savings for this line.
line_savings5
line_savings_display"$5.00"
savings_in_discountsboolean
True on pre-v1.9.0 orders whose saving is already inside discounts — the anti-double-count flag.
savings_in_discountsfalse
unit_subtotalnumbermoneyincl/excl
WooCommerce pre-discount unit value. Do not use this as the regular price.
unit_subtotal14.5
unit_subtotal_display"$14.50"
unit_pricenumbermoneyincl/excl
Final unit value after WooCommerce discounts.
unit_price13.05
unit_price_display"$13.05"
line_subtotalnumbermoneyincl/excl
WooCommerce pre-discount line subtotal.
line_subtotal29
line_subtotal_display"$29.00"
discountsnumbermoneyincl/excl
Native WooCommerce line discount as a positive value — coupons only on current orders.
discounts2.9
discounts_display"$2.90"
line_totalnumbermoneyincl/excl
Final line total after coupons — what prints in the amount column.
line_total26.1
line_total_display"$26.10"
total_refundednumbermoney
Total refunded for this line as a positive value.
total_refunded0
total_refunded_display"$0.00"
taxesarray
Per-rate tax rows for this line.
metaarray
Order item meta as {key, value} pairs.
attributesarray
Product/variation attributes as {key, value} pairs.

Displaying regular price and savings

For a unit-price layout, show the recorded regular price, selling price, and saving like this:

{{#lines}}
{{#unit_savings}}
<span style="text-decoration: line-through;">{{regular_price_display}}</span>
<span>{{selling_price_display}}</span>
<span>{{i18n.savings}}: -{{unit_savings_display}}</span>
{{/unit_savings}}
{{/lines}}

Use the line-total fields when quantity matters:

{{#lines}}
{{#line_savings}}
<span style="text-decoration: line-through;">{{line_regular_total_display}}</span>
<span>{{i18n.savings}}: -{{line_savings_display}}</span>
{{/line_savings}}
{{/lines}}

selling_price is the price before coupons. Use unit_price or line_total for the final amount after WooCommerce discounts.

Reprinting orders created before v1.9.0

Older WCPOS orders may already include the regular-to-selling-price reduction in discounts. If your custom template prints both line savings and line discounts, use savings_in_discounts to avoid showing the same reduction twice:

{{#lines}}
{{#line_savings}}
<span style="text-decoration: line-through;">{{line_regular_total_display}}</span>
{{^savings_in_discounts}}
<span>{{i18n.savings}}: -{{line_savings_display}}</span>
{{/savings_in_discounts}}
{{/line_savings}}
{{#discounts}}
<span>{{i18n.discount}}: -{{discounts_display}}</span>
{{/discounts}}
{{/lines}}

If the template does not print a line-level discounts row, keep showing line_savings even when savings_in_discounts is true. The bundled templates handle this distinction automatically.

fees and shipping

fees and shipping

Loop with {{#fees}}...{{/fees}} and {{#shipping}}...{{/shipping}}.

FieldTypeDescription
labelstringFee label or shipping method name
method_idstringShipping method ID (shipping only)
total / _incl / _exclnumberDisplay-side, inclusive, and exclusive totals
taxesarrayPer-rate tax rows
metaarray{key, value} meta pairs

Formatted variants: total_display, total_incl_display, and total_excl_display.

discounts — coupon/discount rows

discounts

Loop with {{#discounts}}...{{/discounts}}.

FieldTypeDescription
labelstringCoupon description or code fallback
codestringCoupon code
total / _incl / _exclnumberDiscount amount as a positive value

Formatted variants: total_display, total_incl_display, and total_excl_display. Add your own minus sign in the template if you want discounts shown as negative rows.

totals — order, payment, refund, and item totals

totals

Sample values are from the sample order, which later received a $7.25 partial refund.

Money fields follow the same pairing as line items: a bare number for guards and a _display string for printing, with _incl/_excl variants where marked.

subtotalnumbermoneyincl/excl
Order subtotal before discounts.
subtotal52.75
subtotal_display"$52.75"
discount_totalnumbermoneyincl/excl
Order discount total as a positive value — coupons only on current orders.
discount_total5.28
discount_total_display"$5.28"
sale_savings_totalnumbermoneynullableincl/excl
Total recorded regular-to-selling-price savings across product lines, including catalogue sales and till price changes.
sale_savings_total5
sale_savings_total_display"$5.00"
total_savednumbermoneynullableincl/excl
Combined WooCommerce discounts and regular-price savings, with legacy overlap removed. The one customer-facing figure for everything saved.
total_saved10.28
total_saved_display"$10.28"
total_saved_completeboolean
Whether the receipt has enough recorded price data to calculate the complete savings totals.
total_saved_completetrue
tax_totalnumbermoney
Total tax amount.
tax_total0
tax_total_display"$0.00"
totalnumbermoneyincl/excl
Order grand total.
total59.97
total_display"$59.97"
paid_totalnumbermoney
Amount paid / applied.
paid_total59.97
paid_total_display"$59.97"
change_totalnumbermoney
Change returned to the customer.
change_total0
change_total_display"$0.00"
refund_totalnumbermoney
Total refunded as a positive value.
refund_total7.25
refund_total_display"$7.25"
net_totalnumbermoney
Total minus refunds, clamped to zero.
net_total52.72
net_total_display"$52.72"
total_qtynumber
Sum of line item quantities.
total_qty4
line_countnumber
Count of product line rows.
line_count3

Use total_saved when you want one customer-facing figure for everything saved. Do not calculate it by adding discount_total and sale_savings_total in the template: orders created before v1.9.0 may already include their POS price saving in WooCommerce's discount total. The canonical total_saved field detects and removes that overlap.

Savings totals are null and total_saved_complete is false when any product line lacks enough recorded price data for a reliable aggregate. Guard the row with total_saved_complete, then use total_saved to hide a zero value:

{{#totals.total_saved_complete}}
{{#totals.total_saved}}
<span>{{i18n.total_saved}}: {{totals.total_saved_display}}</span>
{{/totals.total_saved}}
{{/totals.total_saved_complete}}

The bundled price-bearing templates use the same guard structure with the tax-inclusive variants (total_saved_incl and total_saved_incl_display), and display Total saved only when the complete value is greater than zero.

tax and tax_summary — display guards and per-rate rows

tax and tax_summary

Use tax for display-mode guards and tax_summary for itemized rate rows.

Tax fieldTypeDescription
tax.displaystringincl or excl
tax.display_inclbooleanTrue when prices display inclusive of tax
tax.display_exclbooleanTrue when prices display exclusive of tax
tax.breakdownstringhidden, single, or itemized
tax.breakdown_hiddenbooleanTrue when tax rows should be hidden
tax.breakdown_singlebooleanTrue when a single tax total is preferred
tax.breakdown_itemizedbooleanTrue when per-rate rows are preferred
has_tax_summarybooleanTrue when tax_summary contains rows

Loop tax_summary with {{#tax_summary}}...{{/tax_summary}}.

FieldTypeDescription
codestringTax rate ID/code
ratenumber/nullRate percentage when resolved
labelstringTax rate label
compoundbooleanWhether the rate is compounded
taxable_amount_exclnumber/nullTaxable base excluding tax
tax_amountnumberTax collected
taxable_amount_inclnumber/nullTaxable base including tax

Formatted variants: taxable_amount_excl_display, tax_amount_display, and taxable_amount_incl_display.

payments — payment rows

payments

Loop with {{#payments}}...{{/payments}}.

FieldTypeDescription
method_idstringPayment method identifier
method_titlestringPayment method display title
amountnumberAmount applied to the order
transaction_idstringGateway transaction ID
tenderednumberCash amount tendered when present
changenumberCash change returned when present

Formatted variants: amount_display, tendered_display, and change_display.

refunds — refund records

refunds

Loop with {{#refunds}}...{{/refunds}}. Refund amounts are positive magnitudes; templates decide whether to prepend a minus sign or render a separate returned-items block.

FieldTypeDescription
idnumberRefund record ID
datedate objectRefund creation date
amountnumberRefund total
subtotalnumberRefunded line subtotal
tax_totalnumberTax refunded
shipping_totalnumberShipping amount refunded
shipping_taxnumberShipping tax refunded
reasonstringRefund reason
refunded_by_idnumber/nullUser ID that issued the refund
refunded_by_namestringUser display name that issued the refund
refunded_paymentbooleanWhether the payment was refunded through the gateway
destinationstringoriginal_method, cash, or manual
gateway_idstringGateway ID used for the refund
gateway_titlestringGateway display title
processing_modestringProvider/manual processing mode
linesarrayRefunded product rows
feesarrayRefunded fee rows
shippingarrayRefunded shipping rows

Refund line fields include name, sku, qty, total, total_incl, total_excl, line_total, unit_total, and taxes. Refund fee and shipping rows use label, total, total_incl, total_excl, and taxes. Display variants are added for totals and tax amounts.

fiscal — fiscal integration snapshot

fiscal

Fiscal fields are empty by default and populated by fiscal integrations or WCPOS Pro snapshot enrichment.

FieldTypeDescription
fiscal.immutable_idstringImmutable fiscal identifier
fiscal.receipt_numberstringFiscal receipt number
fiscal.sequencenumber/nullSequence counter
fiscal.hashstringHash/signature value
fiscal.qr_payloadstringQR payload for fiscal verification
fiscal.tax_agency_codestringTax authority code
fiscal.signed_atstringFiscal signing timestamp
fiscal.signature_excerptstringTruncated signature for display
fiscal.document_labelstringDocument label, e.g. Tax Invoice
fiscal.is_reprintbooleanWhether this render is a reprint
fiscal.reprint_countnumberReprint count
fiscal.extra_fieldsarray/objectJurisdiction-specific values
presentation_hints — formatting and renderer hints

presentation_hints

These fields are mainly consumed by the renderer and formatter. They are available to templates when needed.

FieldTypeDescription
presentation_hints.display_taxstringincl, excl, hidden, itemized, or single
presentation_hints.prices_entered_with_taxbooleanWhether catalogue prices include tax
presentation_hints.rounding_modestringWooCommerce tax rounding setting
presentation_hints.localestringLocale used for formatting
presentation_hints.timezonestringReceipt timezone
presentation_hints.currency_positionstringCurrency symbol position
presentation_hints.currency_symbolstringCurrency symbol
presentation_hints.price_thousand_separatorstringThousands separator
presentation_hints.price_decimal_separatorstringDecimal separator
presentation_hints.price_num_decimalsnumberDecimal places
presentation_hints.price_display_suffixstringWooCommerce price display suffix
presentation_hints.order_barcode_typestringBarcode type used by gallery templates
i18n — translated labels

i18n

Use i18n labels instead of hardcoding text where possible:

{{i18n.order}} #{{order.number}}
{{i18n.cashier}}: {{cashier.name}}
{{i18n.total}}: {{totals.total_display}}

Common keys include order, date, cashier, customer, item, sku, qty, unit_price, regular_price, selling_price, savings, discount, subtotal, total_saved, total, tax, paid, tendered, change, tax_summary, refunded, net_total, customer_note, thank_you_purchase, opening_hours, and the tax-ID label keys such as store_tax_id_label_eu_vat and customer_tax_id_label_other. Extra keys may be added by extensions.