README docs frontend-handout/06-PAYLOAD-REFERENCE.md

06 — Shared invoice payload reference

Single DTO catalog for Android/iOS/web POS models. Used by:

Direction Endpoints
Write POST /v1/invoices/sync (adds required request_id)
Read GET /historyorders[], GET /kds-orders[], GET /dine-ordersdinerOrderDetail[]

Validation source: src/validations/invoice.validation.js
Read mapper: src/utils/invoice-sync-response-mapper.js
Legacy reference: web-applicationinvoiceSyncV3.js (iOS / TRACK sync)

KDS / dine-orders also add order_type_icon (string URL | null) on read only.

.unknown(true) — Extra keys on the invoice object and each line item are accepted on sync (web-pos sends several). They are not rejected by Joi; persistence depends on DB columns / refactorInvoice.


Frontend sources (what clients send today)

Client Sync entry Notes
iOS / legacy TRACK invoiceSyncV3 Sends notes (string array) → DB order_notes; single note string
web-pos handleSaveOrder.jsbuildInvoiceSyncPayload.js Sends note (string); notes[] not wired yet; uses modifier on items (not modifiers)
Android Should mirror iOS shape Use notes[] + modifiers[] per this doc

Invoice-level fields sent by web-pos (in addition to Joi schema)

Field Type Persisted? Notes
allergy_warning string No dedicated column today Accepted via .unknown(true)
external_order_id number | string Check integrations Legacy aggregator hook
id number No Table / local id — not invoice PK
payment_method array Stripped on write Use payments[]; removed in refactorInvoice
seconds_from_gmt number No Prefer timezone
time_zone string Alias Maps conceptually to timezone
time_zone_abbrivation string No Typo preserved for client compat

Line-item fields sent by web-pos (in addition to Joi schema)

Field Type Notes
modifier array Accepted on sync; refactorInvoice serializes to DB modifier string; on read → modifiers
addOns array Cart-only; flattened into items / nested addons before sync
buy, get array Promo / offer metadata
cart_display_name string UI label
discount_display_string string UI label
extras_array array Cart form; extras string is what persists
image string Product image URL
invoice_item_id number Local / DB line id reference
is_offer 0 | 1 Offer flag
is_weightage_item 0 | 1 Weighted product
old_discount_pct number Legacy discount
parent_id number Combo / parent link
sub_total number Duplicate of subtotal
totalPrice, productTotalPrice number UI totals
type string Product type e.g. "General"
unit_id number UOM
vat_amount, vat_name string | number Line VAT display
disposition string | null Cart alias; prefer disposition_type for DB

Complete invoice attribute index (POST /sync body element)

Legend: R = required on sync · O = optional · W = web-pos sends · I = iOS/legacy sends · →DB = persisted column

