Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🛒🤖 justo-mx-api

Dale a tu agente de IA la capacidad de hacer el súper en Jüsto (supermercado online de México).
Una herramienta de lĂ­nea de comandos, pensada para que un asistente (WhatsApp, Telegram, etc.)
busque productos, arme el carrito y genere una orden real — todo conversacional, todo por API.

Python Dependencias Para agentes License

Warning

Proyecto no oficial. No está afiliado ni respaldado por Jüsto. Usalo con tu propia cuenta, bajo tu responsabilidad, y respetando los Términos y Condiciones de Jüsto. Existe para automatización personal y como documentación de cómo el sitio se comunica con su backend.


🤖 ¿Para qué sirve?

Imaginá decirle a tu asistente por WhatsApp "che, pedí plátano, leche y 3 cocas a Jüsto" y que lo haga solo: busca los productos, arma el carrito, elige el horario, te muestra el total y —cuando le das el OK— genera la orden real (contra entrega).

Esta herramienta es ese "brazo": una CLI simple con salida JSON y comandos de una sola línea, diseñada para que un agente de IA (OpenClaw, un bot propio, lo que sea) la ejecute por vos. Resuelve la parte difícil — la API de checkout de Jüsto no es trivial (ver 🔍 La API por dentro).

Pensada para agentes

  • đź§ľ Salida JSON en todos los comandos → fácil de parsear por un LLM.
  • 📏 Comandos de una lĂ­nea (Ă­tems separados por coma) → no se rompen en runtimes que rechazan multi-lĂ­nea.
  • ⏳ Modo background (order-bg / order-wait) → esquiva los timeouts cortos de RPC al ejecutar en un nodo remoto.
  • đź”’ Separa armar de comprar: order deja el carrito STAGED (no gasta); confirm reciĂ©n genera la orden → el agente puede pedir confirmaciĂłn humana antes de pagar.
  • 🌎 Alias AR→MX (palta→aguacate, choclo→elote…) → listas en cualquier dialecto.

👉 Ejemplo de skill listo para usar: examples/openclaw-skill.md (un SKILL.md de OpenClaw con el candado de confirmación incluido).

📦 Instalación

Python 3, solo librería estándar — sin dependencias.

git clone https://github.com/zekear/justo-mx-api
cd justo-mx-api
chmod +x justo
ln -s "$PWD/justo" ~/.local/bin/justo   # opcional: ponelo en el PATH

Important

Cloudflare bloquea IPs de datacenter. Jüsto está detrás de Cloudflare, que rechaza IPs de servidores cloud (403 / challenge de JS). Corré esto desde una IP residencial (tu compu, un server en casa, un nodo doméstico). Si tu agente vive en un VPS, ejecutá justo en un nodo residencial vía exec remoto.

⚙️ Configuración

Credenciales por variables de entorno:

export JUSTO_EMAIL="vos@ejemplo.com"
export JUSTO_PASSWORD="tu-password"
export JUSTO_ZIP="11590"          # tu cĂłdigo postal de entrega (default 11590)

…o apuntá JUSTO_CREDENTIALS a un archivo estilo .env (ver .env.example). Nunca subas tus credenciales reales al repo.

La dirección de entrega se toma de la dirección por defecto de tu cuenta (la gestionás en la app de Jüsto). El pago es contra entrega (MANUAL): no se cobra ni se tokeniza ninguna tarjeta.

🚀 Uso

# buscar productos + precios
justo search "plátano"

# armar un carrito REAL (aparece en tu app de Jüsto), con slot + contra-entrega — NO compra todavía
justo order "Plátano x6, Manzana Roja x10, Leche 1L x4, Pan Bimbo x2, Aguacate Hass x4"

order devuelve un resumen STAGED para revisar:

{
  "status": "STAGED",
  "checkout_token": "…",
  "total": 710.86,
  "currency": "MXN",
  "address": "Casa",
  "slot": "Recomendado — Mañana, 11:00AM - 01:00PM",
  "slot_options": [
    {"n": 1, "label": "Recomendado — Mañana, 11:00AM - 01:00PM"},
    {"n": 2, "label": "Entrega gratis — Miércoles, 07:00AM - 09:00AM"}
  ],
  "items": [ … ]
}
# cambiar el horario de entrega (usá el n de slot_options)
justo set-slot <checkout_token> 2

