> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fire.rest/llms.txt
> Use this file to discover all available pages before exploring further.

# Registro de cambios

> Actualizaciones recientes en la documentación y la referencia de API.

<div style={{border: '1px solid rgb(128 128 128 / 0.25)', borderRadius: '0.75rem', padding: '1.25rem', marginBottom: '2.5rem'}}>
  <div style={{fontWeight: 600, fontSize: '1rem'}}>Suscríbete a las actualizaciones</div>
  <div style={{fontSize: '0.875rem', opacity: 0.8, marginTop: '0.25rem'}}>Recibe un correo cada vez que se publica una entrada nueva — eventos nuevos, cambios incompatibles y actualizaciones de la referencia de API. Puedes darte de baja con un clic.</div>
  <a href="https://buttondown.com/fire-docs" target="_blank" rel="noopener" style={{display: 'inline-block', marginTop: '0.875rem', padding: '0.5rem 1.25rem', borderRadius: '0.5rem', background: '#E6293D', color: '#fff', fontSize: '0.875rem', fontWeight: 600, textDecoration: 'none'}}>Suscribirme</a>
</div>

## 15 de agosto de 2026 — El bloque fiscal: identificadores por país, anulación y proveedor

`fiscalRepresentation` deja de tener campos fijos por país y pasa a llevar el documento
**vigente** de la orden, con los anteriores en `history`.

* **Breaking** — `sequential`, `serie` y `claveAcceso` ya no son campos del bloque. Los
  identificadores del ente viven ahora en **`countryData`**, con el vocabulario del país que
  numeró: `claveAcceso`, `establecimiento`, `puntoEmision`, `secuencial` y `ambiente` en
  Ecuador; `numeroControl`, `numeroFactura` y `serie` en Venezuela. **Recorré las claves, no
  las indexes**: un canal que lea `countryData.claveAcceso` directo funciona en Ecuador y se
  rompe con el primer país que entre. Los campos que significan lo mismo en todo país
  —`documentNumber`, `issuedAt`, `authorizationMode`, `numberingStatus`— no se movieron.
* **`history`** y **`compensates`** — cuando una anulación numera, la nota de crédito pasa a
  ser el documento de arriba, `compensates` apunta a la factura que anula, y la factura entera
  baja a `history`. Cada entrada de `history` tiene **las mismas claves** que el bloque de
  arriba, así que se leen igual.
* **`environment`** — en qué ambiente numeró Fire: `SANDBOX` o `PRODUCTION`. Es nuestro, no
  del ente; el del ente sigue viajando dentro de `countryData` con su propio código.
* **`providerCode`, `providerIdentity` y `providerMetadata`** — antes eran un solo objeto que
  mezclaba tres cosas. `providerCode` es nuestro identificador de adaptador; `providerIdentity`
  es el bloque del proveedor (`name`, `version`, `reference`) y **tiene forma**; `providerMetadata`
  es una bolsa **opaca** y no hay que programar contra sus claves. La respuesta del endpoint de
  numeración devuelve ahora exactamente los mismos tres campos, con los mismos nombres.

<Note>
  Si tu conciliación asume que `documentNumber` es siempre el de la venta, revisala: después de
  una anulación el número de arriba es el de la nota de crédito. Lo que el cliente se llevó
  impreso no se pierde —está en `history`— pero hay que ir a buscarlo ahí.
</Note>

Documentado en [`order.opened`](/es/events/order-opened),
[`order.completed`](/es/events/order-completed),
[`order.cancelled`](/es/events/order-cancelled),
[`order.invoiced`](/es/events/order-invoiced),
[`order.reversed`](/es/events/order-reversed), en la
[referencia del endpoint](/es/api-reference/fiscal-documents) y en la guía
[Integrar un punto de venta](/es/guides/fiscal-integration).

Actualizado en **EN / ES / PT**.

## 13 de agosto de 2026 — La numeración fiscal ahora viaja en todos los eventos de la orden

Las órdenes que el Fiscal Gateway numeró antes de inyectarse ahora llevan esos
identificadores en todos sus eventos, así que ya no hace falta una segunda llamada para
imprimir o conciliar.

* **`data.fiscalRepresentation`** — serie, secuencial, número de documento, clave de
  acceso y el QR (`graphic`), tal como se imprimieron en la caja. **La clave viaja siempre**:
  llega en `null` cuando no se intentó numerar —agregadores, países sin representación
  fiscal, o numeración desactivada— y con el bloque cuando sí. Ramificá por valor
  (`if (data.fiscalRepresentation)`), no por presencia de la clave.

  Que traiga bloque significa **que se intentó numerar, no que se numeró**:
  `numberingStatus` dice cómo terminó el intento y `failure` por qué, cuando no terminó bien
  — una venta cobrada que quedó **sin comprobante fiscal** llega con los identificadores en
  `null` y el motivo en `failure`. Que traiga bloque **no** significa que el comprobante esté
  autorizado: el veredicto del ente sigue en `lastKnown.fiscal.status`. El bloque no cambia
  nunca, ni siquiera después de que el ente autorice o rechace.
* **`data.lastKnown.fiscal.sourceEvent`** — ahora informa la procedencia real en vez de
  deducirla del estado. Un `processing` sembrado al inyectar se reportaba como
  `fiscal.callback` sin que ningún callback hubiera ocurrido; ahora dice
  `order.injected`. Contemplá el valor nuevo si ramificás por este campo.
* Documentado en [`order.opened`](/es/events/order-opened),
  [`order.completed`](/es/events/order-completed),
  [`order.invoiced`](/es/events/order-invoiced) y
  [`order.cancelled`](/es/events/order-cancelled).

Actualizado en **EN / ES / PT**.

