cubobase In English

Conexión para sistemas de afuera

La API de las tiendas cubobase (plan profesional): leer y cambiar pedidos y productos desde otro sistema, y recibir avisos al instante.

Nuevo Agentes de IA: cada tienda tiene su servidor MCP en https://app.cubobase.com/mcp. El dueño conecta su Claude o su ChatGPT tocando «Autorizar», sin llaves. Cómo funciona

Empezar

El dueño de la tienda crea una llave en su app: Menú → Conexiones → Otro sistema → Crear una llave. La llave empieza con cb_ y se muestra una sola vez. Cada pedido a la API la lleva en el encabezado:

curl https://app.cubobase.com/api/v1/pedidos?estado=nuevo \
  -H "Authorization: Bearer cb_TU_LLAVE"

Pedidos

MétodoDirecciónQué hace
GET/api/v1/pedidosLa lista. Filtros: estado (uno o varios, separados por coma), pagado (si/no), desde (creados desde esa fecha), modificado_desde (para sincronizar: del más viejo al más nuevo), telefono, q (busca como el buscador de la app: cada palabra en el nombre, el correo, la dirección o la nota, sin importar tildes ni mayúsculas; un número también encuentra el pedido con ese número o el celular que lo tiene), pagina, por_pagina (hasta 200). Contesta {"pedidos": […], "pagina": 1, "hay_mas": false}.
GET/api/v1/pedidos/{numero}Un pedido, por su número (el que ven el dueño y el comprador).
POST/api/v1/pedidosCrea un pedido. Si se cobra por link (Mercado Pago o Stripe), lo trae en link_de_pago.
PATCH/api/v1/pedidos/{numero}Cambia el estado, si está pagado, el código de envío o los datos propios, y corrige el cliente, la entrega o lo que lleva.
POST/api/v1/pedidos/{numero}/devolverLe devuelve la plata al comprador, toda o una parte, por Mercado Pago o Stripe.

Cómo es un pedido

{
  "numero": 128, "estado": "preparando", "pagado": true, "pagado_el": "2026-10-10T19:13:02-03:00",
  "creado": "2026-10-10T19:12:40-03:00", "actualizado": "2026-10-10T19:30:00-03:00", "origen": "tienda",
  "cliente": {"nombre": "Martín P.", "telefono": "099 123 456", "email": "martin@ejemplo.com"},
  "entrega": {"tipo": "envio", "envio": "DAC a domicilio", "direccion": "Rivera 2450, Montevideo",
              "paga_el_que_recibe": false, "para_el": null, "para_hora": null,
              "seguimiento": {"agencia": "DAC", "codigo": "870-13465148"}, "en_agencia": null,
              "dac": {"entrega": "domicilio", "departamento": "10", "ciudad": "363", "barrio": "305",
                      "calle": "Rivera 2450", "agencia": null, "guia": "870-13465148"}},
  "medio_pago": "mercadopago", "link_de_pago": null,
  "items": [{"producto_id": 31, "variante_id": 88, "codigo": "JEAN-40", "nombre": "Jean recto",
             "variante": "40", "precio": 2290, "cantidad": 1}],
  "subtotal": 2290, "descuento": 0, "descuento_texto": "", "envio": 250, "total": 2540, "devuelto": 0,
  "cobrado": 2540, "a_devolver": 0, "moneda": "UYU",
  "avisos": {"recibido": "2026-10-10T22:13:05+00:00", "preparando": "2026-10-10T22:30:00+00:00"},
  "nota": "", "motivo": "", "reclamo": null, "junto_con": null, "url": "https://malva.cubotienda.com/pedido/…", "datos": {}
}

Avisos al comprador: avisos dice qué mails (o avisos al celular) ya le salieron y cuándo: recibido, pago, preparando, listo, en_camino, rastreo, en_agencia, entregado, resena, retiro15/retiro45/retiro70 (los recordatorios de retiro), cancelado, devuelto, digital. "sin_aviso" en vez de la fecha: se dio por dado sin mandarlo (avisar: false). Cuando sale uno, actualizado cambia y llega el aviso al instante pedido.aviso.

La plata: cobrado es lo que pagó por Mercado Pago o Stripe desde la tienda (lo que se le puede devolver por acá), o null si no pagó así. devuelto, lo que ya se le devolvió. a_devolver, lo que le sobra porque el total bajó después de pagar (se pasó a retiro, se sacó algo, se dejó de cobrar el envío): cobrado − devuelto − total, o 0; está siempre al día, también si se corrigió desde la app, y es lo que se devuelve con …/devolver. En un pedido cancelado no cuenta todo lo pagado (un contracargo o lo devuelto desde Mercado Pago no pasan por cubobase): para cancelar y devolver todo, "devolver_plata": true.