Field Type Sent by →DB Notes
uuid string R W, I yes Client order id; stable for lifetime
request_id string R W, I no Idempotency key; not returned on history
status "open"|"cancelled"|"completed" R W, I yes
customer_id number R W, I yes Must match JWT
location_id number R W, I yes Must match JWT
user string R W, I yes Cashier email / username
user_id number | null O W, I yes
created_at number R W, I yes Unix seconds
updated_at number R W, I yes Unix seconds
paid_at number | null O W, I yes Set when paid
done_at number | null O I yes KDS ready
rider_pickup_at number | null O I yes Delivery
rider_arrived_at number | null O I yes Delivery
subtotal number R W, I yes Ex-VAT header subtotal
vat number R W, I yes Header VAT
payable number R W, I yes Amount due / paid
discountamount number O W, I yes default 0
discountpct number O W, I yes default 0
discount_id number | null O W, I yes
discount_reason string O W, I yes default ""
paid number O W, I yes Tendered amount
change number O W, I yes default 0
tip_amount number O W, I yes default 0
tip number O I yes default 0
charges_fee number O W, I yes default 0
delivery_charges number O W, I yes default 0
delivery_fee number O W, I yes default 0
packaging_fee number O W, I yes default 0
service_percentage number O W, I yes default 0
service_amount number O W, I yes default 0
service_charge number O I yes default 0
refund_amount number O W, I yes default 0
gross_total number | null O W, I yes
net_total number | null O W, I yes
items_subtotal number O W, I yes Sum of lines ex-VAT
items_vat_amount number O W, I yes Sum of line VAT
items_total number O W, I yes Sum of line totals
items_discount_amount number O I yes default 0
info_name string O W, I yes Brand / customer name snapshot
info_address string O W, I yes
info_phone string O W, I yes
info_email string O W, I yes
phone_number string O W, I yes SMS / loyalty phone
crm_delivery_area string | null O I yes CRM delivery area snapshot
items array R W, I yes Line items (see below)
items_number number O W, I yes Parent line count
items_count number O W, I yes Lines + addons + modifiers count
products_count number O W, I yes Product rows
order_no number O W, I yes Server overwrites on sync
customer_invoice_id number | null O W, I yes Server assigns on sync
round number | null O W, I yes Dine-in round / course
payments array | null O W, I yes [{ payment_method, amount, tip_amount? }]
is_paid 0 | 1 O W, I yes
is_qr_payment 0 | 1 O W, I partial May default on read
qr_payment_link string O W, I partial
is_wallet_used 0 | 1 O I yes
table_id number | null O W, I yes Dine-in table
order_type string R W, I yes e.g. "Dine In", "takeaway"
order_type_icon_key string O I yes Iconify key
order_type_icon string | null no Read-only (KDS/dine)
token_number number | null O I yes
plate_number string O I yes
dining_guests number O W, I yes default 0
guest_name string O W, I yes
crm_user_id number O W, I yes default 0
crm_user_name string O W, I yes Server may fill from CRM
brand_id number | null O W, I yes
channel_id number O I yes default 0
channel_name string O I yes
channel string O I yes
note string O W, I yes Single free-text note
notes string[] | null O I (preferred) yes → order_notes iOS key; array of strings
order_notes array | null O legacy alias yes Use notes on new clients; notes wins if both sent
period string | null O W, I yes Business period label
timezone string O I yes e.g. Asia/Dubai
ticket_validate_at number | null O I yes
is_ticket_available 0 | 1 O W, I yes
is_vat_on_discount_exclude 0 | 1 O W, I yes
is_wastage 0 | 1 O W, I yes
is_discount_on_total 0 | 1 O W, I yes
is_syspos 0 | 1 O W, I yes default 1
is_accepted 0 | 1 | 2 O W, I yes KDS acceptance
is_updated 0 | 1 O W, I yes
is_refunded 0 | 1 O I yes
is_kds_printed 0 | 1 O W, I yes
is_invoice_printed 0 | 1 O I yes
row_discount 0 | 1 O W, I yes 1 = item discount applies to product+modifiers+extras+addons
external_order_ready 0 | 1 O I yes Aggregator / external ready flag
is_loyalty_enable 0 | 1 O W, I read default
loyalty_mobile_number string O W, I yes
loyalty_mobile_code string O W, I yes
earn_points number O W, I yes
burn_points number O W, I yes
burn_points_amount number O W, I yes
available_points number O W, I yes
available_points_amount number O W, I yes
coupon_id number O W, I yes default 0
coupon_code string O W, I yes
coupon_amount number O W, I yes
printed_invoice_receipts number O W, I yes
printed_kds_receipts number O W, I yes
app_version string O W, I yes
app_os_version string O W, I yes
build_number number | null O W, I yes
os_type string O W, I yes ios / android / web
updated_app_version string O I yes Set on completed paid sync
updated_os_type string O I yes
created_by_user_id number | null O W, I yes
close_by_user_id number | null O W, I yes Set on complete / cancel
modified_by_user_ids string | number[] O W, I yes History returns number[]
otter_account_id string O I yes
otter_id string O I yes
deliverect_account_id string O I yes
deliverect_id string O I yes
deliverect_date number | null O I yes
deliveroo_id string O I yes
aggregator_order_id string O I yes
pos_receipt_id string O I yes
pos string O I yes
pos_id string O I yes
by string O W, I yes
delivery_cost string O I yes
number_of_customers number | null O I yes
exchange_rate number | null O W, I yes
paid_in_usd number O W, I yes default 0
multi_location_order_id number | null O I yes
shift_id number | null O I yes
is_sms_enable 0 | 1 O W, I read default

