Skip to main content
Esta guía describe el flujo completo para construir un checkout externo con Ordering API, desde la identificación del customer hasta la creación del pedido. Todas las llamadas usan Authorization: Bearer <token> con scope orderingApi. El customer se identifica con externalCustomerId; ese ID pertenece a la app autenticada y no se comparte con otras apps.
Selecciona siempre una dirección del customer antes de marketplace, carrito u orden. Ordering API toma cityId y placeId desde esa dirección; no los envíes como parámetros configurables.

Flujo

1. Crear o actualizar customer

Crea el customer antes de armar el carrito. Esto permite reutilizar direcciones y mantener datos reales de contacto por app.
Envía email, phone, firstName y lastName cuando estén disponibles. El email real no se usa como identidad técnica del usuario interno; Ordering API lo guarda separado y lo copia en Order.email al crear la orden. Para pagos en efectivo o websites que exigen teléfono validado, envía email y phone reales en el customer; Ordering API los usa como snapshot del pedido y no requiere una sesión web del cliente.

2. Dirección y ubicación seleccionada

Para delivery, la app debe trabajar con una dirección normalizada. Primero lista direcciones existentes del customer y reutiliza una si corresponde.
Si no hay una dirección adecuada, créala:
La dirección entrega el placeId y datos normalizados para cobertura. Cuando el servicio puede resolver cityId, Ordering API lo guarda junto a la dirección seleccionada. Para go o serve, puedes omitir dirección, pero igual debes seleccionar un local compatible. Selecciona la dirección una vez para el customer:
La selección queda guardada a nivel customer y app. No tienes que repetirla para cada website. Esto guarda selectedAddressId, selectedPlaceId y selectedCityId en el customer. Marketplace, catálogo, carrito y creación de orden usan esa dirección seleccionada internamente.

3. Seleccionar website con marketplace

Usa marketplace para mostrar comercios disponibles según la dirección seleccionada del customer. Estas rutas viven bajo el customer, por lo que Ordering API resuelve cityId, placeId y menú desde la dirección guardada y sus preferencias.
Cada resultado incluye datos del comercio, websiteId, storeId, baseURL, cobertura y tiempos estimados. Para continuar el checkout necesitas el domain canónico del website, sin protocolo ni www..
Después de que el customer elige un comercio, carga sus datos públicos:

4. Obtener menú y estado del carro

Obtén el catálogo del website antes de mostrar productos. Ordering API toma el menuId desde las preferences del customer. Si todavía no hay un menú guardado, usa el menú por defecto del website. /products devuelve products, categories y categoryTree; úsalo como fuente única de catálogo y navegación.
Para catálogos grandes, parte con búsqueda o categorías y carga el detalle solo cuando el customer abre un producto. El detalle trae availabilityAt, maxPurchaseQuantity y modifiers. Lee también el estado inicial del carrito:
La respuesta de GET /cart es directamente el OrderPreferences calculado por el servicio preferences. Usa data.address, data.store, data.website y data.cart como fuente de verdad para dirección, local, website, medios de pago, horarios y totales. Si el customer tiene una dirección seleccionada, Ordering API la aplica automáticamente al leer o recalcular el carrito. No envíes cityId, placeId ni menuId; Ordering API obtiene ubicación y menú internamente y devuelve el OrderPreferences ya resuelto.

5. Agregar o editar productos

Antes de agregar un producto, valida:
  • availabilityAt.available debe ser true.
  • amount no debe superar maxPurchaseQuantity, si existe.
  • Cada modificador obligatorio debe cumplir min y max.
  • No envíes opciones con availabilityAt.available: false.
  • Si una opción tiene requiresModifierOptionIds, selecciónala solo cuando las opciones requeridas ya estén elegidas.
Después de agregar o actualizar un item, usa data.item._id y data.state.cart.items para guardar el cartItemId real y mostrar precios calculados. Si cambias comentario o modificadores, el cartItemId puede cambiar porque el carrito agrupa items equivalentes. No recalcules totales solo en cliente.

6. Configurar local, entrega, horario y pago

Guarda las decisiones estables del carrito en preferencias.
Para delivery, selecciona una dirección del customer antes de listar locales. Para retiro o consumo en local, consulta locales y elige uno que acepte el tipo de entrega.
Después de definir deliveryType, storeId y, para delivery, dirección, lee GET /cart. Usa data.store.availableScheduleDaysOptions para elegir agenda y data.store.availablePaymentMethods para elegir paymentType. Si usas tarjeta guardada o subtipo de pago, envía cardId y otherPaymentType por separado. Después de cada cambio importante, vuelve a leer el carrito:
Usa esa respuesta como fuente de verdad para itemsPrice, deliveryFee, serviceFee, calculatedTipAmount, totalPrice, amountToPay, couponStatus y beneficios.

