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.
store.name · store.address_lines · store.tax_ids · store.logoorder.number · order.created · cashier.name · customer.namelines[] · line_savings · savings_in_discountstotals.* · discounts[] · fees[] · shipping[] · totals.total_savedpayments[]store.personal_notes · store.policies_and_conditions · i18n.thank_you_purchaseCommon 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.
{{#lines}}
{{#line_savings}}
<s>{{line_regular_total_display}}</s>
{{i18n.savings}}: -{{line_savings_display}}
{{/line_savings}}
{{/lines}}{{#totals.total_saved_complete}}
{{#totals.total_saved}}
{{i18n.total_saved}}:
{{totals.total_saved_display}}
{{/totals.total_saved}}
{{/totals.total_saved_complete}}{{#lines}}
{{#line_savings}}
{{^savings_in_discounts}}
{{i18n.savings}}: -{{line_savings_display}}
{{/savings_in_discounts}}
{{/line_savings}}
{{/lines}}Rendering rules
Currency fields
Numeric money fields are preserved as numbers and the renderer adds locale-aware _display fields for template output:
| Numeric field | Display field |
|---|---|
totals.total | totals.total_display |
lines[].line_total | lines[].line_total_display |
payments[].amount | payments[].amount_display |
tax_summary[].tax_amount | tax_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 field | Inclusive field | Exclusive field |
|---|---|---|
lines[].regular_price | lines[].regular_price_incl | lines[].regular_price_excl |
lines[].selling_price | lines[].selling_price_incl | lines[].selling_price_excl |
lines[].unit_savings | lines[].unit_savings_incl | lines[].unit_savings_excl |
lines[].line_regular_total | lines[].line_regular_total_incl | lines[].line_regular_total_excl |
lines[].line_selling_total | lines[].line_selling_total_incl | lines[].line_selling_total_excl |
lines[].line_savings | lines[].line_savings_incl | lines[].line_savings_excl |
lines[].unit_price | lines[].unit_price_incl | lines[].unit_price_excl |
lines[].unit_subtotal | lines[].unit_subtotal_incl | lines[].unit_subtotal_excl |
lines[].line_subtotal | lines[].line_subtotal_incl | lines[].line_subtotal_excl |
lines[].discounts | lines[].discounts_incl | lines[].discounts_excl |
lines[].line_total | lines[].line_total_incl | lines[].line_total_excl |
fees[].total | fees[].total_incl | fees[].total_excl |
shipping[].total | shipping[].total_incl | shipping[].total_excl |
discounts[].total | discounts[].total_incl | discounts[].total_excl |
totals.subtotal | totals.subtotal_incl | totals.subtotal_excl |
totals.discount_total | totals.discount_total_incl | totals.discount_total_excl |
totals.sale_savings_total | totals.sale_savings_total_incl | totals.sale_savings_total_excl |
totals.total_saved | totals.total_saved_incl | totals.total_saved_excl |
totals.total | totals.total_incl | totals.total_excl |
Date objects
Date fields are objects with multiple preformatted variants. This avoids doing date formatting inside Mustache.
| Field | Description |
|---|---|
datetime, date, time | Default date/time strings |
datetime_short, datetime_long, datetime_full | Locale-aware combined formats |
date_short, date_long, date_full | Locale-aware date-only formats |
date_ymd, date_dmy, date_mdy | Fixed-order date formats |
weekday_short, weekday_long | Day names |
day, month, month_short, month_long, year | Individual 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
| Section | Type | Description |
|---|---|---|
order | object | Order identity, status, dates, note, and payment URL information |
store | object | Store identity, address, contact details, tax IDs, logo, hours, and footer text |
cashier | object | User who processed the order |
customer | object | Customer display name, addresses, and tax IDs |
lines | array | Product line items |
fees | array | Fee rows |
shipping | array | Shipping rows |
discounts | array | Coupon/discount rows |
totals | object | Order totals, payment totals, refund summary, and item counts |
tax | object | Tax display mode flags for section guards |
tax_summary | array | Per-rate tax summary rows |
has_tax_summary | boolean | Convenience guard for tax_summary |
payments | array | Payment rows |
refunds | array | Refund records applied to the order |
fiscal | object | Fiscal snapshot fields populated by fiscal integrations |
presentation_hints | object | Formatting and renderer hints |
i18n | object | Translated 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:
unit_price → 13.05 · line_total → 26.10lines[].discounts → 2.90 on this lineunit_savings → 2.50 · line_savings → 5.00totals.sale_savings_total = 5.00totals.discount_total = 5.28totals.total_saved = 10.28Sale 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
| Field | Type | Example / description |
|---|---|---|
order.id | number | 1042 |
order.number | string | Human-facing order number, e.g. "1042" |
order.currency | string | ISO currency code, e.g. "USD" |
order.customer_note | string | Customer/order note |
order.wc_status | string | Raw WooCommerce status slug, e.g. "processing" |
order.status_label | string | Localised status label, including custom statuses |
order.created_via | string | Source/channel, e.g. "woocommerce-pos" |
order.needs_payment | boolean | Whether a payment section should be shown |
order.payment_url | string | Order payment URL when available |
order.created | date object | Order creation date |
order.paid | date object | Paid date, empty strings when not paid |
order.completed | date object | Completed date, empty strings when incomplete |
order.printed | date object | Render-time print/reprint timestamp |
store — identity, address, contact, hours
store
| Field | Type | Example / description |
|---|---|---|
store.id | number | Store ID, or historical ID for deleted stores |
store.name | string | Store display name |
store.address.address_1 | string | Street address line 1 |
store.address.address_2 | string | Suite/unit line |
store.address.city | string | City/locality |
store.address.state | string | State/region |
store.address.postcode | string | Postal code |
store.address.country | string | ISO country code |
store.address_lines | array | Preformatted address lines; recommended for most templates |
store.tax_ids | array | Structured business tax IDs; loop this instead of using a single tax ID |
store.phone | string | Store phone |
store.email | string | Store email |
store.logo | string/null | Store logo URL or data URI |
store.opening_hours | string/null | Compact opening-hours text |
store.opening_hours_vertical | string/null | Multi-line opening-hours block |
store.opening_hours_inline | string/null | Comma-separated opening-hours text |
store.opening_hours_notes | string/null | Free-text opening-hours notes |
store.personal_notes | string/null | Receipt footer/personal note |
store.policies_and_conditions | string/null | Refund, returns, or terms text |
store.footer_imprint | string/null | Legal footer imprint |
Tax ID objects
store.tax_ids and customer.tax_ids contain objects with the same shape:
| Field | Type | Description |
|---|---|---|
type | string | Identifier such as eu_vat, de_steuernummer, au_abn, br_cpf, us_ein, or other |
value | string | Tax ID value to print |
country | string/null | ISO country code when known |
label | string/null | Localised display label, resolved before rendering |
Example:
{{#store.tax_ids}}
{{label}}: {{value}}
{{/store.tax_ids}}
cashier — user who processed the order
cashier
| Field | Type | Example / description |
|---|---|---|
cashier.id | number | WordPress user ID, 0 when unknown |
cashier.name | string | Cashier display name |
customer — name, addresses, tax IDs
customer
| Field | Type | Example / description |
|---|---|---|
customer.id | number/null | Customer ID, or null for guests |
customer.name | string | Customer display name, or guest label |
customer.billing_address.* | object | WooCommerce billing address fields |
customer.shipping_address.* | object | WooCommerce shipping address fields |
customer.tax_ids | array | Structured 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.
null on orders without POS price history — wrap it in a section.discounts — the anti-double-count flag.{key, value} pairs.{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.
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}}.
| Field | Type | Description |
|---|---|---|
label | string | Fee label or shipping method name |
method_id | string | Shipping method ID (shipping only) |
total / _incl / _excl | number | Display-side, inclusive, and exclusive totals |
taxes | array | Per-rate tax rows |
meta | array | {key, value} meta pairs |
Formatted variants: total_display, total_incl_display, and total_excl_display.
discounts — coupon/discount rows
discounts
Loop with {{#discounts}}...{{/discounts}}.
| Field | Type | Description |
|---|---|---|
label | string | Coupon description or code fallback |
code | string | Coupon code |
total / _incl / _excl | number | Discount 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.
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 field | Type | Description |
|---|---|---|
tax.display | string | incl or excl |
tax.display_incl | boolean | True when prices display inclusive of tax |
tax.display_excl | boolean | True when prices display exclusive of tax |
tax.breakdown | string | hidden, single, or itemized |
tax.breakdown_hidden | boolean | True when tax rows should be hidden |
tax.breakdown_single | boolean | True when a single tax total is preferred |
tax.breakdown_itemized | boolean | True when per-rate rows are preferred |
has_tax_summary | boolean | True when tax_summary contains rows |
Loop tax_summary with {{#tax_summary}}...{{/tax_summary}}.
| Field | Type | Description |
|---|---|---|
code | string | Tax rate ID/code |
rate | number/null | Rate percentage when resolved |
label | string | Tax rate label |
compound | boolean | Whether the rate is compounded |
taxable_amount_excl | number/null | Taxable base excluding tax |
tax_amount | number | Tax collected |
taxable_amount_incl | number/null | Taxable 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}}.
| Field | Type | Description |
|---|---|---|
method_id | string | Payment method identifier |
method_title | string | Payment method display title |
amount | number | Amount applied to the order |
transaction_id | string | Gateway transaction ID |
tendered | number | Cash amount tendered when present |
change | number | Cash 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.
| Field | Type | Description |
|---|---|---|
id | number | Refund record ID |
date | date object | Refund creation date |
amount | number | Refund total |
subtotal | number | Refunded line subtotal |
tax_total | number | Tax refunded |
shipping_total | number | Shipping amount refunded |
shipping_tax | number | Shipping tax refunded |
reason | string | Refund reason |
refunded_by_id | number/null | User ID that issued the refund |
refunded_by_name | string | User display name that issued the refund |
refunded_payment | boolean | Whether the payment was refunded through the gateway |
destination | string | original_method, cash, or manual |
gateway_id | string | Gateway ID used for the refund |
gateway_title | string | Gateway display title |
processing_mode | string | Provider/manual processing mode |
lines | array | Refunded product rows |
fees | array | Refunded fee rows |
shipping | array | Refunded 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.
| Field | Type | Description |
|---|---|---|
fiscal.immutable_id | string | Immutable fiscal identifier |
fiscal.receipt_number | string | Fiscal receipt number |
fiscal.sequence | number/null | Sequence counter |
fiscal.hash | string | Hash/signature value |
fiscal.qr_payload | string | QR payload for fiscal verification |
fiscal.tax_agency_code | string | Tax authority code |
fiscal.signed_at | string | Fiscal signing timestamp |
fiscal.signature_excerpt | string | Truncated signature for display |
fiscal.document_label | string | Document label, e.g. Tax Invoice |
fiscal.is_reprint | boolean | Whether this render is a reprint |
fiscal.reprint_count | number | Reprint count |
fiscal.extra_fields | array/object | Jurisdiction-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.
| Field | Type | Description |
|---|---|---|
presentation_hints.display_tax | string | incl, excl, hidden, itemized, or single |
presentation_hints.prices_entered_with_tax | boolean | Whether catalogue prices include tax |
presentation_hints.rounding_mode | string | WooCommerce tax rounding setting |
presentation_hints.locale | string | Locale used for formatting |
presentation_hints.timezone | string | Receipt timezone |
presentation_hints.currency_position | string | Currency symbol position |
presentation_hints.currency_symbol | string | Currency symbol |
presentation_hints.price_thousand_separator | string | Thousands separator |
presentation_hints.price_decimal_separator | string | Decimal separator |
presentation_hints.price_num_decimals | number | Decimal places |
presentation_hints.price_display_suffix | string | WooCommerce price display suffix |
presentation_hints.order_barcode_type | string | Barcode 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.