# generar la orden real (contra entrega) — cancelable después desde la app de Jüsto
justo confirm <checkout_token>
# -> {"status":"ORDER_PLACED","order_number":"N0111…","total":710.86, …}

Cantidades y matching

  • Cantidad como sufijo por Ă­tem: x4, Ă—4 o :4. Sin sufijo = 1.
  • Separá los Ă­tems por coma en un solo argumento.
  • El match es difuso (palabra completa en el nombre; si no, el primer resultado con precio). Usá un tĂ©rmino especĂ­fico (marca/tamaño) cuando importe el producto exacto.

Modo background (para agentes remotos)

job=$(justo order-bg "…lista larga…" | jq -r .job)
justo order-wait "$job"     # consultá hasta que esté el resumen STAGED

🔍 La API por dentro

El checkout de Jüsto no es un flujo Saleor común: maneja un cart-service propio y un checkout-bff. El checkoutComplete público de Saleor está bloqueado para México (Creation order for country MX not allowed), así que un carrito armado directo contra Saleor nunca se puede completar. El camino real se reverseó leyendo el bundle Next.js del sitio.

Dos hosts, ambos detrás de Cloudflare:

Host Rol
api.justo.mx/graphql/ Saleor GraphQL — búsqueda de productos + login (tokenCreate)
api.justo.cloud cart-service — crear carrito, agregar ítems, consolidar
client-api-gateway.justo.mx estado del checkout, horarios, pago, completar la orden

Todas las llamadas autenticadas mandan: Authorization: JWT <token>, más x-justo-country: MX, x-zip-code: <cp>, x-justo-platform: web-desktop, x-origin: cart_view.

El flujo completo:

  1. Login — Saleor tokenCreate(email, password) → JWT. me.id (base64 User:<n>) → userId numérico.
  2. Crear carrito — POST api.justo.cloud/cart-service/v3/cart body {userId, postalCode, items:[]} → {cartId}.
  3. Agregar ítems — POST api.justo.cloud/cart-service/v3/cart/{cartId}/items body {items:[{id:"<productId>", quantity}]}. El productId es el id numérico del producto en Saleor (decodificá base64 el id del nodo → Product:<n>). El id va como string.
  4. Consolidar — POST api.justo.cloud/cart-service/v2/cart/{cartId}/consolidate?userId={userId} → {context:{checkoutId (base64), checkoutToken (uuid), postalCode}}. (es v2 y en api.justo.cloud — v3 / el gateway dan 404/500.)
  5. Estado del checkout — POST client-api-gateway.justo.mx/v2/checkout body {checkoutId, zipCode} → componentes de UI: dirección (default de la cuenta), horarios (slots-v2, cada uno con context:{shippingMethodId (base64), deliveryDate}), métodos de pago, totales.
  6. Setear horario — POST client-api-gateway.justo.mx/v2/checkout/slots body {checkoutId, shippingMethodId, deliveryDate}.
  7. Setear pago — POST client-api-gateway.justo.mx/v2/checkout/paymentMethods body {checkoutId, gateway:"MANUAL"} (contra entrega). Obligatorio: sin método de pago, completar se rechaza.
  8. Completar — POST client-api-gateway.justo.mx/v1/checkout/complete body {cartId, checkoutId, zipcode, additionalData:{}}. La respuesta siempre muestra un modal de "completado" — el resultado real está en tracking: orderCompleted (con order_number, order_id) si salió, o orderRejected {reason} si falló (reason: 10 = falta método de pago).

Note

Gotchas:

  • Las Ăłrdenes creadas asĂ­ viven en el backend del cart/checkout (ids hex tipo 6a30d…), no en me.orders de Saleor (solo histĂłrico viejo). Se listan/cancelan en la app de JĂĽsto.
  • checkoutComplete de Saleor está duramente bloqueado para MX; ignoralo.
  • Un carrito armado directo contra Saleor (salteando cart-service/consolidate) nunca lo reconoce el Core → siempre reason 10. El camino por cart-service es obligatorio.

🤝 Contribuir

Issues y PRs bienvenidos. Si la API de Jüsto cambia, los endpoints se reverifican leyendo los chunks de https://justo.mx/_next/static/chunks/ (el _buildManifest.js mapea rutas → chunks).

đź“„ Licencia

MIT

About

🛒🤖 Que tu agente de IA haga el súper en Jüsto (México). CLI Python, salida JSON, E2E por API (cart-service + checkout-bff reverseado).

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages