Transaction states
A transaction moves through two independent state machines:| Field | Values | Meaning |
|---|---|---|
estado | pendiente → abierto → cerrado | Payment and billing state |
estado_cocina | pendiente → terminado | Kitchen preparation state |
estado: cerrado) only when both conditions are met: the kitchen has marked it terminado and monto_pendiente reaches zero.
monto_pendiente is a calculated field — it is never stored in the database. The API computes it as monto_total - monto_pagado on every response.Full order walkthrough
Open a cash register
Before creating transactions, you need an open The API returns the new caja with its
caja_turno. If no caja is open, transactions are created without a caja_id and payments will not be tallied to any shift.id. Take note of it — you can also retrieve it later with GET /api/caja/actual.Create a transaction
Create a new transaction with a The transaction starts in
concepto (description), an optional mesa (table identifier), and the caja_id. If you omit caja_id, the API automatically links it to the currently open caja.estado: pendiente with all amounts at zero.Add items
Add a plato (kitchen dish) or producto (standalone product) to the transaction. Supply either The API:
plato_id or producto_id — never both.- Looks up the current price from the plato or producto record.
- Calculates
subtotal = precio_unitario × cantidad. - Recalculates
monto_totalon the parent transaction. - Sets
estado_cocina: pendienteon the transaction if a plato was added. - Moves the transaction to
estado: abierto.
Add extras to an item (optional)
You can attach extras to any item — either a known ingredient (by To link a tracked ingredient instead:Adding extras recalculates the item’s
ingrediente_id) or a free-text description. Each extra has its own precio and cantidad.subtotal and then recalculates the transaction’s monto_total.Kitchen marks the order done
When the kitchen finishes preparing all dishes, a staff member (or the kitchen display) calls:This sets
estado_cocina: terminado on the transaction. If the order is already fully paid, the transaction will close automatically at this point.The gateway also broadcasts the pedido-completado event to all connected WebSocket clients on the /cocina namespace.Record payment
Record a payment for the transaction. You can pay with The response includes the calculated Payment is also automatically registered in the open caja under
efectivo (cash) or qr. Partial payments are allowed — call this endpoint multiple times until monto_pendiente reaches zero.cambio (change) for cash payments:ventas_efectivo or ventas_qr.Transaction closes automatically
Once
monto_pendiente reaches zero and estado_cocina is terminado, the API sets estado: cerrado without any additional call.At closure, the API deducts stock:- For productos: reduces the
stockinteger on the product. - For platos: reduces
cantidadon each linked ingredient according toplato_ingredientes.cantidad × item.cantidad. - For extras with an
ingrediente_id: reduces that ingredient’scantidad.
Reopening a closed transaction
If a customer orders more after the transaction has closed, use the reopen endpoint:estado back to abierto. The existing monto_pagado is preserved — the customer only pays the new monto_pendiente that accrues from the additional items. This is equivalent to the system calling reabrir for you whenever you add an item to a closed transaction.
You can only reopen a transaction that is in
estado: cerrado. Calling this on a pendiente or abierto transaction returns a 400 Bad Request.