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

# Realizar pedidos

> Flujo de checkout de punta a punta desde el menú hasta el ticket en cocina.

Esta guía explica cómo un pedido pasa de tu app o web a Fire spark y luego a cocina.

## El recorrido en términos simples

1. **Explorar** — El cliente elige tienda, canal y `fulfillment_id`, y carga el [menú compuesto](https://firespark.cloud/docs/es/storefront-api/menus/get.md).
2. **Personalizar** — Usa `@fire-spark/storefront` (`createSession` / `toOrderLines`) para convertir un producto personalizado en filas `OrderLine` con precios.
3. **Abrir carrito** — Llama a [Crear pedido](https://firespark.cloud/docs/es/storefront-api/orders/post.md) con el alcance (y normalmente `lines` vacías). `201` es un carrito nuevo; `202` es el `OPEN` que ya existe para ese alcance — usa el `id` de la respuesta.
4. **Sincronizar carrito** — Aplica debounce a los cambios locales y [Actualizar pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/patch) con `lines` + `totals`.
5. **Validar** — Antes del checkout, llama a [Validar pedido](https://firespark.cloud/docs/es/storefront-api/orders/validate/post.md) (o `order.validateOrder()` en `@fire-spark/storefront`) para comprobar precios y disponibilidad contra un menú fresco.
6. **Pagar y colocar** — Guarda los tenders con [Guardar intent de pago](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/payment-intent/put) (`order.setTenders`) o pasa un solo método al colocar. Luego llama a [Colocar pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/place/post) (`order.placeOrder()`). Pasa `intent_id` para bloquear ese borrador. Omítelo para armar un tender real desde `payment.type` más un tender `REDEMPTION` por cada `payment_id` de canje. No hay efectivo por defecto: sin `intent_id` ni `payment.type`, place falla con `PAYMENT_REQUIRED` salvo que los canjes cubran el total (entonces solo tenders `REDEMPTION`). El carrito pasa a `CLOSED` y arranca fulfillment.
7. **Seguimiento** — Suscríbete con `realtime.listenOrder({ orderId })` (ver [Emitir token realtime](https://firespark.cloud/docs/es/storefront-api/realtime/token/post.md)) o consulta [Obtener fulfillment](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/fulfillment/get) para `checkout_state`, estados visitados y `current_node_ids`. En el historial usa [Listar fulfillments](https://firespark.cloud/docs/es/storefront-api/orders/fulfillments/get.md) en vez de un GET por pedido. [Obtener pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/get) sigue exponiendo `fulfillment_status`. Cómo espera el overlay se configura en el [workflow de fulfillment](https://firespark.cloud/docs/es/guides/fulfillment-workflows.md).

## Requisitos previos

* Cliente registrado y autenticado mediante [intercambio de token](https://firespark.cloud/docs/es/storefront-api/oauth/exchange/post.md)
* Ids de tienda, canal y fulfillment desde [Listar tiendas](https://firespark.cloud/docs/es/storefront-api/stores/get.md) y [Listar fulfillment](https://firespark.cloud/docs/es/storefront-api/fulfillment/get.md)
* Menú cargado para la misma combinación de tienda, canal y fulfillment

## Paso 1 — Generar líneas con precio desde la personalización

```javascript theme={null}
import { createSession, indexMenu, toOrderLines } from "@fire-spark/storefront";

const lookup = indexMenu(menu);
const session = createSession(lookup, productId);
// ... el cliente elige modificadores vía session ...
const lines = toOrderLines(session.root);
```

## Paso 2 — Asignar ids antes de crear

Genera el id del pedido en tu servidor **antes** del POST. Así los reintentos son seguros si se pierde la conectividad.

```javascript theme={null}
const orderId = `ord-${crypto.randomUUID().slice(0, 8)}`;
```

## Paso 3 — Crear y luego actualizar el pedido

```bash theme={null}
curl -X POST "https://firespark.cloud/api/storefront/v1/orders" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "ord-48291",
    "store_id": "downtown",
    "channel_id": "app",
    "fulfillment_id": "delivery",
    "customer": {
      "customer_info": {
        "display_name": "Ada Lovelace",
        "first_name": "Ada",
        "last_name": "Lovelace",
        "email": "ada@example.com",
        "phone": "+15551234567"
      }
    },
    "lines": [],
    "totals": {
      "currency": "USD",
      "subtotal": 0,
      "discount_rate": 0,
      "discount_total": 0,
      "tax_rate": 0,
      "tax_total": 0,
      "total": 0
    }
  }'
```

Después haz PATCH de `lines` y `totals` cuando cambie el carrito. La clase headless `Order` de `@fire-spark/storefront` aplica debounce a esas actualizaciones por ti.

## Paso 4 — Validar antes del checkout

```bash theme={null}
curl -X POST "https://firespark.cloud/api/storefront/v1/orders/validate" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "store_id": "downtown",
    "channel_id": "app",
    "fulfillment_id": "delivery",
    "lines": [],
    "totals": {
      "currency": "USD",
      "subtotal": 0,
      "discount_rate": 0,
      "discount_total": 0,
      "tax_rate": 0,
      "tax_total": 0,
      "total": 0
    }
  }'
```

En un `422`, usa `details.issues` y `details.lines` para actualizar la UI del carrito. Ver [Validar pedido](https://firespark.cloud/docs/es/storefront-api/orders/validate/post.md) para cada código de error.

## Paso 5 — Colocar el pedido

```javascript theme={null}
await order.setTenders([
  {
    method: "CARD",
    provider: "kushki",
    collect_at: "DEVICE",
    allocation: null
  }
]);
await order.placeOrder();
```

`placeOrder()` sin `intent_id` guarda el borrador y coloca con él. `placeOrder({ payment })` es el atajo de un solo método. Una sincronización del carrito rechazada sale como `OrderSyncRejectedError` y no se coloca nada; sin un tender real lanza `OrderPaymentRequiredError`. `201` inicia fulfillment. `202` significa que ya hay un place en curso. `409` significa que el pedido ya fue colocado.

## Paso 6 — Mostrar el estado al cliente

Consulta [Obtener fulfillment](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/fulfillment/get) para estados visitados (`entered_at`), `current_node_ids` y milestones. En un listado de pedidos cerrados, llama [Listar fulfillments](https://firespark.cloud/docs/es/storefront-api/orders/fulfillments/get.md) una vez. [Obtener pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/get) sigue exponiendo `fulfillment_status`.

Cocina y POS avanzan el walker con [Actualizar estado](https://firespark.cloud/docs/es/integrations-api/orders/\[id]/status/patch).

## Paso 7 — Cancelar o reembolsar

Si el cliente cancela antes del fulfillment, llama a [Cancelar pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/cancel/post). Eso interrumpe un workflow de fulfillment en curso. En un kiosco, Cancelar durante la espera de liberación del checkout llama a [Reabrir pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/reopen/post): se anulan los tenders sin cobrar y vuelve un pedido `OPEN` nuevo. `order_id` es opcional y puede ser cualquier id de `genId` (`genOrderId` es una opción y sigue devolviendo `ord-<tienda>-<hash>`); omítelo para conservar el id generado. `genId().hash(length, format)` usa un hash de al menos 8 caracteres (por defecto 12; `alphanumeric`, `numeric` o `alphabetic`). `genId().literal("BB21921").hash(8, "numeric").build()` produce un id como `BB2192100000001`. Después de fulfilled, [Reembolsar pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/refund/post) está disponible durante 24 horas. Un tender se reembolsa con [Reembolsar tender](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/tenders/\[tenderId]/refund/post).

## Enlaces relacionados

> [card] [Crear pedido](https://firespark.cloud/docs/es/storefront-api/orders/post.md)
>
> Abrir un pedido con alcance

> [card] [Actualizar pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/patch)
>
> Sincronizar líneas y totales

> [card] [Validar pedido](https://firespark.cloud/docs/es/storefront-api/orders/validate/post.md)
>
> Comprobar líneas contra un menú fresco

> [card] [Colocar pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/place/post)
>
> Cerrar el carrito e iniciar fulfillment

> [card] [Guardar intent de pago](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/payment-intent/put)
>
> Tenders antes de colocar

> [card] [Reabrir pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/reopen/post)
>
> Anular tenders sin cobrar y abrir un carrito nuevo

> [card] [Cancelar pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/cancel/post)
>
> Detener fulfillment antes de que el pedido se cumpla

> [card] [Reordenar](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/reorder/post)
>
> Clonar un pedido fulfilled en un carrito OPEN

> [card] [Reembolsar pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/refund/post)
>
> Reembolsar un pedido fulfilled dentro de 24 horas

> [card] [Obtener fulfillment](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/fulfillment/get)
>
> Estados visitados y milestones

> [card] [Listar fulfillments](https://firespark.cloud/docs/es/storefront-api/orders/fulfillments/get.md)
>
> Historial sin N+1 peticiones

> [card] [Listar pedidos](https://firespark.cloud/docs/es/storefront-api/orders/get.md)
>
> Historial de pedidos

> [card] [Concepto: pedidos](https://firespark.cloud/docs/es/concepts/orders.md)
>
> Visión comercial


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.