7. Revisar billing, custom params y estado temporal

Antes de crear el pedido, revisa si el website exige facturación: Lee la configuración dinámica de billing desde data.options.billing en GET /cart. Si data.options.billing.required es true, guarda billing antes de crear la orden usando PATCH /cart/preferences.
Para billing y campos propios del checkout, guarda billing y orderParams en PATCH /cart/preferences antes de crear la orden. POST /orders solo recibe idempotencyKey; estos campos se validan al crear el pedido según la configuración del website.
Usa PATCH /cart/preferences para guardar parámetros de checkout como billing, tip, cashAmount, gift, orderParams, meta y datos equivalentes. No envíes selectedAddressId, cityId ni placeId en este endpoint; la dirección siempre sale del customer. Estos datos vuelven como campos directos en GET /cart (data.billing, data.tip, data.orderParams, etc.) y expiran automáticamente. Antes de iniciar el flujo de compra, el integrador debe pedirle al usuario final que acepte los términos y condiciones de Justo. Para mostrar los términos del website seleccionado, usa Términos y condiciones de Justo. Ordering API no muestra un checkbox propio dentro del checkout API.

8. Crear pedido

Antes de llamar POST /orders, valida que:
  • El customer exista y tenga email real si necesitas notificaciones.
  • El carrito tenga items.
  • No haya productos o modificadores no disponibles.
  • deliveryType, storeId, paymentType y time estén definidos en orderPreferences.
  • Para delivery, exista una dirección seleccionada en el customer.
  • Billing esté guardado si el website lo exige.
  • Custom params estén en orderParams y el integrador ya haya obtenido la aceptación de términos del usuario final.
  • idempotencyKey sea estable para reintentos del mismo checkout.
Envía solo idempotencyKey en el body. Ordering API arma el pedido con:
  • idempotencyKey desde el body de POST /orders.
  • storeId, deliveryType, paymentType, time, couponCode, cardId, dropOffType, tableName y menuId desde OrderPreferences.
  • billing, tip, cashAmount, gift, orderParams, sessionBirthday y meta desde PATCH /cart/preferences.
  • Email, teléfono y nombre desde el customer guardado con PUT /customers/{externalCustomerId}.
El idempotencyKey debe ser el mismo en reintentos del mismo checkout y distinto para intentos nuevos. Las órdenes creadas por este endpoint siempre quedan asociadas a la app autenticada mediante orderingAPIAppId, se crean como órdenes marketplace y usan embeddedVendor: orderingAPI.

9. Consultar pedido

Después de crear el pedido, puedes leerlo por ID o listar pedidos del customer.
Una app solo puede leer las órdenes creadas por esa misma app.

Propina

cart.calculatedTipAmount sirve como sugerencia calculada por Justo. Guarda la propina final en tip.amount con PATCH /cart/preferences; POST /orders la toma desde ese state.
Si tu app ofrece porcentajes, calcula el monto en cliente usando como base itemsPriceWithoutDiscount cuando exista, o itemsPrice como fallback. No envíes solo el porcentaje al crear la orden.

Cupones

Puedes aplicar couponCode en preferencias del carrito. Luego lee el carrito y respeta couponStatus, benefits y amountToPay.

Errores comunes

  • notFound en website: revisa que domain sea el dominio canónico.
  • Sin comercios en marketplace: revisa que el customer tenga dirección seleccionada con selectedPlaceId y selectedCityId, y que esa dirección tenga cobertura.
  • Sin locales disponibles: revisa deliveryType, dirección seleccionada y cobertura del placeId.
  • Sin horarios: selecciona primero storeId y usa un local abierto para el tipo de entrega elegido.
  • Producto no disponible: vuelve a leer el detalle del producto y valida availabilityAt.
  • Modificadores inválidos: revisa min, max, opciones requeridas y disponibilidad de opciones.
  • Billing requerido: revisa data.options.billing.required y guarda billing con PATCH /cart/preferences antes de crear el pedido.
  • Teléfono requerido: si recibes phone: requirePhoneVerification, revisa que el customer tenga email y phone reales y que los estés enviando al crear la orden cuando actualices el customer en ese mismo paso.
  • Custom params inválidos: revisa los campos esperados por el website y envíalos en orderParams.
  • Total inesperado: usa siempre el carrito calculado como fuente de verdad para totales, fees, descuentos y propina.