notes vs note (iOS / invoiceSyncV3)

Field Shape Storage Read APIs
note single string invoices.note note
notes string array invoices.order_notes (JSON) notes (parsed array)
"note": "Allergy: nuts",
"notes": ["No onions", "Extra spicy", "Serve together"]

On sync, refactorInvoice maps notesorder_notes and removes notes before DB write. History/KDS/dine map order_notes back to notes.


Complete line-item attribute index (items[])

Field Type Sent by →DB Notes
name string R W, I yes
product_id number R W, I yes
qty number R W, I yes
actual_price number R W, I yes Unit price
invoice_uuid string R W, I yes Parent invoice uuid
vat_pct number R W, I yes
customer_id number R W, I yes
location_id number R W, I yes
name_localize string O I yes default ""
price number | null O W, I yes
subtotal number | null O W, I yes
vat number | string O W, I yes Line VAT amount
discount_type "percentage"|"amount" O I yes
discount_pct number O W, I yes
discount_amount number O W, I yes
discount_id number | null O I yes
discount_name string O I yes
addons object[] | null O W, I yes Nested children; flattened to DB rows
is_addon 0 | 1 O W, I yes
addon_linked_with string O W, I yes Parent linked_uuid
modifiers object[] | null O I (preferred) via modifier col Flat array on sync
modifier array | string O W yes (JSON string) Renamed to modifiers on read
combo_item_id number | null O I yes
is_combo 0 | 1 | 2 O W, I yes
combo_items object[] | null O W, I partial Often null on read
note string O W, I yes Per-line note
is_refunded 0 | 1 O W, I yes
refund_quantity number O I yes
refund_reason string O I yes
refund_pm_type string O I yes
refund_amount number | null O W, I yes
is_updated 0 | 1 O I yes
updated_qty number O I yes Delta qty on update
is_deleted 0 | 1 O W, I yes Soft-delete line
deleted_qty number O W, I yes
deleted_at number O W, I yes
is_wastage 0 | 1 O I yes
ri 0 | 1 O I yes Return-inventory flag (legacy)
item_status string O W, I yes default "active"; e.g. "disposition"
disposition_type string | null O W, I yes e.g. "wastage" | "return"
disposition_reason string | null O W, I yes
linked_uuid string O W, I yes Required for addon re-nesting
original_linked_uuid string | null O W, I yes Disposition / transfer lineage
identifier string O W, I yes KDS prepared updates
transferred_to number O W, I yes
transferred_to_uuid string O W, I yes
transferred_quantity number O W, I yes
transferred_to_uuid_list array | string O W, I yes JSON text in DB; array on read
transferred_quantities array | string O W, I yes JSON text in DB; array on read
transfer_recipients array | string O W, I yes JSON text in DB; array on read
created_at number O W, I yes
updated_at number O W, I yes
product_type string O I yes
is_internal 0 | 1 O I yes
sort_order number O I yes History sort
plu string O I yes
otter_account_id, otter_id string O I yes
delivery_cost string O I yes
tip number O I yes
by string O I yes
is_prepared 0 | 1 O W, I yes KDS
base_price number O I yes
brand_id number O W, I yes
label_id number O I yes
preparation_time number O W, I yes
item_type string O I yes
updated_by_user_ids number[] O I yes
re string O I yes Refund/cancel reason (legacy)
round number O W, I yes Course round
extras string O W, I yes JSON map string "{\"matId\": qty}"
item_price_after_discount number O I yes
line_vat number | string O W, I yes
line_total number O W, I yes
line_total_without_vat number | string O W, I yes
coupon_amount number O I yes
coupon_id number O I yes
coupon_code string O I yes
product_recipe_cost number O I yes
total_cost number O I yes
modifiers_cost_amount number | null O I yes Usually from cost snapshot
cost_snapshot_at number | null O I yes Unix on read

See web-pos-only line fields in Frontend sources above.


Enums

Field Allowed values
Invoice status "open", "cancelled", "completed"
Item discount_type "percentage", "amount"

Boolean flags (0 / 1)

Rule Meaning
0 false
1 true
omitted on write Usually defaults to 0

Exceptions: is_syspos default 1; is_combo / is_internal allow null; is_combo may be 0|1|2; read is_accepted is 0|1|2.