Estados: nuevo → preparando → listo → en_camino (si se manda) → entregado; y dos finales: cancelado (con motivo) y devuelto (solo después de entregado). «Pagado» va aparte. Pasar a entregado lo marca pagado.

Reclamos de Mercado Pago: si el comprador abre un reclamo o desconoce la compra, reclamo es {"tipo": "reclamo", "cuando": …} y el pedido queda en espera (no conviene prepararlo ni mandarlo); si Mercado Pago lo resuelve a favor de la tienda, vuelve a null. Un contracargo, o un reclamo que gana el comprador, lo pasa a devuelto con reclamo {"tipo": "contracargo", …}.

Crear un pedido

POST /api/v1/pedidos
{
  "cliente": "Lucía M.", "telefono": "099 123 456", "email": "lucia@ejemplo.com",
  "items": [{"codigo": "VEST-01", "valores": ["M"], "cantidad": 1},
            {"producto_id": 31, "variante_id": 88, "cantidad": 2},
            {"codigo": "PERSONALIZADA", "precio": 800}],
  "entrega": {"tipo": "envio", "envio_id": 3, "direccion": "Av. Brasil 2580, Montevideo"},
  "medio_pago": "mercadopago",
  "nota": "Para regalo",
  "datos": {"id_en_mi_sistema": "A-5521"},
  "avisar": true
}

Cambiar un pedido

PATCH /api/v1/pedidos/128
{"estado": "en_camino", "seguimiento": {"agencia": "DAC", "codigo": "870-13465148"}}

PATCH /api/v1/pedidos/129
{"estado": "cancelado", "motivo": "Sin stock"}

PATCH /api/v1/pedidos/130
{"pagado": true, "datos": {"impreso": true}}

PATCH /api/v1/pedidos/128
{"en_agencia": {"donde": "SALTO", "cuando": "2026-10-27T17:12:51"}}

Quedó en una agencia: si la guía la hace tu sistema, cuando la transportista deja el paquete esperando en una agencia mandá en_agencia (donde: la agencia, hasta 80; cuando: opcional, sin zona se toma la hora de la tienda). Al comprador le llega el mail «Tu pedido llegó a la agencia, ¡ya podés retirarlo!», con la agencia, la empresa de seguimiento y el código de rastreo. Solo con un envío en en_camino (puede ir en el mismo cambio que lo pasa a en_camino; si no, 409). Se anota una sola vez: mandarlo de nuevo no repite el mail ni cambia la agencia. El pedido lo muestra en entrega.en_agencia ({"donde", "cuando"} o null). Con las guías que hace cubobase (DAC conectado), esto pasa solo.

Todo es opcional. al_stock: true con devuelto vuelve lo devuelto al stock. Si el estado no permite el cambio, contesta 409. avisar: false no le manda el aviso al comprador, ni ahora ni después: el aviso de ese cambio (por ejemplo, el «gracias por retirar» al pasar a entregado) queda en avisos como "sin_aviso" y no sale en el próximo cambio con aviso. Los avisos de otros pasos (el del pago, por ejemplo) no se tocan. Con "devolver_plata": true, al pasar a cancelado o devuelto le devuelve además todo lo que falta devolver (si se pagó con Mercado Pago o Stripe): primero la plata, y si no sale, no cambia nada.

Corregir un pedido

PATCH /api/v1/pedidos/131
{"cliente": "Martín Pérez", "telefono": "099 765 432", "nota": "Tocar timbre",
 "entrega": {"tipo": "envio", "envio_id": 3, "direccion": "Rivera 2450, Montevideo"},
 "items": [{"codigo": "JEAN-40", "cantidad": 2}, {"codigo": "PERSONALIZADA", "precio": 800}]}

Devolver la plata

POST /api/v1/pedidos/128/devolver
{"monto": 500, "motivo": "Llegó rayada", "clave": "dev-128-1"}

Los datos propios

Cada pedido y cada producto tiene un casillero libre, datos: un objeto JSON para lo que el otro sistema necesite guardar (su número, una foto, una marca). Lo que se manda se suma a lo que había; una clave con null se borra. Hasta 16.000 caracteres en total. La tienda no lo muestra.

Productos