## 11 de agosto de 2026 — BOH API: qty\_base derivado en el servidor con item\_unit\_id

En las líneas de órdenes de compra (`POST /procurement/orders`, `add-lines` y actualización de línea), `qty_base` ahora es opcional cuando la línea referencia `item_unit_id` — no solo `unit_code`. El servidor deriva `qty_base = qty × factor_to_base` desde la unidad referenciada, así que los integradores externos que referencian una unidad de compra por UUID ya no necesitan conocer ni recalcular su factor de conversión.

Si de todos modos envías un `qty_base` explícito, BOH lo valida contra el valor derivado (tolerancia 0.001) y devuelve `purchase_order_qty_base_mismatch` (422) si no coincide — mismo comportamiento que `unit_code`. Si `item_unit_id` no resuelve a una unidad activa y se omitió `qty_base`, la respuesta ahora es el error tipado `item_unit_not_found` (404).

Actualizado en **EN / ES / PT**.

***

## 11 de agosto de 2026 — BOH API: resolución de establecimiento por ID fiscal en órdenes de compra (Fase 19)

`tax_id` es ahora un campo de primera clase en los establecimientos de BOH (RUC, CNPJ, CUIT, NIT, RUT, RFC u otro código fiscal de hasta 64 caracteres). Es opcional, no único, y se acepta en `POST /identity/stores` y `PATCH /identity/stores/{id}`.

Al crear una orden de compra por API puedes identificar el establecimiento receptor con cualquiera de estos tres campos mutuamente exclusivos:

* **`store_id`** — UUID interno (sin cambios).
* **`external_store_id`** — identificador cruzado externo.
* **`store_tax_id`** *(nuevo)* — identificador fiscal. Devuelve `422` con `purchase_order_store_tax_id_ambiguous` si varios establecimientos activos comparten el mismo valor (p. ej. RUC de Ecuador compartido entre sucursales) — en ese caso usa `store_id` o `external_store_id`.

Combinado con los campos ERP de las Fases 17–18, los ERPs pueden crear órdenes de compra sin conocer ningún UUID interno.

Actualizado en **EN / ES / PT**.

***

## 11 de agosto de 2026 — BOH API restructurada: un endpoint por página

La pestaña de BOH API fue completamente restructurada en páginas individuales por endpoint. Cada endpoint tiene ahora su propia entrada en el menú mostrando el método HTTP (`GET`, `POST`, `PATCH`, `DELETE`), ejemplos interactivos de request/response, y un botón **Pruébalo** para probar el endpoint directamente desde la documentación.

La nueva estructura cubre los 63 endpoints en 6 secciones: Identidad, Catálogo, Recetas, Operaciones, Compras y Webhooks.

Actualizado en **EN / ES / PT**.

***

## 11 de agosto de 2026 — BOH API: órdenes de compra — resolución por supplier\_sku y external\_user\_id

Dos adiciones a la referencia de [órdenes de compra](/es/boh-api/procurement#ordenes-de-compra):

**`supplier_sku` en líneas** — un tercer identificador de ítem para integración con ERPs. En lugar de `item_id` o `external_item_id`, envía `supplier_sku` (sin distinguir mayúsculas) y BOH resuelve el ítem directamente desde el catálogo del proveedor de la orden, derivando `base_unit_id` automáticamente. Error: `purchase_order_supplier_sku_not_found` (404).

**`external_user_id` al crear** — el identificador de usuario del llamador ahora se acepta al crear una orden de compra y se guarda como `actor_external_user_id`. Antes el campo era ignorado silenciosamente.

Actualizado en **EN / ES / PT**.

***

## 10 de agosto de 2026 — Manuales KDS: emparejamiento, tablero de operador, tache de líneas y defaults de display

Manuales KDS nuevos y actualizados con el trabajo reciente de fire-kds:

**[Emparejar un dispositivo](/es/manuals/kds/device-pairing)** — guía nueva. Enrolar TVs de cocina con código de 6 dígitos desde **KDS → Todas las tiendas**, administrar terminales emparejados y entender el cierre de sesión de dispositivo vs correo.

**[Tablero de operador](/es/manuals/kds/operator-board)** — guía nueva. Listado/detalle de supervisor con temporizadores en vivo, filtros, códigos de recolección y sobrescrituras cancelar / listo / despachar.

**[Acciones en pantalla](/es/manuals/kds/screen-actions)** — tache de líneas antes del bump, despacho esperando armado, alerta de pedido nuevo y ajustes de display más ricos (defaults de tienda, nombre del cliente por canal/fulfillment).

**[Turnero](/es/manuals/kds/waitlist)** — filtros de fulfillment (ej. ocultar delivery del turnero).

**[Descripción general](/es/manuals/kds/admin-overview)** — opciones KDS a nivel de tienda (defaults de display, line strike, motivos de cancelación) y enlaces a las guías nuevas.

Actualizado en **EN / ES / PT**.

***

## 7 de agosto de 2026 — BOH API: operaciones, identidad, sincronización masiva y endpoints de compras

La referencia de la [BOH API](/es/boh-api/introduction) ahora cubre el conjunto completo de endpoints para construir una integración completa:

**[Identidad](/es/boh-api/identity)** — nueva sección. Descubre el contexto de tu cuenta (`GET /identity/me`), lista vendors y administra establecimientos y proveedores (crear, actualizar, archivar/desarchivar).

**[Catálogo: Sync masivo](/es/boh-api/catalog-sync)** — nueva sección. Tres endpoints `PUT` de sincronización masiva:

* `PUT /catalog/units` — upsert de unidades por `code + unit_group_code`; las unidades globales se omiten sin error.
* `PUT /identity/suppliers` — upsert de proveedores por `external_supplier_id`.
* `PUT /catalog/classifications/assignments` — reemplaza todas las asignaciones de clasificación de un ítem o establecimiento de forma atómica.

**[Operaciones](/es/boh-api/operations)** — nueva sección. Cubre todos los tipos de movimiento de inventario:

* Recepciones de mercancía (crear, listar, obtener) — soporta `external_store_id` y `external_supplier_id` para no necesitar UUIDs previos.
* Conteos de inventario (crear, listar) — alcance `FULL` o `PARTIAL`, con `area_breakdown` para sesiones de conteo colaborativo por áreas.
* Mermas (crear, listar) — líneas por ítem, tag de ítems o snapshot de subreceta.
* Transferencias (crear, listar) — débito/crédito atómico entre establecimientos.
* Lotes de producción (crear, listar, obtener) — registra ejecuciones de receta con output real y overrides de ingredientes opcionales.
* Seguimiento de transacciones (estado, listar) — consulta cualquier escritura asíncrona por su `tracking_id`.

**[Compras](/es/boh-api/procurement)** — nueva sección. Ciclo de vida completo de órdenes de compra (`POST /procurement/orders` con clave de idempotencia, listar/obtener, enviar, confirmar, añadir/actualizar/eliminar líneas, cancelar, cerrar y estado de cumplimiento), además de `PUT /procurement/par-levels` para upsert de objetivos de stock por ítem/establecimiento y `GET /procurement/suggested-order` para obtener cantidades de reorden sugeridas. Las órdenes de compra también soportan **integración con ERPs mediante identificadores externos**: `external_supplier_id`, `external_item_id` y `unit_code` resuelven los registros internos del lado del servidor (sin necesidad de UUIDs de BOH), `external_reference` etiqueta la orden con tu código de documento (filtrable en el listado) y las líneas aceptan montos informativos (`tax_amount`, `delivery_amount`, `total_amount`, `markup_amount`).

Actualizado en **EN / ES / PT**.

***

## 7 de agosto de 2026 — Manuales BOH: líneas por canal, conteos colaborativos, moneda de cuenta

Tres actualizaciones en los manuales de usuario BOH que reflejan cambios recientes en el producto:

**Recetas — líneas con alcance por canal (Fase 16)**

El modelo de "complementos por servicio" fue reemplazado por **líneas con alcance por canal** en una única receta. Cada línea ahora tiene un campo opcional `service_codes`:

* Líneas sin `service_codes` son **generales** y siempre aplican.
* Líneas con `service_codes: ["DELIVERY"]` solo aplican cuando el canal de la orden coincide.
* Una única receta publicada por producto y tienda reemplaza el par BASE + COMPLEMENT anterior.

Actualizado: [Recetas — Líneas con alcance por canal](/es/manuals/boh/recipes#lineas-con-alcance-por-canal).

**Conteos — sesiones de conteo colaborativo**

Nueva sección que documenta las **sesiones de conteo en campo**: varios dispositivos pueden contar diferentes áreas de inventario de la misma tienda al mismo tiempo. Cada dispositivo reclama un área exclusiva, cuenta y la marca como lista. El dispositivo administrador finaliza la sesión, lo que crea un conteo normal.

Actualizado: [Conteos — Sesiones de conteo colaborativo](/es/manuals/boh/stock-counts#sesiones-de-conteo-colaborativo).

**Catálogo — moneda de la cuenta**

Nueva sección que documenta la configuración de **moneda de la cuenta**. Cada cuenta BOH ahora tiene una moneda ISO 4217 predeterminada (configurada en Cuenta y accesos → Configuración de cuenta) que se usa en costos de abastecimiento, precios de ítems de proveedor y reportes.

Actualizado: [Catálogo — Moneda de la cuenta](/es/manuals/boh/catalog#moneda-de-la-cuenta).

Actualizado en **EN / ES / PT**.

***

## 7 de agosto de 2026 — Listas de precios: nuevo manual de usuario

Las listas de precios permiten manejar precios distintos por canal, local o campaña sin mantener
cada uno a mano. El manual ya está disponible:
**[Listas de precios](/es/manuals/backoffice/price-lists)**.

* **Listas conectadas** — una lista puede seguir a una lista base. Cambias el precio una vez y
  llega a todas; el producto que necesita un precio propio lo fija y deja de seguirla, solo para
  ese producto. Las fórmulas tipo `=P*1.15` quedan vivas: cuando la base se mueve, la lista se
  recalcula sola.
* **Precios por contexto** — el mismo producto puede valer distinto dentro de un combo. Esos
  precios vivían escondidos en la configuración de cada combo; ahora se ven y se editan desde la
  fila del producto, con el porcentaje contra el precio suelto.
* **Edición masiva con redondeo comercial** — aplica un porcentaje o un monto a muchos productos
  de una vez, alcanzando también los precios dentro de combos, y redondea a `.99`, `.90` o número
  entero para no terminar vendiendo a 13,42.
* **Modo comparación** — superpone otra lista como referencia para ver, producto por producto,
  dónde se separan las dos.
* **Alcance antes de guardar** — un resumen de qué listas conectadas reciben el cambio y, sobre
  todo, **cuál no recibe nada** porque todos los productos que tocaste tienen precio propio ahí.
* **Conectar una lista existente** — una lista que nació como copia y quedó desactualizada puede
  conectarse a una lista base. Lo que coincide con la base pasa a seguirla, lo que tiene precio
  propio se queda como está: al conectar no se mueve ningún precio.

<Note>
  Los precios por horario (*day-parting*) todavía no están disponibles, y esta fase trabaja sobre
  el precio final con impuestos incluidos — el precio neto y el de referencia vienen después. El
  manual deja los dos límites explícitos.
</Note>

***

## 6 de agosto de 2026 — Latidos de salud de kioscos, KDS y cajas

Los kioscos, las pantallas KDS y las cajas POS ya pueden reportar que están vivos, y el tablero
de disponibilidad de Fire lee la flota a partir de esos latidos. El endpoint es
[`POST /external/component-health`](/es/api-reference/component-health) y necesita una API key
con el scope `component-health:write`.

* **[Salud de componentes](/es/api-reference/component-health)** — un latido por ciclo con
  `componentType`, `componentId`, `storeId` y `status`. Opcionales: `sentAt`, `offlineSince`,
  `degradedReason`, `appVersion` y un `details` libre. Responde `204 No Content`.
* **`X-Heartbeat-Interval`** — cada `204` trae la cadencia vigente, en segundos. Adoptala en el
  próximo ciclo: así se reconfigura el intervalo sin publicar una release.
* **El `componentId` tiene que ser estable** — si cambia entre reinicios, para Fire es otro
  componente: el viejo se da de baja a los 7 días y el nuevo arranca sin historia.
* **`degradedReason` usa un vocabulario común** — `printer_down`, `pinpad_down`,
  `backend_unreachable`, `queue_backlog`, `peripheral_other`. Las claves de `details` para
  `kds_station` todavía están por acordar con el equipo de KDS.

<Note>
  `status` solo acepta `online` y `degraded`. No existe `down`: un equipo no puede declararse
  muerto — Fire infiere la caída por la ausencia de latido, tras dos intervalos perdidos.
</Note>

## 4 de agosto de 2026 — Nuevo campo `assignedAt` en eventos de menú y producto

`menu.updated v2` y `product.updated` ahora llevan `assignedAt` en cada categoría y producto.

* **`categories[n].assignedAt`** y **`products[n].additionalInfo.assignedAt`** — fecha en que la entidad entró al menú, ISO 8601 UTC, sin milisegundos. Es un dato de **membresía**, no de edición: no cambia con ediciones de precio, nombre, imagen u orden; sí cambia (fecha nueva) cuando el ítem se quita del menú y se vuelve a agregar. Casos borde completos en [`menu.updated` → Fecha de incorporación al menú](/es/webhook-reference/menu-updated-v2#fecha-de-incorporación-al-menú). No viaja en [`product.price_updated`](/es/webhook-reference/product-price-updated) ni en [`product.availability_changed`](/es/webhook-reference/product-availability-changed) — esos eventos solo transmiten su delta.
* **[`menu.updated`](/es/webhook-reference/menu-updated-v2) / [`product.updated`](/es/webhook-reference/product-updated) usan `taxInfo`** (no `taxesInfo`), **`type: PRODUCTO`** para ítems estándar y **`modifierGroups[n].type: RADIO`** para grupos de selección única (`CHECKBOX` para múltiple).
* **`storeId` es el UUID interno de la tienda** (`stores.id`), no el `store_number` — misma convención en `menu.updated`, `product.updated`, `product.price_updated` y `product.availability_changed`.
* **El `priceInfo` de `product.price_updated` no comparte forma con el `priceInfo` de catálogo** de `menu.updated` / `product.updated` — es el precio de venta recién guardado con su descuento, no precios de catálogo.

<Note>
  `channelReferenceName` significa el **fulfillment** (`delivery`, `pickup`) en `list.stores[n].channels[n]` de `menu.updated`, pero el **canal de ventas** (`iFood`, `Rappi`) en el mismo nombre de campo de `product.updated`, `product.price_updated` y `product.availability_changed`. Misma clave, dos cosas distintas según el evento.
</Note>

Actualizado en **EN / ES / PT**.

## 4 de agosto de 2026 — Suscripción por correo al registro de cambios

Ya puedes recibir un correo cada vez que se publica una entrada nueva en esta página.
Suscríbete desde el botón de arriba — la lista la gestiona Buttondown, así que ninguna
dirección se guarda en la documentación, y un clic en cualquier correo te da de baja.

* **Un correo por entrada, en los tres idiomas** — English, Español y Português llegan
  juntos en el mismo mensaje, así que no hay nada que elegir.
* **Solo envía una entrada nueva** — corregir una errata en algo ya publicado nunca lo
  reenvía.

Actualizado en **EN / ES / PT**.

## 2 de agosto de 2026 — `order.opened` y los bloques de pago diferido

Cada evento avanza en **su propia línea de versión** — no hay un número de contrato global:

| Evento                                          | Versión                                |
| ----------------------------------------------- | -------------------------------------- |
| [`order.opened`](/es/events/order-opened)       | **v1** (evento nuevo, primera versión) |
| [`order.completed`](/es/events/order-completed) | v1 → **v1.1**                          |
| [`order.invoiced`](/es/events/order-invoiced)   | v1 → **v1.1**                          |
| [`order.cancelled`](/es/events/order-cancelled) | v2 → **v2.1**                          |

Todo lo agregado es retrocompatible (bloques nuevos sobre un shape existente). Nada de
esto cambia un campo que ya estés leyendo, y el contrato anterior de cada evento sigue
publicado detrás de su pestaña de versión.

* **Nuevo evento [`order.opened`](/es/events/order-opened)** — se dispara cuando una
  orden se inyecta **ya abierta**: existe, la cocina puede arrancar, nadie pagó
  todavía. Lleva el mismo snapshot V4 que `order.completed`. **No** se dispara para
  órdenes inyectadas como `COMPLETED` o `CANCELLED`. Este evento no tiene v0 — nació
  en v1.
* **`data.policy.deferredPayment`** — agregado a **los cuatro** eventos de orden
  (`order.opened`, `order.completed`, `order.invoiced`, `order.cancelled`). Dice si la
  orden puede cocinarse, facturarse o despacharse **antes** del pago. Se resuelve una
  vez al inyectar y se estampa inmutable; todos los eventos posteriores repiten el
  mismo valor.
* **`data.lastKnown`** — agregado a esos mismos cuatro eventos. Foto orientativa del
  estado de cocina y fiscal. **Nunca condiciones una acción irreversible a este
  campo** — puede venir `null` o viejo, y el propio Fire lo ignora y relee de la
  fuente antes de emitir nada.

<Note>
  En `order.opened`, `payments.paymentMethods[]` es lo que el POS **declaró**, no lo que
  se cobró — `transactionStatus` viene en `PENDING` y `transactionId` normalmente vacío.
  Fire sobreescribe el arreglo con los tenders reales cuando entra el cobro, y emite
  `order.completed`. Leer el medio declarado como evidencia de cobro es el error más
  común con este evento.
</Note>

Actualizado en **EN / ES / PT**.

## 22 de julio de 2026 — Manuales de usuario BOH

Añadida la sección **BOH** en la pestaña Manuales de usuario, cubriendo la administración del inventario back-of-house desde el Fire backoffice:

* **[Descripción general y conceptos](/es/manuals/boh/admin-overview)** — cómo encajan catálogo, recetas, abastecimiento, movimientos, conteos y reportes; el flujo de stock; mapa del menú BOH.
* **[Tiendas y proveedores](/es/manuals/boh/stores-suppliers)** — tiendas BOH vinculadas a Restaurant OS y proveedores con vínculos ítem–proveedor (precio, unidad de compra, SKU).
* **[Catálogo](/es/manuals/boh/catalog)** — grupos de unidad y unidades, ítems, etiquetas de ítems intercambiables (FIFO / FEFO / prioridad / mayor stock), clasificaciones.
* **[Recetas](/es/manuals/boh/recipes)** — recetas de venta, producción y subrecetas; ciclo borrador → publicada → archivada; líneas por canal; simulador de venta.
* **[Abastecimiento](/es/manuals/boh/procurement)** — programaciones de recepción, ciclo de vida de las órdenes de compra, niveles par y pedido sugerido.
* **[Recepciones y devoluciones](/es/manuals/boh/goods-receipts-returns)** — recepciones de mercancía (entrada de stock, vínculo a OC, sobre-recepción) y devoluciones a proveedor.
* **[Mermas y consumos internos](/es/manuals/boh/waste-consumption)** — catálogo de razones de merma, eventos de merma, consumos internos.
* **[Transferencias y producción](/es/manuals/boh/transfers-production)** — transferencias entre tiendas y lotes de producción con rendimiento.
* **[Conteos](/es/manuals/boh/stock-counts)** — áreas de inventario, conteos completos/parciales y la app móvil de conteo.
* **[Reportes](/es/manuals/boh/reports)** — usos y consumos, mermas, rendimiento de producción y balance a fecha.

Las 10 páginas publicadas en **EN / ES / PT**.

***

## 13 de julio de 2026 — Cancelar orden: campo `cancellationType`

Añadido el campo opcional `cancellationType` (`string`) al body de [Cancelar orden](/es/api-reference/cancel-order). Cuando se envía, el ID o código del motivo de cancelación del catálogo se persiste en la orden y se reporta al gateway de pago. Actualizado en **EN / ES / PT**.

## 3 de julio de 2026 — Inyectar orden: distribución de descuento en combo

Añadida la sección [Descuentos de combo](/es/api-reference/orders#descuentos-de-combo) en la referencia de Inyectar orden.

Cuando un producto `COMBO` tiene precio contenedor 0, el `discountsValue` del combo **no debe** colocarse en la línea del contenedor (produce totales negativos). En su lugar, hay que distribuirlo proporcionalmente entre los `selectedModifiers`:

* `discount_i = ROUND(D × (base_i / B), 2)` — parte proporcional por modificador
* Cada modificador debe mantener `subtotalIncludeDiscounts >= 0` y `total >= 0` tras el descuento
* El contenedor COMBO debe tener todos los campos de precio en `0`
* `SUM(modifier.totalPrice.discountsValue)` debe igualar el descuento total del combo

Incluye ejemplo JSON antes/después (descuento BRL 17,94 en un combo de 7 ítems, base BRL 89,68) y tabla de desglose completo. Actualizado en **EN / ES / PT**.

## 29 de junio de 2026 — Manuales de usuario KDS

Añadida la sección **KDS** en la pestaña Manuales de usuario, cubriendo tanto el uso por parte del operador como la administración desde el backoffice:

* **[Descripción general y conceptos](/es/manuals/kds/admin-overview)** — cómo encajan tiendas, estaciones, pantallas, enrutamiento, dispositivos e impresión; dos tipos de estación (producción vs convergencia); patrones de cocina (solo ensamblaje, KITCHEN, multi-estación).
* **[Configurar una tienda](/es/manuals/kds/store-setup)** — aplicar una plantilla (asistente de blueprint) o configurar desde cero; orden recomendado de pasos.
* **[Estaciones](/es/manuals/kds/stations)** — campos, reglas opcionales por canal / servicio / tipo de ítem, creación paso a paso.
* **[Pantallas](/es/manuals/kds/screens)** — identificador de dispositivo, crear y asignar estaciones, relación pantalla ↔ estación.
* **[Enrutamiento](/es/manuals/kds/routing)** — capas de decisión (enrutamiento → reglas → distribución → convergencia), modos de distribución, ejemplo multi-estación.
* **[Periféricos, impresión y validación](/es/manuals/kds/peripherals-printing)** — teclados, impresión de recogida (una pantalla por tienda), cancelación de órdenes, checklist de go-live y rutas de referencia.
* **[Acciones en pantalla](/es/manuals/kds/screen-actions)** — avanzar, retener/liberar, deshacer, cancelar, paginación, menú de configuración y atajos de teclado.
* **[Pantalla de espera](/es/manuals/kds/waitlist)** — pantalla para clientes (áreas en preparación / listo, destaque al pasar a listo, paginación automática).

Las 8 páginas publicadas en **EN / ES / PT**.

## 22 de junio de 2026 — Nueva guía: Estructura de productos · Publicación de menús actualizada

### Nueva guía: Estructura de productos

Nueva página [Estructura de productos](/es/guides/combo-products) en la pestaña Guías — cubre el tipo `COMBO` y los overrides de modificadores:

* **Tipo COMBO** — `priceInfo.price` es siempre `0`; usar `priceInfo.referencePrice` como precio de encabezado del producto.
* **Precio de referencia** — suma de (opción más barata × `minOptions`) en cada grupo de modificadores obligatorio (`minOptions ≥ 1`).
* **Overrides de modificadores** — `productModifiers[n].overrides` define un precio diferente para una opción dentro de un combo específico; tiene precedencia sobre el precio base del producto en `products[]`.
* **Precios delta** — grupos obligatorios muestran `+R$ X` respecto al baseline; grupos opcionales muestran el precio completo del add-on.

### Guía de publicación de menús

* Eliminada la sección `menus.sync` — ese evento ya no existe.
* Corregido el formato del payload: `event` es ahora un objeto anidado (`id`, `type`, `executionId`, `createdAt`), no campos al nivel raíz.
* El paso de verificación de firma ahora especifica que el signing secret se obtiene en **Integraciones de agregadores** en el dashboard de Fire.
* Añadida sección de estructura del menú con descripción de `list`, `categories`, `products` (tabla de tipos) y `modifierGroups`.

Actualizado en **EN / ES / PT**.

## 15 de junio de 2026 — `order.completed` — nuevos campos de método de pago

Añadidos 4 campos a `payments.paymentMethods[n]` en el evento [`order.completed`](/es/events/order-completed). Todos son nullable y ya están en producción.

* **`idAuth`** (`string | null`) — ID de autorización del procesador de pago (ej. SiTef `IdAuth`). Distinto de `authorizationCode`.
* **`receiptCustomer`** (`string | null`) — Texto completo del comprobante para el cliente; puede ser multilínea.
* **`receiptMerchant`** (`string | null`) — Texto completo del comprobante para el comercio; puede ser multilínea.
* **`acquirer.cnpj`** (`string | null`) — CNPJ de la credenciadora de pago — solo Brasil.

Actualizado en **EN / ES / PT**.

## 15 de junio de 2026 — Campos de detalle de método de pago

Añadidos 5 campos opcionales a `payments.paymentMethods[n]` en [Inyectar orden](/es/api-reference/orders):

* **`id_auth`** (`string | null`) — Número de autorización NFCE (SiTef 952 / IdAuth).
* **`receipt_customer`** (`string | null`) — Vía del cliente: texto del comprobante impreso para el portador (SiTef 121 / ReceiptCustomer).
* **`receipt_merchant`** (`string | null`) — Vía del comercio: texto del comprobante impreso para el establecimiento (SiTef 122 / ReceiptMerchant).
* **`acquirer.cnpj`** (`string`) — CNPJ de la credenciadora para NFCE (SiTef 950 / CNPJAuth). `acquirer` queda documentado como nullable — enviar `null` para métodos sin credenciadora.
* **`card.media`** (`string`) — Tipo de lectura de la tarjeta: `CHIP`, `MAGNETIC`, `NFC`, `MANUAL` (SiTef 2090 / Media). `card` queda documentado como nullable — enviar `null` para métodos sin tarjeta.

Todos los campos son opcionales y ya están implementados en el validador. Actualizado en **EN / ES / PT**.

## 14 de junio de 2026 — Webhook de estado de orden de agregador

* **Nuevo webhook entrante [`POST /v1/webhooks/aggregators/order-status`](/es/api-reference/aggregator-order-status)** — tu agregador de delivery (Rappi / Uber / Didi / iFood / PedidosYa / Glovo…) hace POST con el estado de entrega de la orden a medida que avanza (`courier_assigned` → `on_route` → `delivered`…). Fire refleja el último estado en `orders.aggregator` y registra cada evento.
* **El estado es passthrough** — no se impone ningún enum; las etiquetas propias del agregador se guardan **tal cual**, y el estado **actual** es el del **`occurredAt` más reciente** (sin compuerta anti-regresión). Las etiquetas amigables y traducidas se resuelven al momento de mostrar desde el catálogo del canal.
* **Correlación flexible de la orden** — envía `orderId` (UUID de Fire) **y/o** `externalOrderId` (tu referencia, comparada contra `metadata.order_id`); al menos uno es requerido, ambos vendor-scoped. Si envías ambos y correlacionan a órdenes **distintas** → `409`.
* **No hay un `eventId` emitido por Fire para ecoar** — un estado de agregador es un evento externo espontáneo (Fire no es la fuente de verdad aquí). La idempotencia se llavea por `(channelCode, providerEventId)` + `status`; `channelCode` debe ser igual al `metadata.channel.code` de la orden.
* **Auth**: API key vendor-scoped con el nuevo scope **`webhooks:aggregator`**. `202` async + cola, mismo envelope que los callbacks fiscal / KDS.
* Documentado en **EN / ES / PT**.

## 12 de junio de 2026 — Descuentos del agregador en Inyectar orden

Documentado cómo enviar descuentos promocionales del agregador (iFood, Rappi, UberEats, etc.) en el endpoint [Inyectar orden](/es/api-reference/orders).

* **Los descuentos del agregador son un método de pago, no una fila de descuento.** Cuando el agregador aplica un descuento al cliente, el local recibe el importe completo y el agregador reembolsa la diferencia — modélalo como una entrada extra en `payments.paymentMethods[]` con `paymentMethodCode: "AGGREGATOR_DISCOUNT"`, `transactionType: "BENEFIT"`, `processor` con el nombre del agregador y `card: null`.
* **`payments.discounts[]` queda vacío** para descuentos del agregador — ese array es solo para promos/cupones que absorbe el local.
* Nueva regla de balance documentada: `SUM(paymentMethods[].totalBill)` debe ser igual a productos + cargos extra + envío.
* Nuevo [ejemplo de request](/es/api-reference/orders#descuentos-del-agregador) con una orden de iFood (BRL 38.69 CREDIT + BRL 1.00 AGGREGATOR\_DISCOUNT = BRL 39.69 bruto).
* Actualizado en **EN / ES / PT**.

## 11 de junio de 2026 — Nomenclatura underscore + payload thin de cierre de día

* **Nombres (breaking)** — `store.day-closed` → **`store.business_day_closed`** y `order.status-updated` → **`order.status_updated`** (nomenclatura underscore). Actualiza tu switch de `event.type`.
* **[`store.business_day_closed`](/es/events/store-day-closed) ahora es un payload thin** — identidad del cierre (`businessDayId`, `businessDayDate`, `timezone`, `status`), timing (`openedAt`/`closedAt`), `closedBy` y una **`store` mínima** (`uid`, `code`, `externalId`, `countryCode`, `timezone`, `currencyCode`). **Removido del evento**: `sales`, `metrics`, `summary`, `byChannel`, `byPaymentMethod`, `forceClosedOrders`, `closureStats`, `cancelledOrders`, `metadata` — consúltalos por `businessDayId` cuando los necesites. **`snapshotId` renombrado a `businessDayId`** (mismo valor).
* Documentado en **EN / ES / PT**.

## 10 de junio de 2026 — Eventos canónicos de orden + evento de cocina

Los eventos fiscales pierden el país del nombre y pasan a ser **canónicos de orden** — sigue siendo el contrato **v1**, solo cambia el `event.type`:

* **`fiscal.authorized.br` → [`order.invoiced`](/es/events/order-invoiced)** y **`fiscal.cancelled.br` → [`order.reversed`](/es/events/order-reversed)**. Si tu integración despacha por `event.type`, actualiza el switch — el payload no cambia de forma.
* **Ahora disparan para todos los países**: Brasil (SEFAZ vía tu proveedor fiscal) y CO/EC/CL/AR/VE vía el [callback fiscal genérico](/es/api-reference/fiscal-callback). El país viaja en `fiscal.countryCode`.
* **Nuevo evento [`order.status_updated`](/es/events/order-status-updated)** — el KDS avanza la orden en cocina (`preparing` → `ready` → `dispatched`), con bloque `kitchen` y el recorrido completo en `history`.
* **Fire es la fuente de verdad** — los webhooks entrantes ([callback fiscal](/es/api-reference/fiscal-callback), [estados KDS](/es/api-reference/kds-order-status)) ahora **validan que `eventId` referencie un evento emitido por Fire para esa orden**; si no, responden `400` antes del `202`. Ecoa siempre el `event.id` de un envelope que recibiste.
* Documentado en **EN / ES / PT**.

## 9 de junio de 2026 — Contrato de eventos **v1**

El contrato de eventos de orden/fiscal/cierre es ahora oficialmente **v1**. Todas las adiciones son **retrocompatibles** (campos opcionales nuevos); la forma anterior se preserva como **v0 (deprecada, histórica)** — cambia con el selector de versión arriba de cada página de evento.

* **Descuentos** — descuentos de orden y de producto viajan como objeto **`Discount`** (`priority`, `type` `FIXED`/`PERCENTAGE`, `value`, `net_price`, `discount_value`, `net_price_after_discount`) en `payments.discounts`, `payments.totals[].discounts` y `orderLines[].price.*[].discounts` + `lineTotals[].discounts`.
* **Impuestos granulares** — `taxes[]` ahora lleva los impuestos de la reforma BR `IBS_UF`, `IBS_MUN`, `CBS` junto a `ICMS`/`PIS`/`COFINS`, con metadata de reforma (`cClassTrib`, `reducao`, `rateNominal`, `rateEffective`). El desglose es **uniforme en todos los países** — LATAM lleva su `IVA` local en el mismo `taxes[]`; solo la emisión SEFAZ (`metadata.fiscal`, `fiscal.*.br`) es BR-only.
* **`itemType`** — enum completo: `PRODUCT` / `COMBO` / `MODIFIER` / `PACKAGING`.
* **`fulfillment.delivery.deliveryConfirmationCode`** — código de confirmación del agregador (ej. iFood / Rappi).
* **store.business\_day\_closed** — `sales` ahora incluye `product_discounts`, `gross_before_discounts`, `shipping`, `extra_charges`, `total_charged` y `taxes_by_type`. *(Superado el 11 de junio — estos agregados ya no van embebidos en el evento; el payload de cierre ahora es thin. Ver la entrada de arriba.)*
* **order.cancelled / order.invoiced / order.reversed** — llevan el snapshot v1 de orden.
* Documentado en **EN / ES / PT** con ejemplos actualizados.

## 8 de junio de 2026

* **menu.updated**: añadido `productModifiers[n].overrides[]` — permite definir un precio diferente para una opción específica de modificador cuando pertenece a un producto concreto. Cada override apunta a un `productId` y proporciona su propio `priceInfo.price` y `priceInfo.salePrice`. Actualizado EN/ES/PT.

## 5 de junio de 2026

* **menus.sync**: página eliminada — Fire envía un único evento `menu.updated` por menú; la sincronización en lote ya no es un evento separado.

* **menu.updated**: campo `event.timezone` eliminado del payload. Añadido `data.groupId` — UUID que identifica el batch de sincronización; varios eventos emitidos juntos comparten el mismo valor, lo que permite correlacionarlos en sistemas externos. Los arrays `schedules` de categorías y productos ahora incluyen ejemplos completos de 7 días con distintas ventanas de horario por categoría (p. ej. Hamburguesas 11:00–23:00, Desayunos 07:00–11:00). Campo `standardTime` en productos documentado: `true` hereda los horarios del menú, `false` significa que el producto tiene su propio array `schedules`. Actualizado EN/ES/PT.

* **Inyectar orden**: el campo `type` es ahora **obligatorio** en cada ítem de `order.products[]`, en cada ítem de `selectedModifiers[]` y en cada ítem de `payments.extraCharges[]`. Valores aceptados: `COMBO` (producto con grupos de modificadores no vacíos), `PRODUCT` (producto simple vendible o opción vendible dentro de modificadores), `MODIFIER` (opción de modificador puro), `PACKAGING` (ítem de empaque). Los payloads que omitan `type` son inválidos. Ejemplos de petición actualizados en EN/ES/PT.

* **Inyectar orden**: documentado `shippingMethod.delivery.additionalInfo.deliveryConfirmationCode` como string opcional para enviar el código de confirmación de entrega.

## 1 de junio de 2026

* **Inyectar orden**: secciones **Montos y tramos de precio** y **Envío y descuentos**; tres ejemplos de petición conciliados (entrega simple, descuento en línea + envío, varios productos + descuento de orden); énfasis en `payments.shippingCost[]`, `payments.discounts[]` y `discountsValue` por producto (EN/ES/PT).

## 27 de mayo de 2026

* **menus.sync**: ejemplo de payload completo (categorías, productos, grupos de modificadores, horarios); `data.menus[]` reemplazado por `data.menu` (un menú por evento); páginas EN/ES/PT en webhook reference.
* **menu.updated**: estructura general alineada con `menus.sync` — campos del catálogo (`list`, `categories`, `products`, `modifierGroups`, `scheduledActivities`) anidados bajo `data.menu`; tablas de campos y ejemplo de borrado actualizados.
* Guía **Publicación de menú** (EN/ES/PT): ejemplos y pasos de procesamiento actualizados para `data.menu`.
* **Inyectar orden**: campo opcional `comment` documentado en `order.products[]`; ejemplo de petición actualizado (sustituye `productComment`).
* **menu.updated** / **menus.sync**: los `productId` de las opciones de modificador deben existir en `products`; el ejemplo incluye `prod_size_small` y `prod_size_large`.
* **menu.updated**: corregida la indentación del ejemplo principal del payload bajo `data.menu`.
* **Webhooks de menú** (`menu.updated`, `menus.sync`, **product.updated**): `data.country` documentado y ejemplificado como **ISO 3166-1 alpha-2** (p. ej. `EC`, `BR`, `CO`) en lugar de un ID numérico de país.

## 26 de mayo de 2026

* Agregada la pestaña **Manuales de usuario** como sección principal de la navegación.
* Agregados manuales de FIRE POS V2 para **Vinculación**, **Cajeros** y **Códigos de autorización** en inglés, español y portugués.
* Agregadas imágenes placeholder sutiles para las capturas pendientes de POS, manteniendo la estructura visual final de las guías mientras se preparan las capturas.
* **Inyectar orden**: eliminado el campo `order.stock` del cuerpo (no aplica al contrato). Ejemplo de respuesta **200** actualizado al sobre real (`data`, `isArray`, `status`, `method`, `pathname`, `duration`, `traceId`).
* **Login** (playground): `authMethod: none`, URL absoluta de staging en el frontmatter `api:`, cabecera `Content-Type` con valor por defecto y `grant_type` por defecto para evitar el error *Missing required fields* al usar **Probar**.
* **Inyectar orden**: `price` de línea de producto documentado con todos los campos del **tramo de precio** y `taxes[]` (`name`, `rate`, `amount`, `metadata` opcional).
* **Inyectar orden**: `payments.shippingCost[]` y `payments.discounts[]` documentados como las mismas filas de tramo de precio que `totals[]`; ejemplo de petición actualizado con líneas de envío y descuento.
* **Cancelar orden**: referencia API actualizada a la ruta de agregador `POST /api/v4/integrations/sales/aggregator/orders/{order_uid}/refund`, con campos de cancelación/reembolso y sobre estándar de respuesta; movida debajo de **Inyectar orden** en la referencia API.

## 11 de mayo de 2026

* Nueva pestaña **Cambios** al final de la navegación y esta página inicial.
* Eliminada la página de **canales de venta** (listado) y su entrada en la navegación (todos los idiomas).
* **Intro de la API**: texto ajustado; retirada la tarjeta de canales de venta.
* **Inyectar orden**: documentada la cabecera `Authorization` (EN). **ES y PT**: ruta, cabeceras y cuerpo actualizados al contrato actual de integración (objetos de canal/servicio, dispositivo, operador, ejemplos).
* **Login** (**ES** y **PT**): alineado con `POST /api/authentication/login` y respuesta `accessToken` (client credentials).
* **Inicio en español** (`/es/`): contenido revisado.
* **Configuración**: nueva guía **Integraciones de agregadores** (panel Fire: endpoints de webhook y eventos de prueba).