Invoice-level flags

is_paid, is_qr_payment, is_wallet_used, is_ticket_available, is_vat_on_discount_exclude, is_wastage, is_discount_on_total, is_syspos, is_accepted, is_updated, is_refunded, is_kds_printed, is_invoice_printed, is_loyalty_enable, is_sms_enable, row_discount, external_order_ready

Item-level flags

is_addon, is_refunded, is_updated, is_deleted, is_wastage, ri, is_prepared


Invoice object

Required on sync

Field Type Notes
uuid string Client UUID; stable for order lifetime
request_id string Idempotency key (sync only, not returned on history)
status enum See above
customer_id number
location_id number
user string
created_at number Unix seconds
updated_at number Unix seconds
subtotal number
vat number
payable number
items array Line items
order_type string e.g. dine-in / takeaway

Optional — basics & timestamps

Field Type Default / notes
user_id number | null
paid_at number | null
done_at number | null KDS ready marker
rider_pickup_at number | null
rider_arrived_at number | null

Optional — finance

Field Type Default
discountamount number 0
discountpct number 0
discount_id number | null
discount_reason string ""
paid number 0
change number 0
tip_amount number 0
tip number 0
charges_fee number 0
delivery_charges number 0
delivery_fee number 0
packaging_fee number 0
service_percentage number 0
service_amount number 0
service_charge number 0
refund_amount number 0

Optional — calculated totals

Field Type Default
gross_total number | null
net_total number | null
items_subtotal number 0
items_vat_amount number 0
items_total number 0
items_discount_amount number 0

Optional — customer snapshot

All string, default "":

info_name, info_address, info_phone, info_email, phone_number

Optional — order / numbers

Field Type Notes
items_number number default 0
items_count number default 0
products_count number default 0
order_no number default 0; server overwrites on sync
customer_invoice_id number | null server sets on sync
round number | null

Optional — payments

Field Type Notes
payments array | null [{ payment_method, amount, tip_amount? }]
is_paid 0|1
is_qr_payment 0|1 May not persist; read may default
qr_payment_link string default ""
is_wallet_used 0|1

Optional — table & service

Field Type Notes
table_id number | null Required for dine-orders association
order_type_icon_key string Iconify key e.g. mdi:silverware-fork-knife
order_type_icon string | null Read-only (KDS/dine)
token_number number | null
plate_number string
dining_guests number default 0
guest_name string default ""

Optional — CRM / brand / channel

Field Type Default
crm_user_id number 0
crm_user_name string ""
crm_delivery_area string | null
brand_id number | null
channel_id number 0
channel_name string
channel string

Optional — notes & timezone

Field Type Notes
note string Free-text / cancel audits
notes string[] | null Prefer this on sync → DB order_notes
order_notes array | null Alias; notes wins if both sent
period string | null
timezone string e.g. Asia/Dubai
ticket_validate_at number | null

Optional — flags

Field Type Notes
is_ticket_available 0|1
is_vat_on_discount_exclude 0|1
is_wastage 0|1
is_discount_on_total 0|1
is_syspos 0|1 default 1
is_accepted 0|1|2
is_updated 0|1
is_refunded 0|1
is_kds_printed 0|1
is_invoice_printed 0|1
row_discount 0|1 Item discount applies to product+modifiers+extras+addons when 1
external_order_ready 0|1

Optional — loyalty / coupon / printing

Field Type Default
is_loyalty_enable 0|1 0
loyalty_mobile_number string ""
loyalty_mobile_code string ""
earn_points number 0
burn_points number 0
burn_points_amount number 0
available_points number 0
available_points_amount number 0
coupon_id number 0
coupon_code string ""
coupon_amount number 0
printed_invoice_receipts number 0
printed_kds_receipts number 0

Optional — app / user tracking

Field Type Notes
app_version string
app_os_version string
build_number number | null
os_type string android / ios
updated_app_version string
updated_os_type string
created_by_user_id number | null
close_by_user_id number | null
modified_by_user_ids string | number[] | null History returns number[]

Optional — integrations & misc