MétodoDirecciónQué hace
GET/api/v1/productosLa lista (también los ocultos). Filtros: q (busca en el nombre, el código y el detalle, sin importar tildes), codigo, id_antes, visible (si/no), pagina, por_pagina.
GET/api/v1/productos/{id}Un producto.
POST/api/v1/productosCrea uno (hace falta nombre y precio).
PATCH/api/v1/productos/{id}Cambia lo que se mande.
DELETE/api/v1/productos/{id}Lo saca de la tienda (los pedidos viejos lo siguen nombrando).
POST /api/v1/productos
{
  "nombre": "Vestido floreado", "codigo": "VEST-01", "precio": 2490, "precio_antes": 2990,
  "detalle": "Viscosa, largo midi", "descripcion": "…", "visible": true,
  "categorias": ["Ropa", "Novedades"],
  "fotos_url": ["https://mi-sistema.com/fotos/vestido.jpg", "https://mi-sistema.com/fotos/vestido-espalda.jpg"],
  "id_antes": "6207",
  "opciones": [{"nombre": "Talle", "valores": ["S", "M", "L"]}],
  "variantes": [{"valores": ["S"], "stock": 3}, {"valores": ["M"], "stock": 2, "codigo": "VEST-01-M"},
                {"valores": ["L"], "stock": 0}],
  "datos": {"id_en_mi_sistema": 6207}
}

PATCH /api/v1/productos/31
{"precio": 2590, "variantes": [{"valores": ["M"], "stock": 5}]}

Tienda, envíos y categorías

GET/api/v1/tiendaNombre, dirección, país, moneda, si está abierta, si hay retiro, formas de pago y envíos.
GET/api/v1/enviosLos envíos de la tienda, con su id y precio.
GET/api/v1/categoriasLas categorías, con cuántos productos tiene cada una.

Avisos al instante

El dueño pone la dirección de su sistema en Conexiones → Otro sistema → Avisos al instante (tiene que ser https://). Desde ahí, cada vez que pasa algo, la tienda manda un POST con JSON:

EventoCuándo
pedido.nuevoEntra un pedido (de la tienda, del Encargado, de la API).
pedido.pagadoSe pagó (Mercado Pago, Stripe, o el dueño lo marcó).
pedido.estadoCambió de estado (trae antes).
pedido.envioLe pusieron el código de envío.
pedido.corregidoSe corrigió el cliente, la entrega o lo que lleva (desde la app o la API).
pedido.plata_devueltaSe le devolvió plata al comprador (el pedido trae devuelto).
pedido.avisoLe salió un mail (o un aviso al celular) al comprador: trae avisos, cuáles (["listo"], ["retiro15"]). Sirve para mandarle una copia por otro canal en el mismo momento.
producto.cambiadoCambió el precio, el stock, si se ve, el nombre o el código, o se borró.
pruebaEl dueño tocó «Mandar un aviso de prueba».
POST https://mi-sistema.com/avisos
X-Cubobase-Evento: pedido.pagado
X-Cubobase-Id: 8123
X-Cubobase-Firma: sha256=5d41402abc4b2a76b9719d911017c592…

{"id": 8123, "evento": "pedido.pagado", "creado": "2026-10-10T19:13:05-03:00",
 "tienda": "malva", "pedido": { …como en GET /api/v1/pedidos/{numero}… }}
# Python
import hashlib, hmac
def es_de_cubobase(cuerpo: bytes, firma: str, secreto: str) -> bool:
    esperada = "sha256=" + hmac.new(secreto.encode(), cuerpo, hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperada, firma)

Si tu sistema lee seguido

Un sistema con varias partes que consultan a cada rato (el estado, los avisos, las ventas, un buscador) se pasa enseguida de las 120 consultas por minuto. Lo que funciona —lo aprendió el primer sistema que se conectó, la gestión de un comercio que le pedía a su tienda vieja unos 1.000 pedidos por minuto en los picos— es una copia propia:

Errores

Siempre en JSON: {"error": "codigo", "mensaje": "qué pasó, en castellano"}.

EstadoCódigoQué pasó
400json_invalido, dato_invalidoFalta algo o está mal escrito.
401sin_llave, llave_invalidaFalta la llave, o fue revocada.
403sin_profesional, tienda_inactivaLa tienda no tiene la profesional, o no está activa.
404no_existeEse pedido, producto o dirección no existe.
409no_se_puedeEl estado del pedido no permite ese cambio.
422pedido_invalido, producto_no_existe, variante_no_existe, foto_invalida, direccion_invalida, no_se_puede_devolverLos datos están bien escritos pero no se puede hacer (sin stock, tienda cerrada…).
429demasiadosMás de 120 pedidos por minuto.

Agentes de IA (MCP) Nuevo

Además de la API, las tiendas tienen un servidor MCP (Model Context Protocol, el estándar con el que los agentes de IA se conectan a otros sistemas). El dueño conecta su Claude, su ChatGPT o cualquier agente compatible, y el agente maneja la tienda con las mismas reglas que la app. Es para todas las tiendas, también la Base.

https://app.cubobase.com/mcp

Para probarlo desde la terminal con Claude Code (después, /mcp abre el «Autorizar»):

claude mcp add --transport http cubobase https://app.cubobase.com/mcp

Lo nuevo se agrega sin romper lo que ya anda: los campos que hay no cambian de nombre ni de significado. ¿Dudas? Escribinos a contacto@cubobase.com.