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 /history → orders[], GET /kds-orders → [], GET /dine-orders → dinerOrderDetail[] |
Validation source: src/validations/invoice.validation.js
Read mapper: src/utils/invoice-sync-response-mapper.js
Legacy reference: web-application → invoiceSyncV3.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.js → buildInvoiceSyncPayload.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 notes → order_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