Field Type Notes
otter_account_id, otter_id string
deliverect_account_id, deliverect_id string
deliverect_date number | null
deliveroo_id, aggregator_order_id string
pos_receipt_id, pos, pos_id string
by, delivery_cost string
number_of_customers number | null
exchange_rate number | null
paid_in_usd number 0
multi_location_order_id number | null
shift_id number | null

Sync-response-only fields

Field Type Where
cached boolean Sync response
request_id_status 0|1|2 Idempotent sync replay
error_code string e.g. DUPLICATE_REQUEST

Line item object (items[])

Required on sync

Field Type
name string
product_id number
qty number
actual_price number
invoice_uuid string
vat_pct number
customer_id number
location_id number

Optional — core / tax / discount

Field Type Default / notes
name_localize string ""
price number | null
subtotal number | null
vat number 0
discount_type "percentage"|"amount"|null
discount_pct number 0
discount_amount number 0
discount_id number | null
discount_name string ""

Optional — addons / modifiers / combo

Field Type Notes
addons object[] | null Nested children
is_addon 0|1 Parents should be 0
addon_linked_with string Links addon row to parent linked_uuid
modifiers object[] | null Flat list
combo_item_id number | null
is_combo 0|1|2|null
combo_items object[] | null Read often null (not stored separately)

Typical modifier object

{
  "quantity": 1,
  "id": 21897,
  "subtotal": 17,
  "modifier_id": 3930,
  "actual_price": 17,
  "description": "",
  "priority": 1,
  "name": "Fries + Fanta",
  "comment": "draft"
}

Unknown keys allowed. Do not nest { items: [...] } groups for new clients — send a flat array.

Optional — state / refund / delete

Field Type Default
note string ""
is_refunded 0|1 0
refund_quantity number 0
refund_reason string | null
refund_pm_type string
refund_amount number | null
is_updated 0|1 0
updated_qty number 0
is_deleted 0|1 0
deleted_qty number 0
deleted_at number | null
is_wastage 0|1 0
ri 0|1 0
item_status string default "active"
disposition_type string | null e.g. "wastage" | "return"
disposition_reason string | null

Optional — metadata / tracking

Field Type Notes
linked_uuid string Important for addon re-nesting on reads
original_linked_uuid string | null Disposition / transfer lineage
identifier string Used by KDS prepared updates
transferred_to number 0
transferred_to_uuid string
transferred_quantity number 0
transferred_to_uuid_list array | string Stored as JSON text; array on read
transferred_quantities array | string Stored as JSON text; array on read
transfer_recipients array | string Stored as JSON text; array on read
created_at, updated_at number | null
product_type, item_type string
is_internal 0|1|null
sort_order number | null History sorts by this
plu, otter_*, by, delivery_cost string
tip number | null
is_prepared 0|1 KDS
base_price number | null
brand_id, label_id number | null
preparation_time number | null
updated_by_user_ids number[] | null
re string
round number default 1
extras string History: JSON string map when present

Optional — calculated / cost

Field Type Default
item_price_after_discount number | null
line_vat number | null
line_total number | null
line_total_without_vat number | null
coupon_amount number 0
coupon_id number | null
coupon_code string ""
product_recipe_cost number 0
total_cost number 0
modifiers_cost_amount number | null Usually from cost snapshot
cost_snapshot_at number | null Unix on read

Payments object

{
  "payment_method": "cash",
  "amount": 105,
  "tip_amount": 0
}
Field Required on sync element
payment_method yes
amount yes
tip_amount no (default 0)

Unknown keys allowed.


Suggested native model split

InvoiceDto          // table above
  └─ items: [InvoiceItemDto]
       ├─ addons: [InvoiceItemDto]?
       └─ modifiers: [ModifierDto]?
  └─ payments: [PaymentDto]?
  └─ notes: [String]?

Map flags as integers. Map timestamps as Int64 / Long seconds.


Full sync example (comments are not valid JSON)

See 02-INVOICE-SYNC.md for a minimal working payload, and repo docs/INVOICE_REQUEST.md for a fully annotated jsonc example.


Fields NOT to invent for this service

  • Non-master extras/materials as the primary customization path (out of scope)
  • Expecting GET /invoices/:uuid to return this mapped shape today (it does not)
  • Treating sync 200 as guaranteed DB commit
  • Sending booleans as JSON true/false for flag columns