Logistivo CLI: gestiona tu operación logística desde una terminal y desde tu ERP
Un único catálogo de comandos alimenta tres superficies: el cliente de terminal lg, el asistente de IA dentro del panel y el canal al que se conectan los asistentes de IA externos. Una capacidad se escribe una sola vez y aparece en las tres; además, cada acción de escritura del panel ya tiene un comando, así que tus scripts y tus propios agentes de IA pueden hacer el trabajo que tu equipo hace en pantalla. Los pagos, el consentimiento legal y el cierre de la cuenta se quedan deliberadamente en el navegador. Esta página es un contrato. La tabla de comandos de abajo no está escrita a mano: se genera a partir del registro de comandos en vivo en cada petición.
¿Qué es Logistivo CLI?
Logistivo CLI (lg) es un cliente de línea de comandos que ejecuta el trabajo de tu cuenta de Logistivo (cargas y viajes, solicitudes, ofertas y licitaciones, flota y conductores, documentos, contactos y cuentas corrientes, facturas y contabilidad, almacén y stock, miembros del equipo y aranceles aduaneros) desde una terminal, un script o tu propio agente de IA. Los comandos no vienen integrados en el cliente: el cliente descarga el catálogo de comandos del servidor y se construye a partir de él. Los mismos comandos se pueden llamar por HTTP sin instalar nada (es la vía que usan las integraciones con ERP y CRM) y a través del canal MCP al que se conectan los asistentes de IA externos.
Una única forma de comando: lg --parameter=value. Hoy el catálogo contiene 519 comandos en 125 dominios; la lista más amplia que ve un solo rol es de 452 comandos en 112 dominios.
Cada acción de escritura del panel tiene un comando: medido contra los endpoints de escritura del panel, el 100 % de los que entran en el alcance está cubierto. Los pagos (3D Secure), el consentimiento legal y el cierre de la cuenta se quedan deliberadamente en el navegador; para ellos, un comando devuelve un enlace.
Los comandos que reciben un documento o una foto también funcionan fuera del navegador: escribe --attachment_uuid=@./cmr.pdf y lg sube primero el archivo; por HTTP subes el archivo a /api/common/commands:upload y pasas el attachment_uuid devuelto.
Las claves de integración llevan un nivel de acceso: employee (el predeterminado para claves nuevas) para la operativa diaria, manager para equipo, configuración, claves y dinero. Una clave nunca tiene más derechos que la persona en cuyo nombre actúa.
Los flags nunca se inventan: cada flag es un nombre de parámetro del propio JSON Schema del comando, y de ahí salen también su tipo y si es obligatorio.
Los comandos de escritura piden confirmación; los irreversibles nunca se ejecutan sin ella (HTTP 409, código de salida 4 en la CLI).
Reintentar no crea duplicados: una llamada que lleva un idempotency_key se ejecuta como máximo una vez.
Cada ejecución queda en un único registro de auditoría: si vino de una terminal, del chat o de un asistente, queda constancia.
Qué está disponible hoy y qué está en camino
Esta sección está arriba del todo a propósito. El error más caro que puede cometer un documento de integración es describir como disponible un endpoint que todavía no está abierto: el integrador escribe el código, el endpoint devuelve 404 y la confianza ya no vuelve.
Como el contrato está congelado, el código de integración que escribas hoy seguirá funcionando a medida que se abran las piezas restantes. Los campos que no conozcas deben ignorarse; esa regla es la que nos permite añadir sin romper.
Catálogo de comandos y tabla de identidad — La identidad pública dominio/verbo de cada comando está congelada y la versión del contrato se publica como 1 en cada respuesta del catálogo y en la cabecera X-Contract-Version. La tabla de esta página se genera a partir del registro en vivo: un comando añadido en el servidor aparece aquí solo, y un comando eliminado desaparece.
Endpoint de descubrimiento sin autenticación — GET /api/public/cli/catalog — nombres de comandos, identidad dominio/verbo, descripción, parámetros en JSON Schema, indicadores de control y los campos de versionado (since, deprecated_at, replaced_by, aliases). Sin autenticación: emitir un token es un paso que viene DESPUÉS de la decisión de integrar, no antes. La respuesta no contiene ningún dato de tenant.
Endpoints autenticados de catálogo y ejecución — GET /api/common/commands, GET /api/common/commands/{name} y POST /api/common/commands/{name}. El control de rol, el control de confirmación, la idempotencia y el registro de auditoría viven en un único punto de aplicación por el que también pasan el chat y la terminal.
Cobertura del panel: cada acción de escritura tiene un comando — 519 comandos en 125 dominios, contrastados con los endpoints de escritura del panel: cada endpoint dentro del alcance está respaldado por un comando (un espejo del endpoint o el mismo servicio compartido) y ninguno queda sin demostrar. Fuera del alcance de forma deliberada: los pagos con 3D Secure, el consentimiento legal, el cierre de la cuenta y el inicio de sesión, que se quedan en el navegador; la gestión de claves, webhooks y sandbox, que son comandos integrados de lg; y los endpoints propios de la app del conductor.
Verificación previa (dry_run): míralo sin ejecutarlo — Con dry_run: true en el cuerpo de la petición, el comando no se ejecuta: se ejecutan la validación, el control de rol/alcance, la resolución del destino y el cálculo de créditos, y se devuelve una vista previa; no se escribe nada, no se gasta crédito y la clave de idempotencia no se consume. El endpoint de lotes también lo acepta, por lote. Una verificación previa nunca entra en el handler del comando; cuando se lanzó, 178 verificaciones previas sobre todos los comandos de escritura del catálogo de ese momento no produjeron ni una sola sentencia de escritura.
Claves de integración — Claves de API que actúan en nombre de un miembro real del equipo, emitidas en el panel o con lg keys create: alcance de lectura/escritura, un nivel de acceso (employee por defecto, o manager), vida útil, último uso, rotar, transferir y revocar. lg login --api-key, lg whoami y un lg logout que revoca en el servidor se basan en ellas.
Sandbox: ensaya escrituras sin tocar producción — Un tenant sandbox separado por empresa con el mismo catálogo de comandos; se abre en autoservicio y emite su propia clave. El crédito, el marketplace y el enrutamiento de webhooks están separados entre los dos entornos; el entorno se deduce de la empresa de la clave y no se puede indicar en la petición.
Versionado, taxonomía de errores, idempotencia y límites de peticiones — Los comandos llevan since / deprecated_at / replaced_by / aliases y un comando obsoleto responde con una cabecera X-Deprecated. Los fallos de negocio llevan un error_key estable junto al error_code de nivel de transporte, y el diccionario de claves se publica en el catálogo. Las claves de idempotencia están acotadas a tu empresa, vinculadas a un comando y bloqueadas durante 24 horas. Los límites de peticiones (rate limits) son por token, en tres grupos, y cada 429 lleva Retry-After.
Webhooks salientes: un POST cuando ocurre algo — El push firmado está disponible para 13 eventos. Las suscripciones se gestionan desde el panel o con lg webhooks; la firma lleva su propia marca de tiempo, el calendario de reintentos es de 60 · 300 · 1800 · 7200 · 21600 segundos y el motivo de silenciamiento siempre se registra. Cada nombre de evento está respaldado por una clase de evento que realmente se despacha: nada se anuncia para luego no enviarse nunca. La vía pull (updated_since + cursor) no se eliminó: el push se añadió junto a ella, no en su lugar.
Comandos que reciben archivos — 33 comandos reciben un documento o una foto: un CMR, una factura, un permiso de circulación, fotos de palés. Sube el archivo una vez a POST /api/common/commands:upload, o deja que lg lo haga con --attachment_uuid=@./file.pdf, y pasa el attachment_uuid devuelto; los clientes MCP usan la herramienta upload_attachment. El tipo de archivo se detecta a partir del contenido, y una subida sigue siendo utilizable durante 24 horas.
El cliente de terminal lg — Publicado en npm con licencia MIT: instálalo con `npm install -g @lgstv/lg`, o ejecútalo sin instalar con `npx @lgstv/lg`. Es un único archivo sin dependencias y, como la superficie HTTP está abierta, puedes integrarte sin él. Inicia sesión con un código de aprobación que confirmas en el navegador y después mantiene la sesión iniciada, renovándola por sí solo; sube los archivos locales por ti (@path, --file, lg upload), gestiona las claves de integración (lg keys), nunca acepta un secreto en la línea de comandos, respeta Retry-After, reintenta los 5xx con la misma clave de idempotencia y avisa de los comandos obsoletos y de las versiones de contrato más recientes.
Sincronización incremental: paginación por cursor y updated_since — El contrato de abajo (limit + cursor opaco firmado, next_cursor, updated_since) está fijado y se está desplegando en los comandos de listado. Hasta que un comando de listado anuncie cursor y updated_since en su JSON Schema, trátalo como una ventana pequeña: máximo 20 filas, sin cursor.
Qué lo hace diferente: el cliente no conoce ningún comando, los dibuja
Esta es la decisión que da sentido al resto de la página. En una CLI corriente los comandos viven dentro del cliente; en Logistivo viven en el servidor.
En el esquema clásico, cuando el servidor gana una capacidad, el cliente necesita una nueva versión y el usuario tiene que instalarla. Entre tanto, los dos lados saben cosas distintas, y ese es el modo de fallo más silencioso de las integraciones: el script se ejecuta, el código de salida es 0 y el comando simplemente no describe lo que el servidor puede hacer.
En Logistivo, la definición de un comando es un único registro: su nombre, lo que hace, sus parámetros en JSON Schema, qué roles pueden verlo, si necesita confirmación y si su efecto es reversible. Cuando lg arranca, descarga ese catálogo y genera a partir de él su texto de ayuda, sus flags y su validación de entrada. En el momento en que se añade un comando en el servidor, lg lo conoce, sin actualizar el cliente.
El mismo catálogo alimenta al asistente de IA del panel y al canal al que se conectan los asistentes de IA externos. Una capacidad se escribe una vez y aparece en tres sitios, y los tres pasan por el mismo control de rol, el mismo control de confirmación y el mismo registro de auditoría. No hay un inventario de comandos aparte para la CLI; si lo hubiera, las tres superficies divergirían en silencio en menos de seis meses.
Sin desfase de versiones — La lista de comandos que conoce el cliente es, por construcción, la lista que tiene el servidor. «¿Qué versión de lg tiene este comando?» es una pregunta que no existe.
Los nombres de los flags nunca se adivinan — Los flags de un comando son exactamente los nombres de parámetro de su JSON Schema. La forma de saber qué acepta un comando no es leer un documento, sino leer el catálogo, y el catálogo siempre está al día.
Tu CLI es tan grande como tu cuenta — El catálogo se filtra por rol: un comando que tu rol no puede ver nunca aparece en tu lista. Una cuenta de transportista ve 452 comandos, un cargador 448, un agente de aduanas 312, y una cuenta de afiliado (socio de referidos) tiene un conjunto propio de 55 comandos.
La documentación no puede quedarse atrás — La tabla de comandos de esta página sale del mismo registro. No existe ninguna lista que una persona tenga que mantener sincronizada con la realidad.
La regla de nombres: cómo crecen los nombres de los comandos
El catálogo va a crecer. Los comandos nuevos no se nombran sobre la marcha; se aplican seis reglas. Las publicamos aquí porque son los nombres que tu integración va a escribir durante años, y que sean predecibles tiene valor para ti.
Un dominio es una entidad en plural — loads, demands, invoices, export-documents. Los dominios de dos palabras van en kebab-case. La única excepción es un sustantivo incontable: stock nunca se pone en plural, porque «stocks» significa otra cosa.
Todos los verbos de una entidad viven en un mismo dominio — loads reúne todos los verbos que actúan sobre una carga: create, list, get, update, set-status, assign-driver, list-problems, archive y más. Abrir un dominio nuevo por cada verbo (load-statuses, load-drivers) obligaría al usuario a buscar la misma entidad en tres sitios.
El verbo nunca se filtra al dominio; el dominio es lo que CAMBIA — Asignar un conductor cambia la carga, no al conductor, así que es lg loads assign-driver. El objeto indirecto (-driver) se une al verbo, nunca al dominio.
Un subrecurso nunca tiene dominio propio — Una línea de factura y un artículo de un documento no se pueden listar por sí solos; se accede a ellos a través de su propietario: lg invoices add-line, lg export-documents add-item. Lo decide una sola prueba: si no puedes listar u obtener la cosa de forma independiente, no es un dominio.
Acotar es un flag, no un verbo nuevo — lg fleet-documents list --days=30 es lo correcto; no existe un verbo «list-expiring» aparte, porque la ventana ya es un parámetro. Un verbo calificado solo se usa cuando las filas que devuelve no son la entidad del dominio: loads list-problems devuelve indicadores de problemas, no cargas.
El par (dominio, verbo) es único en todo el catálogo — Incluso para dos comandos cuyos roles nunca se solapan. Si el mismo par se diera a dos comandos, tu código de integración estaría mirando un nombre mientras la CLI ejecuta cosas distintas según quién la invoque.
Cobertura: todo lo del panel, desde un comando
Muchos equipos conectan Logistivo a su propio agente de IA o a su sistema de automatización, y un agente solo es útil si puede terminar el trabajo. Así que la regla es sencilla: todo lo que un usuario de oficina puede cambiar en el panel, también lo puede cambiar un comando, detrás del mismo control de rol, el mismo control de confirmación y el mismo registro de auditoría.
Esto está medido, no afirmado. Cada endpoint de escritura que hay detrás del panel se contrasta con el registro de comandos, y un endpoint solo cuenta como cubierto cuando un comando lo declara como su espejo HTTP o llama al mismo servicio compartido. De los endpoints de escritura dentro del alcance, el 100 % está cubierto y ninguno queda sin demostrar. Cada endpoint que se deja fuera lleva un motivo por escrito (pasos de identidad y de pago, el plano de control de la integración, los endpoints propios de la app del conductor, la telemetría del cliente, copias muertas sin ningún llamante), y los que le importan a un integrador se enumeran más abajo.
Los comandos que reciben un archivo siguen la misma regla: 33 comandos de la tabla reciben un documento o una foto, y todos funcionan desde lg, por HTTP y por MCP (consulta Comandos que reciben archivos).
El trabajo de gestión también está cubierto, detrás de una clave más fuerte: 62 comandos de la tabla (miembros del equipo y roles, configuración de la empresa, cuentas bancarias, tarjetas guardadas, claves de integración) necesitan una clave de integración de nivel manager. Una clave de nivel employee, la predeterminada, ejecuta la operativa diaria y recibe INSUFFICIENT_KEY_LEVEL en esos comandos.
Las cuentas de afiliado (socio de referidos) tienen un catálogo propio: 55 comandos en 20 dominios (referidos, leads, notas y tareas de CRM, presentaciones comerciales, ganancias y pagos), más los comandos de cuenta y de equipo que tiene cualquier rol. Los comandos exclusivos de afiliados no están en la tabla pública de abajo, que enumera los tres roles del panel; una cuenta de afiliado los ve en GET /api/common/commands y en lg commands. Una empresa que es a la vez afiliado y cargador, transportista o agente de aduanas ve ambos conjuntos.
Un agente debería empezar con lg users get (nombre de API get_current_user): devuelve el rol, el nivel de acceso de la clave en uso, los permisos efectivos y si una aprobación legal pendiente o un número de teléfono sin verificar está bloqueando ahora mismo las escrituras, para que el agente pueda prever un rechazo en lugar de encontrárselo.
La cobertura se mide con un informe que compara el registro de comandos con los endpoints de escritura del panel; un endpoint del panel añadido sin comando aparece en él como no demostrado. Si encuentras una acción del panel a la que no puedes llegar desde un comando, comunícalo a soporte.
1. Pide el enlace — El trabajo que tiene que ocurrir en la propia sesión de navegador de la persona no es un comando, pero la superficie de comandos lo conoce. lg handoff-links generate (nombre de API get_browser_handoff_link) devuelve un enlace de logistivo.com para los fines que permite tu rol: package_purchase, payment_cards, legal_documents, integration_keys, affiliate_demo_accounts y account_close. Es gratuito, no escribe nada y el enlace no lleva ningún secreto: la persona inicia sesión como siempre.
2. Pásaselo a la persona — Muestra el enlace al usuario o envíalo por tu propio canal. La persona termina el paso allí: la aprobación del contrato y el pago con 3D Secure de un paquete, añadir una tarjeta, aprobar textos legales pendientes, emitir una clave de API cuyo secreto se muestra una sola vez o cerrar su propia cuenta.
3. Lee el resultado con un comando — Una vez hecho el paso, su resultado vuelve a ser visible para los comandos: el paquete y el saldo de créditos, la tarjeta guardada (enmascarada, solo los cuatro últimos dígitos), la clave nueva en la lista de claves. Un agente nunca recibe un número de tarjeta, un pago ni un consentimiento en un chat.
Pagos y 3D Secure — Comprar o mejorar un paquete y añadir una tarjeta requieren 3D Secure en el navegador. Los comandos listan paquetes y precios, leen el saldo y su historial, listan las tarjetas guardadas (enmascaradas), fijan la tarjeta predeterminada y eliminan una; la compra en sí pasa por el enlace de traspaso al navegador.
Consentimiento legal — La aprobación de los textos legales la hace la persona, en el navegador. lg users get te dice que hay una aprobación pendiente; ningún comando puede darla.
Cierre de la cuenta, inicio de sesión y contraseña — Cerrar tu propia cuenta, iniciar sesión y cambiar una contraseña son pasos de identidad y se quedan en el navegador. lg user-accounts preview muestra lo que supondría cerrar la cuenta, sin hacerlo.
Claves de integración, webhooks y el sandbox — Gestionarlos devuelve secretos que deben mostrarse una sola vez, en tu terminal, así que son comandos integrados de lg (lg keys, lg webhooks, lg sandbox) sobre sus propios endpoints HTTP en lugar de comandos del catálogo. El catálogo solo lleva los dos comandos de claves sin secretos: integration-keys list e integration-keys revoke.
El chat del asistente del panel — Las claves de integración no pueden manejar el chat del asistente de IA dentro del panel; iniciar o continuar una ejecución con una clave responde 403. Un agente se conecta en su lugar a través de los endpoints de comandos, lg o el canal MCP; ahí cada comando se ejecuta con el nivel de acceso de la clave y sus escrituras se registran como escrituras de integración.
La app del conductor — Las cuentas de conductor no tienen catálogo de comandos, y la app del conductor mantiene sus propios endpoints. Los usuarios de oficina gestionan los conductores, sus documentos, gastos y viajes mediante comandos.
Instalación e identidad
lg es un script de Node de un solo archivo y sin dependencias (Node 18+), publicado en npm como @lgstv/lg. El paquete instala dos comandos idénticos, lg y logistivo; usa logistivo si lg ya es un alias en tu máquina. Como es un solo archivo, copiar lg.mjs en el servidor ERP de un cliente también funciona. No necesitas el cliente para construir una integración con ERP/CRM: los mismos comandos están disponibles por HTTP.
1. Instalar — Solo necesitas Node 18 o posterior; no hay más dependencias. Instálalo de forma global o ejecútalo sin instalar con npx.
2. Iniciar sesión con un código de aprobación — lg login muestra un código de aprobación corto y abre logistivo.com/connect en tu navegador; por SSH, en CI o con --no-browser solo imprime la dirección, que puedes abrir en cualquier dispositivo, incluido tu teléfono. Inicia sesión allí como siempre, comprueba que el código de la página es el mismo que el de tu terminal, elige acceso de solo lectura o de lectura y acción, y apruébalo. No se escribe nada secreto en la terminal: ni contraseña, ni clave, ni código de un solo uso. Después, la sesión sigue iniciada en ese ordenador: cerrar la terminal no cierra la sesión, y lg renueva por sí solo el token de acceso antes de que caduque. lg logout también cierra la sesión en el servidor, y puedes eliminarla en el panel, en Settings › Integration keys › AI and CLI connections. lg login --password (correo y contraseña) sigue disponible como alternativa de respaldo. Requiere lg 0.11 o posterior.
3. Para servidores y CI: una clave, no un código de aprobación — En un servidor o en un job de CI no hay nadie que apruebe un código en un navegador. Emite una clave en el panel (Settings › Integration keys) o con lg keys create (opcionalmente en nombre de un miembro del equipo dedicado y con un alcance reducido) y ponla en LOGISTIVO_TOKEN, o guárdala con lg login --api-key. Mientras la variable esté definida, el archivo de configuración nunca se lee. Detalles: la sección «Conectarse con una clave de API».
4. Verifica y explora el catálogo — lg commands lista todos los comandos que tu rol puede ver, agrupados por dominio; lg help muestra los verbos de ese dominio, y lg help muestra la lista completa de parámetros de un comando con sus tipos y cuáles son obligatorios. Nada de ese texto vive dentro del cliente: todo sale del catálogo. Recuerda que la lista depende de tu rol: los verbos de un dominio no son los mismos para un transportista que para un cargador (loads set-status, por ejemplo, solo está en el catálogo del transportista). Si falta un verbo, revisa tu rol antes de revisar tu instalación.
Nunca pongas la clave en el control de versiones, en un log de CI ni en una ventana de chat. Si iniciaste sesión con un código de aprobación o con una clave de integración, lg logout también cierra la sesión en el servidor; en una sesión con contraseña (lg login --password) solo borra la copia LOCAL y lo dice explícitamente. El registro de auditoría guarda tus argumentos, pero enmascara como *** cualquier campo cuyo nombre contenga token, password, IBAN, card u OTP, y todos los parámetros que un comando declara secretos.
LOGISTIVO_TOKEN — Token de acceso personal. Mientras esté definida, el archivo de configuración nunca se lee; es la vía preferida en CI y en servidores.
LOGISTIVO_BASE_URL — Raíz del servidor. Por defecto, https://logistivo.com. Cámbiala solo si apuntas a tu propio entorno; el flag --base-url hace lo mismo para un único comando.
LOGISTIVO_HOME — Directorio del archivo de configuración y de la caché del catálogo. Por defecto, ~/.logistivo. Sepáralo si trabajas con dos cuentas en una misma máquina.
LOGISTIVO_PROFILE — Con qué perfil ejecutar. `lg profile use` es la elección persistente; esta variable es para una sola ejecución y es la forma más corta de alternar entre un perfil live y uno sandbox en CI. Un nombre de perfil desconocido no se ignora en silencio: da error.
NO_COLOR — Si está definida, no se imprime ningún color ANSI (la forma permanente del flag `--no-color`). Actívala en un puente que escriba en un archivo de log o en la salida de CI; las secuencias de escape de color rompen las herramientas que leen esos logs después.
Ergonomía del cliente
Estas funciones facilitan el uso diario del cliente `lg`. Ninguna cambia el contrato HTTP; sáltate esta sección si te integras directamente por HTTP.
Varios entornos y claves — Mantén staging y producción, o tus puentes de cliente y de transportista, en perfiles separados. La lista de perfiles nunca imprime un token; cada fila muestra la huella sha256 del token. El catálogo de comandos se guarda en caché por perfil, host y token, así que dos roles nunca pueden ver la lista de comandos del otro.
Sincronización incremental: lg sync — Ejecuta el bucle de sincronización de la guía práctica en un solo comando: una marca de agua por entidad, updated_since con un cursor, salida JSONL y un margen de seguridad de cinco minutos. Usa --full para el primer volcado completo (backfill). El comando es de solo lectura; no existe un flag --write. lg sync --list deduce del catálogo las entidades sincronizables para tu rol.
Experiencia de errores y autocompletado del shell — Ante un 422, el cliente nombra el campo rechazado como el flag que escribiste, junto con el error_key estable y la propia explicación del catálogo. Ante un 409 imprime la línea de comando --yes ya preparada; ante un 429 espera lo que indique Retry-After. El autocompletado del shell cubre dominios, verbos, flags y valores enum, y funciona sin conexión.
Los parámetros secretos nunca van en la línea de comandos — Algunos comandos reciben un secreto: conectar la integración contable con Paraşüt, por ejemplo, requiere las credenciales de cliente y la contraseña de ese sistema. lg nunca acepta un valor así como flag, porque acabaría en el historial de tu shell y en la salida de ps: te lo pide sin mostrarlo en pantalla, o lo lee de ---file=PATH o de stdin (---file=-), y lo guarda solo en memoria. Un comando cuyo parámetro obligatorio es secreto solo se ejecuta desde lg: llamado desde el chat, por MCP o dentro de lg batch, se rechaza con SECRET_REQUIRES_CLI. El registro de auditoría siempre guarda el valor como ***.
Conectarse con una clave de API
Un ERP, un CRM, un script o un agente de IA se conecta a Logistivo con una clave de integración emitida en el panel o con lg keys create. La clave actúa en nombre de un miembro real del equipo: el rol de esa persona decide la lista de comandos, el nivel de acceso de la clave decide lo delicado que puede ser el trabajo y, cuando esa persona deja el equipo, la clave muere con ella. No existe una «cuenta de servicio» sintética ni existirá: el aislamiento multi-tenant está vinculado al usuario, y un puente sin dueño es de los que siguen escribiendo en silencio durante años.
1. Emite una clave en el panel — Settings › Integration keys › New key. Ponle un nombre («Sincronización nocturna del ERP»), elige el alcance y el nivel de acceso y, si quieres, acorta su vida útil. La clave se muestra una sola vez, solo en esa pantalla; el servidor no la guarda. Si la pierdes, Rotate (rotar) emite una nueva y la antigua deja de ser válida al instante.
2. Conéctate desde la terminal — lg login --api-key valida la clave, imprime la identidad y el alcance, y descarga el catálogo de comandos. lg whoami pregunta al servidor con qué usuario, empresa, rol y alcance estás ejecutando. lg logout también revoca la clave en el servidor, igual que cierra allí una sesión iniciada con código de aprobación (solo el lg logout de una sesión con contraseña no puede hacerlo).
3. O HTTP directamente — La clave es un token de acceso que viaja en la cabecera Authorization: Bearer y funciona directamente contra los tres endpoints de comandos. En un servidor o en CI, ponla en LOGISTIVO_TOKEN; mientras esa variable esté definida, el archivo de configuración nunca se lee.
4. O gestiona las claves desde la terminal: lg keys — lg keys es el gemelo en terminal de la pantalla del panel: los mismos endpoints, el mismo control (el permiso de gestión del equipo y, si lo llamas con una clave, una clave de nivel manager). create, rotate y transfer devuelven un token nuevo una sola vez: con --save-profile=NAME va directamente a un perfil local y nunca se imprime; si no, lg lo imprime una vez. En modo --json, el token solo se incluye si añades --show-secret, y una llamada --json sin ninguno de los dos flags se rechaza antes de enviar la petición, así que el token no puede acabar en silencio en la salida de un script. rotate, transfer y revoke piden confirmación (--yes); a una clave se la identifica por su nombre exacto o por su uuid, nunca por aproximación. El nivel de acceso se mantiene sin cambios en una clave rotada o transferida.
El alcance se aplica en toda la superficie de la API, no solo en el catálogo de comandos: una clave de solo lectura deja pasar las peticiones de lectura (GET/HEAD/OPTIONS) y cualquier otra petición de escritura responde 403 forbidden. Hay dos excepciones deliberadas y ambas están protegidas por un control más fino: el endpoint de ejecución de comandos (la decisión sale del propio indicador read_only del comando, porque los comandos que no escriben también se llaman con POST) y una clave que se revoca a sí misma (lg logout, permitido también con una clave de solo lectura). El alcance, los permisos por dominio y el nivel de acceso son tres ejes independientes y todos deben cumplirse: una clave read no puede escribir ni siquiera con nivel manager, una clave write de nivel employee no puede gestionar el equipo, y un permiso de dominio loads:write no abre el trabajo de gestión. Emite la clave en nombre del miembro con menos privilegios que cubra tus necesidades: el rol decide qué registros puedes ver siquiera.
read — El catálogo de comandos y los comandos que no escriben (list, search, preview). Un comando de escritura devuelve 403 forbidden, antes del control de confirmación; una clave de solo lectura ni siquiera llega a ver un 409. La opción adecuada para la sincronización nocturna y los informes.
write — Todos los comandos. Los comandos que requieren confirmación la siguen pidiendo con 409; confirm: true (--yes en la CLI) funciona exactamente igual que antes. El alcance nunca relaja el control de confirmación.
employee — El predeterminado para toda clave nueva. Operativa diaria: cargas, solicitudes, ofertas, viajes, flota y documentos de flota, documentos, contactos; todos los comandos que no necesitan permiso de gestión, más los permisos de flota. Un comando que necesita más responde 422 con error_key INSUFFICIENT_KEY_LEVEL y required_key_level: manager; el endpoint REST equivalente responde 403 con la misma clave. El nivel adecuado para la sincronización nocturna de un ERP, un puente de telemática o un script de operaciones.
manager — Todo lo que puede hacer la persona en cuyo nombre actúa la clave, incluida la gestión: miembros del equipo y roles, configuración de la empresa, claves de integración, cuentas bancarias y su verificación, tarjetas guardadas, relaciones entre empresas, pagos a afiliados. Una clave manager nunca añade un derecho que la persona no tenga: sin el permiso de gestión del equipo, sigue sin poder gestionar el equipo. Las claves que existían antes de que se introdujeran los niveles de acceso son claves manager, así que se comportan exactamente igual que antes.
Una clave por integración — Si el CRM y el ERP comparten una clave, cortar uno significa cortar el otro. Dale a cada puente su propia clave; de todos modos, la lista las muestra por nombre.
Rotar — Emite un token nuevo y revoca el antiguo de inmediato; se conserva la vida útil restante. Úsalo ante la sospecha de una filtración y a intervalos regulares. La integración recibe 401 hasta que se actualiza con el token nuevo.
Revocar — La clave se cierra de forma permanente; no se puede deshacer, emite una clave nueva si hace falta. Si el miembro en cuyo nombre actúa la clave se elimina del equipo o se desactiva, la clave cae por sí sola.
Vida útil y límite — La validez por defecto es de 180 días; puedes acortarla al crearla, nunca ampliarla. Un usuario puede tener como máximo 10 claves activas. La hora del último uso se ve en la lista; una clave que nunca se ha usado lo indica explícitamente.
Quién gestiona — Emitir, rotar, transferir y revocar está abierto a los responsables con permiso de gestión del equipo (el mismo control que para añadir o quitar miembros del equipo) y, cuando se hace con una clave de integración, esa clave debe ser de nivel manager. Un responsable puede emitir una clave en nombre de otro miembro; para un puente se recomienda un miembro dedicado y con un alcance reducido.
Los diez primeros minutos: del panel a tu primera llamada
Los minutos más caros de una integración son los diez primeros. Los cuatro pasos de abajo trazan ese camino en orden; el mismo orden existe en el panel como asistente (Settings › Integration › Setup wizard), y el asistente llama exactamente a los endpoints que se describen aquí. Un desarrollador sin acceso al asistente llega al mismo sitio leyendo esta sección.
Ninguno de los cuatro pasos termina con «ya lo envié». Si la clave funciona de verdad lo responde el registro de peticiones; si el webhook llega de verdad lo responde el registro de entregas. Ambos están abiertos en el panel y en lg. Una configuración que nunca se mide es una configuración de la que solo se cree que funciona.
1. Decide qué vas a hacer: define primero el alcance — Lo que una clave puede ver no se decide más tarde: eliges el alcance al emitirla. Hay dos ejes. El alcance general (read / write) solo responde a «¿puede escribir?». El alcance fino (permisos por dominio: loads:read, invoices:write) indica qué dominios puede tocar, y en el momento en que se define, la clave pasa a ser fail-closed (cerrada por defecto): cualquier dominio que no hayas seleccionado, y cualquier endpoint que no corresponda a ningún dominio, devuelve 403. La lista de dominios del panel no es una lista escrita a mano; se deriva del catálogo de comandos en vivo de tu rol y muestra cuántos comandos y endpoints REST abre cada dominio. Los endpoints del catálogo de comandos, de «quién soy» (current) y de «cerrar sesión» siempre están exentos del alcance: una clave siempre debe poder describirse y cerrarse a sí misma. El tercer eje es el nivel de acceso: employee (el predeterminado) ejecuta la operativa diaria; manager también hace trabajo de equipo, configuración, claves y dinero. Elige employee a menos que el puente haga trabajo de gestión.
2. Emite la clave: el token se muestra una sola vez — Settings › Integration › New key. Ponle un nombre («Sincronización nocturna del ERP»), elige el usuario en cuyo nombre se ejecuta y el nivel de acceso, y acorta la vida útil si quieres. El token en bruto solo se devuelve en esa respuesta; el servidor no lo guarda y en el panel no existe «mostrar de nuevo». Si lo pierdes, rótalo para obtener uno nuevo, y el antiguo muere al instante. Nunca pongas el token en el control de versiones, en un log de CI ni en una ventana de chat; ponlo en el almacén de secretos del sistema de destino.
3. Haz la primera llamada y comprueba que llegó DE VERDAD — Bastan dos peticiones. La primera demuestra tu identidad (está exenta del alcance y funciona con cualquier clave): ¿el alcance es el que esperabas?, ¿el estado está activo?, ¿se acerca expires_at? La segunda lee datos reales del dominio que elegiste. Si pasa, la identidad, el alcance, el control de correo y la ruta de red son correctos. Si no pasa, no adivines: el propio registro de peticiones de la clave muestra, fila a fila, qué endpoint se rechazó, con qué código y con qué clave de error estable (INSUFFICIENT_SCOPE, IP_NOT_ALLOWED, KEY_ACTOR_BLOCKED …). En el panel, ese registro es la ventana «Recent requests»; en la terminal, es lg logs. El asistente vigila exactamente este registro y se niega a poner el paso en verde hasta que ve una llamada real correcta.
4. Configura el webhook y verifica la firma antes de hacer nada — Esperar eventos es más barato que preguntar cada minuto. Registra una dirección https, elige los eventos que te interesan y vincula la suscripción a tu clave: si la clave se revoca, la entrega también se detiene. El secreto solo se muestra una vez, al crearla. Tu endpoint receptor debe verificar primero la firma: la cadena firmada es «{t}.{cuerpo en bruto}» y el algoritmo es HMAC-SHA256; la marca de tiempo está DENTRO de la firma, así que descarta cualquier petición con más de 300 segundos de antigüedad aunque la firma sea válida. Compara en tiempo constante y nunca vuelvas a serializar el cuerpo: en el momento en que analizas el JSON y lo vuelves a imprimir, la firma deja de coincidir. Desde el panel, «Send test» dispara un ping firmado real y puedes seguir la entrega intento a intento.
Sandbox: practica escrituras sin tocar producción
La verificación previa (dry_run) te dice lo que HARÍA un comando; pero si la idempotencia repite de verdad, si el webhook se entrega de verdad, qué aspecto tienen las ramas de error y de dónde sale el crédito solo se ve en una escritura REAL. Para eso está el sandbox: un tenant separado que refleja tu empresa (el mismo código, el mismo catálogo de comandos) y que nunca toca tu registro live.
El sandbox no es un indicador de la petición, es un TENANT. Una empresa de Logistivo separada abierta para la tuya: su propio usuario, su propio paquete, su propio registro de créditos, sus propias suscripciones de webhooks. El entorno SE DEDUCE de la empresa de la clave y quien llama no puede indicarlo, así que aunque elijas el perfil equivocado la petición se detiene en el servidor con 403 ENVIRONMENT_MISMATCH. «Creía que escribía en el sandbox y escribí en producción» es estructuralmente imposible.
La superficie es idéntica, y está medido: el catálogo que obtiene una clave sandbox es el mismo que obtiene tu clave live (con una clave de cargador, 448 comandos en ambos lados). Un puente que funciona en el sandbox funciona en producción; nada de lo que aprendas tiene que aprenderse dos veces.
El sandbox no se abre vacío: contiene datos semilla generados (NO copiados): contactos, cargas en ambas direcciones y solicitudes. Los nombres son abiertamente inventados y las direcciones de correo están en el dominio @sandbox.invalid; nunca se lee, se clona ni se usa como plantilla ninguna fila de un tenant real.
A propósito, NO hay botón de reinicio, y nunca se borra ningún registro, archivo ni documento. Si quieres empezar de cero, la renovación abre una nueva generación y la antigua se queda, retirada. Unos cientos de filas de ensayo acumuladas no cuestan nada al lado de una rutina de borrado conectada al tenant equivocado.
1. Abre el sandbox — Un sandbox por empresa. El endpoint requiere permiso de gestión del equipo (team.manage), así que lo hace un administrador de tu empresa. Si ya existe, el mismo endpoint responde por GET con su estado: id de empresa, crédito restante, número de claves activas, suscripciones, historial de generaciones y los topes.
2. Emite una clave sandbox y guárdala como segundo perfil — La clave se emite en nombre del propio usuario puente del sandbox y vuelve marcada como environment: sandbox; el token en bruto solo aparece en esa única respuesta. En el lado de lg, no sustituyas tu clave live: guarda AMBAS como perfiles separados; --sandbox y --live son selectores para una sola ejecución.
3. Escribe de verdad — Aquí no hay --dry-run; escribir es justo lo que se busca. Envía la misma clave de idempotencia dos veces y verás que la segunda respuesta vuelve como status: replayed: ese es el resultado medido en el sandbox. Llama a propósito a un comando con control sin confirmación y lee el cuerpo del 409; prueba un comando fuera de tu alcance y lee el rechazo. Nada de eso deja rastro en tu registro live: tu saldo live no cambia durante esa misma ejecución.
4. Lee la lista de comprobación antes de pasar a producción — El endpoint go-live responde a partir de lo que hiciste REALMENTE en el sandbox: si escribiste, si viste las ramas de error, si se entregó un webhook, si sacaste el receptor de la dirección de ensayo, si pusiste una caducidad a la clave. Cada elemento vuelve como pass / todo / unknown. La misma respuesta lleva también una PROPUESTA DE ALCANCE derivada de los comandos que llamaste realmente: úsala para emitir tu clave live sin más amplitud de la que necesitas.
Crédito y facturación — El sandbox tiene su propio registro de créditos y tu saldo live no se mueve. Es una estructura, no una comprobación: el crédito se cuenta por empresa y el sandbox es una empresa separada. Se abre en el nivel gratuito, no tiene método de pago y está fuera de la ventana de cobro mensual: no puede llegar a una factura por ninguna vía.
Marketplace — Una solicitud que abras en el sandbox NO aparece en las pantallas de los transportistas reales y NO llega a su correo ni a sus notificaciones push; y tú tampoco ves solicitudes reales. La separación es simétrica y se aplica en dos consultas distintas: a quién le es VISIBLE una solicitud y a quién se le ENVÍA son preguntas diferentes.
Webhooks — Las suscripciones también llevan la marca de entorno. Un evento del sandbox nunca se entrega a una suscripción live y un evento live nunca llega a una del sandbox; para una suscripción cuya marca se haya desviado no se abre ninguna entrega. Como el tope de suscripciones es por empresa, tus suscripciones de ensayo no consumen tu cuota live.
Datos semilla — Los registros de ejemplo del sandbox son GENERADOS, nunca copiados de tenants reales. La siembra es idempotente: una segunda llamada no pone una segunda semilla encima de tus propios registros.
El mismo catálogo — Tu rol es tu rol también en el sandbox, y la lista de comandos es idéntica: medido, 448 comandos en ambos lados. El sandbox no es una demo recortada; es un gemelo de tu empresa.
Límite actual: las suscripciones de webhooks no se pueden gestionar con una clave sandbox — Los endpoints de suscripciones requieren el permiso de gestión del equipo (team.manage), y el usuario puente del sandbox no tiene ningún rol de equipo, así que hoy `lg --sandbox webhooks …` responde 403. Toda la superficie de comandos funciona; la restricción afecta solo al registro de suscripciones. Si quieres ensayar webhooks en el sandbox, pídelo a soporte; esto está medido y registrado como un hueco abierto.
GET /api/common/integration-sandbox — Estado: si existe, qué empresa, crédito restante, número de claves activas y de suscripciones, historial de generaciones, los topes y una guía de disparadores que muestra qué comando genera qué evento.
POST /api/common/integration-sandbox — Abre el sandbox (uno por empresa, idempotente). Requiere el permiso team.manage.
POST /api/common/integration-sandbox/keys — 201 + la clave y el token en bruto (solo aquí, solo una vez). La marca environment: sandbox se deduce de la empresa; quien llama no puede indicarla.
GET /api/common/integration-sandbox/go-live — La lista de comprobación para pasar a producción y una propuesta de alcance, calculadas a partir de tu tráfico real en el sandbox.
POST /api/common/integration-sandbox/renew — Abre una nueva GENERACIÓN del sandbox y retira la anterior.
El modelo de comandos
Hay una sola gramática y no tiene excepciones. Para saber cómo llamar a un comando, lo único que necesitas es lo que el catálogo dice de él.
lg loads list --status=in_transport --limit=20 --json
Los nombres de los flags son los nombres de parámetro del esquema, y lg acepta las dos grafías: --load_code y --load-code llegan al mismo campo (lg help muestra la forma kebab-case). Por eso, al ver un flag sabes en qué campo JSON acaba, y pasar de la CLI a HTTP no requiere traducir nombres. Un parámetro booleano escrito sin valor es true (--only_open); lo contrario es --no-only_open. Escribe un argumento cuyo valor empiece por guion como --flag=value; si no, un flag olvidado se traga en silencio el siguiente como su valor. En un comando que recibe un archivo, pon @ delante de una ruta local (--attachment_uuid=@./cmr.pdf); consulta Comandos que reciben archivos.
lg — El cliente.
loads — El dominio: la entidad con la que trabajas, en plural.
list — El verbo: lo que haces con esa entidad, tomado de un vocabulario cerrado que solo crece por decisión deliberada: verbos simples (list, get, create, update, delete, search, preview, generate, extract …) y verbos compuestos que nombran lo que se adjunta o se cambia (add-document, set-status, assign-driver). lg help lista los verbos de un dominio.
--status=in_transport — Un parámetro: su nombre es exactamente el nombre del parámetro en el JSON Schema y su valor debe coincidir con el tipo del esquema. Un valor no válido en un campo enum nunca llega al servidor.
--limit=20 — Número de filas en los comandos de listado. El máximo se indica en la descripción de parámetros de cada comando: normalmente 20 en una llamada de listado simple y hasta 100 en modo sincronización (con cursor o updated_since).
--json — Salida JSON sin procesar.
--json — Imprime JSON sin procesar. Es la única forma correcta para scripts: la tabla alineada por defecto es para personas, elige sus columnas según los datos y puede cambiar de formato sin aviso. Nunca escribas un script que analice la salida en tabla.
--yes, -y — Supera el control de confirmación (confirm: true por HTTP). Úsalo solo en un script que sepa lo que va a hacer; en un comando irreversible, este flag equivale a decir «no hay vuelta atrás».
--idempotency-key= — Hace que reintentar un comando de escritura sea seguro. Una segunda llamada con la misma clave no vuelve a ejecutar el comando; devuelve el primer resultado. Si construyes un bucle de reintentos, genera la clave TÚ MISMO y envía la misma en cada intento.
--dry-run — Ejecuta una verificación previa en lugar del comando: se ejecutan la validación, los controles y el cálculo de créditos, y no se escribe nada (consulta la sección de verificación previa). Válido en todos los comandos y en lg batch.
--refresh — Fuerza la actualización del catálogo. lg guarda el catálogo en caché durante una hora; si sabes que se acaba de añadir un comando en el servidor, usa esto en lugar de esperar.
--help, -h — Imprime la descripción del comando en el catálogo, cada parámetro, su tipo, sus valores enum y si es obligatorio. No hay ningún archivo de ayuda dentro del cliente.
--profile=, --sandbox, --live — Con qué perfil ejecutar esta llamada concreta. --sandbox y --live eligen el perfil que contiene una clave sandbox o una clave live; el entorno se deduce de la clave en el servidor, así que una discrepancia se detiene con 403 ENVIRONMENT_MISMATCH en lugar de escribir en el sitio equivocado.
--base-url, --timeout, --verbose, --no-color, --version — Respectivamente: apuntar un comando a otro servidor, un tiempo de espera en segundos, detalle de petición/respuesta, desactivar el color ANSI y la versión del cliente.
Ejemplos reales
Todos los comandos de abajo existen hoy en el catálogo; aquí no hay ningún nombre ni parámetro inventado. Las salidas están abreviadas. Las salidas muestran el nivel `data.result`; por HTTP el mismo objeto llega dentro del sobre `{success, data:{…}}` (consulta la API de comandos HTTP).
Cargas que están ahora en carretera — lg loads list --status=in_transport --limit=20
Una carga completa, en JSON sin procesar — lg loads get --load_code=FSK2158 --json
Indicadores abiertos de coherencia documental — lg loads list-problems --only_open=true --limit=10
Resolver el país — lg countries search --query=Germany --json
Filtrar con el id resuelto — lg loads list --receiving_country_id=57 --date_from=2026-09-01 --limit=20
Encontrar un código HS a partir del nombre de un producto — lg tariffs search --query="aluminium profile"
Hacer avanzar una carga (solo rol de transportista) — lg loads set-status --load_code=FSK2158 --status=transit --date=2026-08-21 --yes
Borrador — lg export-documents create --doc_type=proforma-invoice --currency_code=EUR --json
Generarlo (con control) — lg export-documents generate --document_id=8412 --yes
Sin el cliente: la API de comandos HTTP
lg es una comodidad, no la puerta. Tanto el catálogo como la ejecución pasan por tres endpoints HTTP (los archivos tienen un cuarto, el endpoint de subida; consulta Comandos que reciben archivos); una integración con ERP o CRM se conecta aquí directamente. La identidad es un token de acceso personal enviado en Authorization: Bearer. TODAS las respuestas llegan en el mismo sobre: `{ "success": bool, "data": { … }, "code": "…", "message": { … } }`. Todo el contrato vive dentro de `data`: `contract_version`, `command`, `status` y, como salida del comando, `result`; en caso de fallo, `error_code`, `error_key` y `error`. Los ejemplos de respuesta de esta página muestran el objeto `data` en lugar del sobre, para ahorrar espacio; no olvides desenvolver `data` en tu propio código. `lg --json` también imprime el sobre COMPLETO, y por eso las rutas jq empiezan por `.data.result…`. La única excepción es `/api/public/status`: ese endpoint no lleva sobre para que los sistemas de vigilancia puedan alertar sin analizarlo.
Pedir confirmación con 200 + ok:false está prohibido y nunca ocurrirá. La razón es sencilla: los clientes tratan 200 como éxito, así que una petición de confirmación devuelta como 200 cortaría el flujo en silencio y nadie se daría cuenta. La confirmación siempre es 409.
GET /api/common/commands — Todo el catálogo que tu rol puede ver: contract_version; por comando, name, domain, verb, description, JSON Schema, read_only, confirmation_needed, irreversible, credit_cost, since, deprecated_at, replaced_by, aliases y los campos de acceso key_level, permission, file_params, secret_parameters y cli_only; en el nivel superior, el diccionario error_keys, rate_limits, idempotency_ttl_hours, tus roles del catálogo, el contrato de attachments (subida) y el nivel de acceso de la clave con la que llamas. Envía un ETag; If-None-Match responde 304. ?domain= también coincide con un dominio antiguo (alias). Construye tu cliente a partir de esto; no codifiques una lista de comandos a mano.
GET /api/common/commands/{name} — Un comando completo. name es el nombre congelado del comando en el catálogo (list_loads), no la identidad de la CLI. Un comando obsoleto responde con una cabecera X-Deprecated.
POST /api/common/commands/{name} — Ejecución. Cuerpo: { args, confirm?, idempotency_key? }. El estado HTTP de la respuesta es el propio resultado: cualquier cosa distinta de 200 es información, no ruido. Los errores llevan error_code (transporte) y, en los rechazos de negocio, error_key.
Comandos que reciben archivos
33 comandos de la tabla reciben un documento o una foto: adjuntar un CMR a una carga, leer los códigos HS de una factura, crear un vehículo a partir de su permiso de circulación, estimar un palé a partir de fotos, subir un documento de empresa, cotejar una factura con una lista de bultos (packing list). En el navegador, sueltas el archivo en un formulario; en cualquier otro sitio son dos pasos: subir el archivo y pasar su id al comando.
Un parámetro recibe un archivo cuando su nombre termina en attachment_uuid o attachment_uuids: photos[].attachment_uuid dentro de una lista, front_attachment_uuid en un cheque. No tienes que recordarlo: cada fila del catálogo lleva file_params con las rutas exactas, el esquema marca esos campos (format: uuid, x-logistivo-file: true) y la respuesta del catálogo lleva un bloque attachments con la dirección de subida, los tipos aceptados, los límites de tamaño y el tiempo de vida. lg help también los muestra.
Subir es una escritura, así que una clave con alcance de lectura no puede subir; cualquier clave con alcance de escritura puede, con cualquiera de los dos niveles de acceso. Las subidas pertenecen al usuario, no a la clave: dos claves del mismo usuario ven las mismas subidas, y nadie puede usar las de otra persona. Un id desconocido, caducado o que no es tuyo simplemente no se encuentra, y no se revela el motivo.
Los adjuntos del chat del panel y las subidas de comandos son espacios separados: un archivo adjuntado en el chat del asistente no se puede pasar a un comando por su id, y una subida de comando nunca aparece en un hilo de chat.
Una subida no es un comando y no tiene ningún efecto de negocio por sí sola: no pasa nada con tus datos hasta que un comando usa el id. Por eso subir nunca pide confirmación: el control lo lleva el comando que consume el archivo.
1. lg: pon @ delante de una ruta local — lg sube primero el archivo y después ejecuta el comando con el id devuelto; un valor sin @ es el id de un archivo que subiste antes. Las listas aceptan rutas separadas por comas o un flag repetido, los campos anidados aceptan JSON, y --file es un atajo cuando el comando tiene exactamente un campo de archivo de primer nivel. lg verifica cada archivo en local (que exista, su tamaño, su tipo) antes de enviar nada, y lg batch sube cada archivo distinto una sola vez antes de ejecutar el lote.
2. HTTP: sube el archivo y luego pasa attachment_uuid — Envía el archivo como multipart/form-data en un campo llamado file. Una subida nueva responde 201; el mismo archivo subido de nuevo por el mismo usuario responde 200 con el estado replayed y el mismo id, y no se escribe nada. Como en toda esta página, el ejemplo muestra el objeto data dentro del sobre.
3. MCP: la herramienta upload_attachment — Un cliente MCP no puede enviar multipart, así que el canal ofrece una herramienta extra que no está en el catálogo: upload_attachment recibe un nombre de archivo y el contenido en base64 y devuelve el mismo attachment_uuid. Llama al mismo servicio que la subida por HTTP, con las mismas reglas.
El tipo sale del contenido — El nombre del archivo y el tipo declarado se ignoran; la extensión guardada es la detectada. Se aceptan para subir: jpg, jpeg, png, webp, heic, heif, pdf, xlsx, xls, csv, txt, doc, docx, xml, zip. Después, cada comando aplica su propia lista, más restringida, antes de ejecutar nada y responde UNSUPPORTED_FILE_TYPE con los tipos aceptados, o FILE_TOO_LARGE.
Tamaño — Imágenes de hasta 10 MB, otros archivos de hasta 15 MB.
Tiempo de vida — Una subida se puede usar durante 24 horas. Después ya no se resuelve (ATTACHMENT_NOT_FOUND), pero no se borra. Vuelve a subirla si un comando falla por ese motivo.
Mismo archivo, mismo id — Volver a subir el mismo archivo (mismo nombre, tamaño y contenido) devuelve el id existente en lugar de escribir uno nuevo, siempre que le quede al menos una hora, y no consume tu tope diario.
Topes diarios — 300 subidas por usuario y día (TOO_MANY_FILES) y 2 GB por empresa y día (DAILY_LIMIT_REACHED); ambos responden 429 con retry_after.
POST /api/common/commands:upload — Subida multipart en el campo file. 201 para una subida nueva, 200 con el estado replayed para el mismo archivo. Devuelve data.attachment: attachment_uuid, filename, mime_type, size_bytes, sha256, extraction_status, expires_at y reused.
El control de confirmación y los comandos irreversibles
Cada comando del catálogo lleva dos indicadores: confirmation_needed (si requiere aprobación explícita antes de ejecutarse) e irreversible (si su efecto se puede deshacer). Son preguntas distintas, y ambas se aplican en el servidor en lugar de dejarse a la buena educación del cliente.
El control tiene que ver con la responsabilidad, no con las reglas de negocio. Hacer una oferta es el primer paso hacia un contrato de transporte; emitir una factura crea un asiento contable; un movimiento de stock modifica un libro de registro. Nada de esto debería poder ejecutarse dos veces por accidente.
El control se lee del comando EFECTIVO. Cuando un comando envuelve a otro (como hace el ejecutor genérico del chat), el control sale de los indicadores del comando que realmente se va a ejecutar, no del envoltorio. Con un indicador fijo, uno de dos fallos sería inevitable: o el comando de facturas se ejecutaría sin confirmar, o cada consulta de país mostraría una tarjeta de confirmación.
read_only y sin control no son lo mismo. Hay tres estados distintos: invoices preview no tiene control y no escribe nada; loads create tiene control y escribe; invoices create no tiene control pero escribe (nace un borrador). Lo decide una sola prueba: cuando el comando termina, ¿ha cambiado alguna fila en la base de datos?
Algunas acciones no están detrás de este control porque directamente no son comandos: comprar un paquete, añadir una tarjeta con 3D Secure, aprobar textos legales y cerrar una cuenta ocurren en el propio navegador de la persona. Para eso, lg handoff-links generate devuelve un enlace de logistivo.com (gratuito, sin escribir nada y sin llevar ningún secreto) y la persona termina el paso allí. Ningún indicador, lo pongas como lo pongas, convierte un pago o un consentimiento en una llamada a la API.
Técnicamente es posible que una integración supere el control automáticamente en cada llamada, pero no es recomendable. El patrón correcto es automatizar el control solo para los comandos que sabes que son reversibles y enviar los irreversibles a la cola de una persona.
1. Llámalo — Llama al comando con control sin confirm. No cambia nada.
2. Lee el resumen — Recibes un 409; confirmation.summary en el cuerpo es una frase escrita para una persona («Se va a emitir una factura: X Ltd, 1.200,00 TRY»), no un volcado de argumentos sin procesar. Los comandos monetarios también llevan una vista previa estructurada: líneas, totales y avisos.
3. Confirma — Repite la misma llamada con confirm: true (--yes en la CLI). Los comandos irreversibles están marcados para que se ejecuten como máximo una vez.
Verificación previa: mira lo que haría un comando de escritura sin ejecutarlo
El paso más caro al conectar un puente con un ERP es descubrir si tu cuerpo de petición es correcto ejecutando REALMENTE el comando: un borrador de factura en el libro real, un crédito quemado, limpieza manual. dry_run (ejecución en seco) acaba con eso: añades un campo a la petición, el comando no se ejecuta y lees lo que pasaría.
Hoy el registro contiene 519 comandos; 233 de ellos solo leen y no escriben nada. De los 286 comandos de escritura restantes, 251 tienen control: llamados sin confirm ya responden 409 y describen lo que harían. El hueco eran los otros 35: borradores de factura, borradores de documentos de exportación, líneas; justo la cadena que un puente conecta primero. En esos, llamar era hacer.
Había un segundo hueco incluso en los comandos con control: la validación del esquema se ejecuta DESPUÉS del control. Así que una llamada a la que le faltaba un argumento recibía primero la tarjeta de confirmación, la confirmaba y solo entonces oía «falta este campo». Una verificación previa responde a ambas cosas en un solo viaje de ida y vuelta.
Y el error de puente más común (y el que más tarde se descubre) es este: envías un campo que no está en el esquema (customer_id donde se espera recipient_contact_id), el servidor lo descarta en silencio, el comando devuelve 200 y el registro acaba en el sitio equivocado. La respuesta de la verificación previa enumera esos campos por su nombre bajo arguments.ignored; ningún mensaje de error lo hará nunca.
Una verificación previa no escribe nada, y eso es estructural antes que una medición: la ruta de verificación previa nunca entra en el handler del comando, así que se cumple para todos los comandos, incluidos los que se añadan más adelante. También se midió cuando se lanzó: se capturó cada sentencia SQL emitida al verificar previamente todos los comandos de escritura del catálogo de ese momento (dos conjuntos de argumentos, dos roles, 178 verificaciones previas). Ni un solo INSERT/UPDATE/DELETE, ni un solo job en cola, ni un solo correo; el número de filas en 31 tablas y el saldo de créditos no cambiaron.
El código de salida es el mismo que produciría la llamada real (se ejecutaría 0, control de confirmación 4, conflicto de idempotencia 2, cualquier otra cosa 1), así que «lg … --dry-run || exit» es un control con sentido en un paso de CI.
1. Llámalo con dry_run — Añade "dry_run": true al cuerpo de la petición. Se ejecutan la validación, el control de rol y alcance, la resolución del destino y el cálculo de créditos; el comando no.
2. Lee would_execute — Es el único indicador sobre el que ramificar. Cuando es false, would_stop.at indica dónde se detendría una llamada real: idempotency, target_precheck, confirmation_gate o arguments.
3. Corrige tu cuerpo de petición — arguments.ignored nombra los campos que se descartarían en silencio, missing_required los obligatorios que omitiste, y would_charge cuántos créditos se irían y si el saldo los cubre.
4. Quita dry_run — Repite hasta que would_execute sea true; después quita el indicador y haz la llamada real. La clave de idempotencia que enviaste durante la verificación previa no se consumió, así que la llamada real se ejecuta con normalidad.
HTTP siempre es 200 — «El comando fallaría» nunca llega como un 4xx: la verificación previa en sí tuvo éxito y la predicción está en el cuerpo. La excepción es un rechazo de transporte, y ahí se comporta exactamente como una llamada real: 404 comando desconocido, 403 rol/alcance, 429 límite de peticiones.
Una clave con alcance de lectura no puede hacer un dry run de un comando de escritura — Recibe un 403. Una verificación previa responde a «qué pasa si llamo a esto CON ESTA CLAVE, ahora»; dar luz verde a una clave de lectura y luego un 403 en la llamada real sería precisamente la sorpresa que la verificación previa existe para evitar.
La clave de idempotencia no se consume — Una clave enviada durante una verificación previa no abre ninguna fila en el registro, y un bloqueo caducado no se libera. Así que envía la clave que piensas usar de verdad: la verificación previa te dice si sigue libre, si repetiría una ejecución anterior o si choca con otro comando.
Se combina con confirm — Envía dry_run y confirm juntos y la pregunta pasa a ser «si confirmo, ¿qué pasa?». Sigue sin ejecutarse nada.
La verificación previa de un lote es por lote — commands:batch también acepta dry_run, pero el indicador pertenece al lote, no a un elemento (enviarlo en un elemento da un 422). Recibes un informe por elemento más el coste total de créditos del lote; un saldo insuficiente se informa, no se rechaza.
No es gratis — Cada verificación previa ejecuta consultas reales (vista previa, saldo) y cuenta para el límite de peticiones. No verifiques previamente todo el catálogo en cada despliegue; verifica los comandos que cambiaste.
Idempotencia: por qué reintentar no crea duplicados
Un ERP no lee tu mensaje de error, no ve tu pantalla y volverá a enviar la misma petición tras un tiempo de espera agotado. Esta sección existe exactamente para ese comportamiento.
Una llamada que lleva un idempotency_key (clave de idempotencia) se ejecuta como máximo una vez. La segunda llamada no vuelve a ejecutar el comando; devuelve el resultado registrado con el estado replayed. Cuando se cae la red, cuando una petición agota el tiempo de espera o cuando una cola recoge el mismo trabajo dos veces, recibes el primer resultado en lugar de una factura duplicada.
Usa una clave en todos los comandos de escritura. El campo read_only del catálogo te da esa distinción gratis: todo comando con read_only: false merece una clave de idempotencia.
Tu estrategia de reintentos debe usar backoff exponencial y llevar la MISMA clave en cada intento. Generar una clave nueva en cada intento equivale a no usar idempotencia en absoluto. No envíes la misma clave en paralelo: el «como máximo una vez» está garantizado para reintentos secuenciales, no para dos peticiones que compiten entre sí.
Trampa 1: el fallo también queda bloqueado — Si la primera ejecución fue rechazada por una regla de negocio (failed), una segunda llamada con la misma clave devuelve el mismo error y el mismo error_key, y no reintenta. Corregir el argumento y volver a intentarlo requiere una clave NUEVA. Una clave representa un intento, no una intención.
Trampa 2: un resultado grande se repite sin cuerpo — El registro guarda un resultado solo si ocupa menos de 64 KB. Un resultado mayor se repite con el estado replayed pero con el cuerpo vacío. Tu integración debe fiarse de la señal «replayed» y no del cuerpo, y obtener los datos con el comando get correspondiente.
Trampa 3: una clave pertenece a un comando — Enviar la misma clave con un comando distinto devuelve 409 idempotency_conflict con el conflicting_command; no se ejecuta nada y no se repite nada. Un cliente que comparte una clave entre dos verbos está roto, y lo descubre por un error, no por una repetición silenciosa.
Trampa 4: el bloqueo dura 24 horas, no para siempre — Pasadas 24 horas, la misma clave es una ejecución nueva. Los reintentos de red llegan en cuestión de minutos; los números de documento recurrentes anuales de un ERP no deben quedarse en «replayed» para siempre. El catálogo publica la ventana como idempotency_ttl_hours.
Trampa 5: un error del servidor no bloquea la clave — Un 5xx server_error no es un rechazo de negocio: la clave no queda vinculada, así que un reintento con la misma clave ejecuta realmente el comando. Solo failed bloquea (trampa 1).
Alcance y formato: tu empresa, cualquier cadena, mejor un UUID — La unicidad se aplica sobre (tu empresa, clave): el INV-1001 de otro tenant nunca choca con el tuyo y nunca puede repetir tu resultado. Usa un UUID simple o un compuesto que sea único por construcción, como {ERP-document-no}:{verb}.
Sincronización incremental y paginación
Un puente ERP/CRM debe traer lo que ha cambiado, no todo cada hora. Todos los comandos de listado (loads list, demands list-own, contacts list, invoices list, teammates list, load-groups list, reservations list, drivers list, tenders list, products search, warehouses search) aceptan dos parámetros compartidos y devuelven un campo compartido.
Por qué no hay offset: en una tabla viva, un offset se desplaza. Una fila insertada entre dos páginas hace que te saltes o cuentes dos veces un registro, en silencio. El cursor solo avanza, así que un registro insertado o actualizado a mitad del recorrido acaba al final de la lista: no se pierde nada ni se duplica nada.
Una carga inicial completa es el mismo mecanismo: empieza con updated_since=1970-01-01T00:00:00Z y sigue next_cursor hasta que sea null. No hay un endpoint de «exportación» aparte porque no hace falta.
Lo mismo con lg: lg loads list --updated_since=2026-09-01T00:00:00Z --limit=100 --json, y después lg loads list --cursor= --json.
Para la siguiente sincronización, pon en updated_since el mayor updated_at que hayas visto. Las marcas de tiempo tienen precisión de un segundo, así que un registro en el límite puede llegar dos veces; es inofensivo siempre que hagas upsert por external_ref o por código en tu lado. Sin updated_since ni cursor, un comando se ejecuta en modo chat: orden pensado para personas, como máximo 20 filas, next_cursor a null y truncated indicando que «hay más». No uses ese modo para sincronizar.
Claves de error legibles por máquina de esta sección: INVALID_CURSOR, INVALID_UPDATED_SINCE, DUPLICATE_EXTERNAL_REF, EXTERNAL_REF_TOO_LONG, EXTERNAL_REF_INVALID. Todas responden HTTP 422 con error_code: "failed" y result.error_key en el cuerpo. Ramifica según la clave, nunca según el texto.
updated_since — Marca de tiempo ISO-8601 (se recomienda UTC, p. ej. 2026-09-01T00:00:00Z). Filas actualizadas en ese instante o después. Pasa el comando a modo sincronización: orden fijo (updated_at, id) ascendente, limit con un máximo de 100.
cursor — El next_cursor de la respuesta anterior, tal cual. Es opaco y está firmado: nunca construyas ni edites uno, nunca reutilices el cursor de otra empresa o de otro comando; todo eso se rechaza con INVALID_CURSOR.
limit — Tamaño de página. 1-100 en modo sincronización (10 por defecto).
next_cursor (respuesta) — Cursor de la página siguiente. null significa que la lista está completa; es la única respuesta correcta a «¿hay más?».
total (respuesta) — Filas que cumplen los filtros, con independencia de la página; sirve para informar del progreso.
Tu propia clave: external_ref
No conviertas nuestros ids autoincrementales (invoice_id, contact_id) en la clave de negocio de tu ERP; son opacos y privados de tu empresa. Las cargas, solicitudes, contactos, facturas, productos y almacenes llevan tu clave en su lugar.
Defínela al escribir — loads create, demands create, contacts create y contacts update, e invoices create aceptan un external_ref opcional (máximo 120 caracteres) y lo devuelven sin cambios.
Úsala al leer — loads get --external_ref=ORD-2026-0917, invoices get --external_ref=..., contacts get --external_ref=..., demands get --external_ref=... funcionan todos; en los comandos de listado y búsqueda, --external_ref= es un filtro de coincidencia exacta.
Única por empresa — Un segundo registro con la misma clave se rechaza con 422 y result.error_key = DUPLICATE_EXTERNAL_REF; la clave de otra empresa te responde «no encontrado». La comparación no distingue mayúsculas de minúsculas (ord-1 = ORD-1). Un registro archivado conserva su clave; restáuralo antes de reutilizar la clave.
Envía también un idempotency_key — Un reintento tras un tiempo de espera agotado en la red devuelve el primer resultado en lugar de crear un duplicado. Los dos no son intercambiables: external_ref es tu clave de negocio, idempotency_key identifica un intento.
Webhooks salientes: te hacemos un POST cuando ocurre algo
Todo lo anterior era pull: tú preguntas y nosotros respondemos. Un puente ERP tenía que preguntar una vez por minuto para enterarse de que una carga había cambiado de estado, de que se había emitido una factura o de que había llegado una oferta. Ya no: registra una dirección https, elige los eventos que te interesan y te llegará un POST firmado cuando ocurran.
El push se añadió JUNTO AL pull, no en su lugar. La sincronización incremental (updated_since + cursor) sigue intacta y sigue siendo la herramienta adecuada: la primera carga completa, el relleno del histórico y la respuesta a «¿me he perdido algo?» viven ahí. Los webhooks reducen la latencia de minutos a segundos. Un puente sano usa ambos: el webhook como disparador y la sincronización como red de seguridad.
El payload es una SEÑAL, no una copia del registro. Lleva los identificadores (id, tu propio external_ref, status, hora); el detalle lo obtienes tú con tu propia clave mediante GET, y esa llamada ya pasa por tus propios controles de autorización. Por eso la superficie de exposición se queda en el nivel de identificadores. Faltan dos campos de forma deliberada: la identidad de la empresa que hizo una oferta (las ofertas ciegas aparecen con un alias en el panel; poner la identidad en un webhook rompería esa privacidad por un segundo canal) y los datos de contacto de las reservas (no hace falta mover datos personales por un canal adicional).
Los nombres de los eventos están CONGELADOS. Si cambia el significado de un nombre, se abre un nombre nuevo y el antiguo sigue vivo durante una ventana de obsolescencia. Añadir un campo nuevo al payload NO sube la versión del contrato: un consumidor debe ignorar los campos que no conoce.
GET /api/common/integration-webhooks — El registro más el catálogo de eventos, los límites y los nombres de las cabeceras. Cada fila lleva su motivo de silenciamiento y un resumen de entregas de los últimos 7 días.
POST /api/common/integration-webhooks — 201 + { webhook, secret, shown_once: true }. El secreto solo aparece aquí.
PATCH /api/common/integration-webhooks/{uuid} — Nombre / dirección / eventos / indicador de activo. NO toca el secreto.
DELETE /api/common/integration-webhooks/{uuid} — La elimina: la fila se borra de forma lógica (soft delete; el historial sigue siendo consultable) y las entregas pendientes se cancelan.
POST /api/common/integration-webhooks/{uuid}/rotate-secret — 201 + un secreto nuevo. El valor antiguo deja de funcionar en ese momento.
POST /api/common/integration-webhooks/{uuid}/test — Un evento ping: firma real, ruta real, calendario de reintentos real.
GET /api/common/integration-webhooks/{uuid}/deliveries — Las entregas más recientes: estado, número de intento, código HTTP, duración, etiqueta de error.
POST /api/common/integration-webhooks/deliveries/{uuid}/replay — Reenvía una sola entrega: el event_id se CONSERVA, el id de entrega es nuevo y el payload se copia literalmente.
Catálogo de eventos
Cada uno de los 13 eventos de abajo está respaldado por una clase de evento que se despacha REALMENTE. En el catálogo no hay nombres del tipo «estaría bien»: un evento que se anuncia pero nunca se dispara es un evento que el integrador espera para siempre, y ese fallo es silencioso. Esta tabla tampoco está escrita a mano: se genera a partir del catálogo en vivo en cada carga de la página.
invoice.payment_recorded está AUSENTE a propósito: esa clase de evento existe en el código pero no se despacha desde ningún sitio. El evento de pago se añadirá el día en que la clase se dispare de verdad, no antes. Anunciar un evento antes de tiempo es peor que no añadirlo nunca.
load.created — A load became visible to your company (created by you or shared with you). (load)
load.status_changed — A load moved to a new status (pending, in_transport, transit, done). (load)
load.driver_assigned — A driver was assigned to a load. (load)
demand.created — A freight demand was created by your company. (demand)
demand.status_changed — A freight demand changed status. (demand)
demand_bid.created — A bid was placed on a demand you are party to. (demand_bid)
demand_bid.revised — A bid was revised (a new revision replaced the previous one). (demand_bid)
demand_bid.accepted — A bid was accepted. (demand_bid)
invoice.created — An invoice draft was created. (invoice)
invoice.issued — An invoice was issued (it now carries an invoice number). (invoice)
invoice.cancelled — An invoice was cancelled. (invoice)
warehouse_reservation.created — A warehouse dock/area reservation was created. (warehouse)
warehouse_reservation.status_changed — A warehouse reservation was approved, rejected or otherwise moved. (warehouse)
Verificar la firma
Cada petición lleva una cabecera X-Logistivo-Signature: t=,v1=. La cadena firmada es «.» y el algoritmo es HMAC-SHA256. El prefijo v1 permite versionar el esquema: si algún día llega un segundo esquema, la cabecera llevará t=…,v1=…,v2=… y tú eliges el que conoces.
Publicamos dos receptores de referencia sin dependencias, uno para Node y otro para PHP puro. Ambos aplican las cuatro reglas anteriores y se prueban a sí mismos con --selftest: firma válida, cuerpo manipulado, secreto incorrecto, marca de tiempo fuera de la ventana, cabecera malformada, la trampa de la reserialización y los dos tipos de repetición (misma entrega / mismo hecho). El verificador es la contrapartida exacta del código que usamos nosotros: consumimos el contrato que publicamos.
Verifica el cuerpo EN BRUTO — La firma se calcula sobre bytes. Decodificar y volver a serializar el cuerpo (JSON.stringify(req.body), json_encode($request->all())) convierte los mismos DATOS en BYTES distintos y la firma deja de coincidir. En Node la trampa es el formato de los números (1.50 en la red se convierte en 1.5; los enteros grandes pierden precisión); en PHP es el escapado de caracteres (/ se convierte en \/, İ se convierte en \u0130). Usa express.raw en Express y $request->getContent() en Laravel. Es el error más común al escribir un receptor.
Comprueba la marca de tiempo — t está DENTRO de la firma. Verificar solo la firma permite que cualquiera que haya capturado una petición válida la reproduzca horas después, y el receptor la contaría como un evento verificado. Descarta cualquier petición en la que |now − t| > tolerance aunque la firma sea correcta. La ventana recomendada es de 300 segundos.
Compara en tiempo constante — hash_equals / timingSafeEqual. Comparar con == permite a un atacante adivinar la firma byte a byte.
Deduplica por event_id, no por id — event_id identifica el HECHO: es el mismo para dos suscriptores que reciben el mismo evento y se CONSERVA en un reenvío. id (= X-Logistivo-Delivery) identifica la ENTREGA y cambia en un reenvío. Responde a «¿ya he procesado esto?» con event_id; si lo respondes con id, un reenvío hará el mismo trabajo dos veces.
Entrega, reintentos y silenciamiento
Tu receptor no siempre estará disponible. La vía lo asume: un fallo transitorio entra en el calendario de reintentos, uno permanente silencia la suscripción, y el MOTIVO del silenciamiento siempre se registra.
El motivo del silenciamiento es legible por máquina y estable (delivery_failures, endpoint_gone, unsafe_target, key_revoked, by_user) y aparece tanto en el panel como en `lg webhooks list`. Silenciar sin motivo dejaría sin respuesta la pregunta «¿por qué no llega nada?». Al volver a activar la suscripción se reinician el contador y la marca.
Tú escribes la dirección; NUESTRO servidor hace la petición. Sin un control, un tenant que introdujera una dirección de metadatos de la nube podría hacer que emitiéramos peticiones desde dentro de nuestra propia red. Por eso la dirección se comprueba tanto al registrarla como en CADA entrega:
Tiempos de espera — 8 s en total, 4 s para conectar: un receptor lento no debe ocupar un worker. Pon el trabajo en cola y devuelve 2xx de inmediato.
Calendario de reintentos — 60 · 300 · 1800 · 7200 · 21600 segundos → 6 intentos, una ventana de aproximadamente 8,6 horas.
El único fallo permanente: 410 Gone — Significa «bórrame»: sin reintento, la suscripción se silencia en el acto. NUNCA devuelvas 410 por un fallo de firma.
Cualquier otro fallo — Se reintentan TODOS, incluidos los 4xx. Perder un evento de negocio cuesta más que unas pocas peticiones de más: un receptor que devuelve 403 mientras se actualiza una regla del WAF perdería en silencio un evento de «factura emitida» en una vía que tratara los 4xx como permanentes.
Retry-After — Se respeta en 429 y 503 (con un máximo de 6 horas).
Redirecciones — NO se siguen. Saltar a una dirección interna mediante un 302 rompería el control de direcciones por una segunda vía.
Silenciamiento automático — Tras 10 entregas agotadas consecutivas. Un 410, un destino inseguro y la revocación de la clave de integración vinculada silencian INMEDIATAMENTE.
solo https, solo los puertos 443/8443, se rechazan las credenciales incrustadas (https://user:pass@…);
se rechazan localhost, los nombres de una sola etiqueta y los sufijos internos como .internal / .local / .svc: la intención se rechaza antes incluso de mirar el resultado de la resolución, así que el DNS de horizonte dividido (split-horizon) no puede romper el control;
los literales IP y TODOS los registros de la resolución DNS deben ser públicos. Si un nombre resuelve a la vez a una dirección pública y a una privada, nadie nos pregunta cuál elegir → el nombre se rechaza directamente;
en el momento de la entrega, la dirección se resuelve una vez y la conexión queda fijada a la dirección verificada: la ventana de DNS rebinding queda cerrada;
el CUERPO de la respuesta del receptor nunca se guarda en ningún sitio (solo el código de estado, la duración y una etiqueta de error corta), así que la vía de «lectura», que es lo que realmente vale un agujero en el control de direcciones, sigue cerrada.
A propósito, NO existe ningún interruptor de configuración para «permitir direcciones privadas»: un interruptor así acaba quedándose activado por accidente algún día.
Se devuelve UNA SOLA VEZ, solo al crear la suscripción y en rotate-secret. Se guarda cifrado en el servidor y nunca se puede volver a leer; no existe «mostrar de nuevo».
lg lo imprime en pantalla y lo deja ahí: no lo escribe en ningún archivo de configuración ni de caché.
Si se pierde, lo rotas; el valor antiguo deja de funcionar EN ESE MOMENTO. Para un cambio sin cortes, tu receptor debería probar ambos secretos durante la transición.
Cambiar la dirección NO toca el secreto: un mantenimiento rutinario como «la URL se ha movido» no debe romper la verificación en el lado receptor.
Salud y estado: nadie debería notar un puente silencioso antes que tú
Un puente de integración rara vez muere haciendo ruido. Lo normal es que se quede callado de madrugada: un token caduca, la persona en cuyo nombre actúa la clave deja el equipo, se reduce un alcance o el endpoint receptor empieza a devolver 403. Quien lo nota primero es casi siempre el cliente. lg status existe para invertir ese orden.
Un solo comando responde a dos preguntas a la vez, porque durante una incidencia ambas se hacen en el mismo momento: ¿está activa la plataforma? y ¿está sano mi puente? La línea de la plataforma funciona sin token: durante un fallo, el propio token es el primer sospechoso, y atar la pregunta del estado a él te dejaría sin respuesta justo cuando la necesitas.
El resumen de salud no mantiene ningún registro nuevo; condensa tres fuentes existentes en una sola frase: el contador de uso diario (cuánto llamaste y cuánto falló), el registro de peticiones (qué petición, cuándo y por qué se rechazó) y el registro de entregas de webhooks salientes (si el evento llegó al receptor). La tasa de error siempre se lee del contador diario; el registro detallado tiene un tope y lo dice claramente cuando se alcanza.
El mismo resumen aparece en el panel: en Settings › Integration › Keys, cada fila lleva un distintivo y, debajo, el motivo. Los umbrales no se calculan en el cliente; el nivel que asignó el servidor es el que pintan tanto el panel como lg status, así que las dos pantallas nunca pueden decir cosas distintas sobre la misma clave.
Tu sistema de vigilancia no necesita token. El endpoint devuelve solo palabras de estado; no lleva versión, nombre de host, nombre de cola, número de trabajos, texto de error ni datos de clientes, y no puede llevarlos.
El resumen de salud se genera con un número constante de consultas por petición; el número de consultas no crece con el número de claves. Para el detalle, lee las peticiones recientes de esa clave con lg logs y el puente saliente con lg webhooks list.
SALUDABLE — Ningún fallo medido y tenemos prueba de éxito: una llamada correcta en el registro, o tráfico que se mantuvo sin errores en el contador.
ATENCIÓN — Algo ha empezado a romperse: la tasa de error o la racha de fallos consecutivos ha superado un umbral, se están rechazando peticiones en el control, la clave está a punto de caducar, o un puente que hablaba con regularidad se ha quedado callado.
FALLANDO — El puente no funciona ahora mismo: el token se revocó sin querer, se sigue llamando a una clave cerrada, hay cinco fallos seguidos, la tasa de error supera el cincuenta por ciento o se ha silenciado una suscripción de webhook.
CERRADA — La clave se cerró deliberadamente y nadie la está llamando. Es una decisión, no un fallo, y no se pinta de rojo.
SIN DATOS — No hay medición: la clave nunca se ha llamado, o la propia medición falló. Ninguna de las dos cosas es verde.
Ningún verde falso. El distintivo de saludable requiere una prueba medida de éxito; una clave que nunca se ha llamado nunca se pone en verde, porque ni una sola medición demuestra que funcione.
Ningún rojo falso. Las claves que cerraste a propósito aparecen como Cerrada. Pintarlo todo de rojo hace que el rojo no signifique nada; una clave cerrada solo se pone en rojo si se sigue llamando después del cierre, y entonces sí hay un puente realmente roto.
No poder medir no es lo mismo que no tener datos. Si una consulta falla en el servidor, la fila no muestra un cero en silencio; dice que no se pudo tomar la medición.
El silencio siempre se informa, pero nunca se convierte a ciegas en un aviso. Que un puente de cierre de mes se quede callado treinta horas es normal; que se calle un puente que habló al menos cinco de los últimos siete días es un fallo. El ritmo se mide, no se supone.
La propia consulta de estado no contamina los números de salud. Las llamadas que hace lg status aparecen en el registro de peticiones, pero se excluyen de los cálculos de salud; si no, tu propia consulta de estado correcta reiniciaría la racha de fallos y ocultaría justo el fallo que la pantalla existe para mostrar.
Cada línea está medida: se ejecuta una consulta real contra la base de datos, el catálogo de comandos se construye de verdad y el registro en vivo del worker de la cola se lee de verdad. No se supone nada.
La propia respuesta también es una medición: si puedes leer el cuerpo, la capa web está activa.
El nivel superior se deriva solo de los componentes obligatorios. Cuando la cola se detiene, la respuesta es degraded, no down: una llamada síncrona a la API no necesita la cola, y declarar caída la plataforma sería una falsa alarma.
Cuando el estado de la cola no se puede medir, el nivel superior se deja intacto: no saber no es lo mismo que medir que algo está roto.
Si la plataforma está caída, el endpoint devuelve HTTP 503. El cuerpo no lleva sobre para que las herramientas de monitorización puedan alertar sin analizarlo, y la respuesta nunca se guarda en ninguna caché.
Errores y códigos de salida
Aquello sobre lo que ramifica una máquina es una cadena estable. El texto del campo de error va dirigido a una persona, está localizado y cambia sin aviso: una integración que ramifica según el texto del mensaje no está soportada, y que se rompa no es un bug.
Dos taxonomías, dos campos. error_code es la capa de transporte (la tabla de arriba) y es sobre lo que ramificas primero. error_key es la clave estable de regla de negocio dentro de failed (INSUFFICIENT_CREDITS, NOT_FOUND, DUPLICATE_CONTACT, INSUFFICIENT_STOCK) y se publica como diccionario en el catálogo (error_keys) y más abajo. Un comando que todavía no emite una clave devuelve error_key: null; trata una clave que no esté en el diccionario como un fallo genérico.
ok — HTTP 200 · error_code — · CLI 0 · —
replayed — HTTP 200 · error_code — · CLI 0 · Repetición idempotente; el trabajo NO se volvió a ejecutar.
failed — HTTP 422 · error_code failed · CLI 1 · No: lo rechazó una regla de negocio (consulta error_key). No tiene sentido hasta que cambie el argumento.
idempotency_conflict — HTTP 409 · error_code idempotency_conflict · CLI 2 · No: la clave se usó primero para otro comando (conflicting_command). Genera una clave nueva.
forbidden — HTTP 403 · error_code forbidden · CLI 3 · No: control de rol, o una clave con alcance de lectura en un comando de escritura.
not_found — HTTP 404 · error_code not_found · CLI 2 · No: nombre de comando incorrecto o eliminado.
(esquema) — HTTP 422 · error_code invalid_request · CLI 2 · No: el cuerpo de la petición o un argumento no superó la validación del esquema (errors{}); no es una regla de negocio.
server_error — HTTP 500 · error_code server_error · CLI 6 · Sí: backoff exponencial con la MISMA clave de idempotencia; la clave no quedó bloqueada.
401 unauthenticated — El token caducó o fue revocado. Reintentar no servirá; hay que sustituir el token.
429 rate_limited — Límite de peticiones alcanzado para este token. La respuesta siempre lleva Retry-After y un cuerpo con retry_after, limit y bucket; respétalo en lugar de inventarte un retraso fijo. lg espera y reintenta hasta tres veces, y después termina con 5.
5xx server_error / error de red — Reintenta con backoff exponencial y la MISMA clave de idempotencia. Cambiar la clave vuelve a ejecutar un trabajo que el servidor quizá ya haya completado. lg reintenta tres veces (1 s, 2 s, 4 s) y después termina con 6 y error_code network_error o server_error.
Promesa de estabilidad
La pregunta más cara de un contrato de integración es «¿el código que escribo hoy seguirá funcionando mañana?». La responde un solo número: contract_version en el catálogo, y la cabecera X-Contract-Version en cada respuesta. Responde exactamente a una pregunta: ¿el código escrito antes sigue funcionando sin cambios? Si el número no ha subido, sí. Si ha subido, no: se eliminó o se restringió algo de lo que dependías.
Porque un anuncio no elimina nada: tu código existente funciona exactamente igual que antes, también al día siguiente. Subir la versión con el anuncio emitiría dos señales para un solo cambio y te enseñaría a ignorar la primera, debilitando la señal que de verdad importa. El anuncio ya viaja en la llamada que estás haciendo: deprecated_at y replaced_by en la fila del catálogo, una cabecera X-Deprecated más un bloque deprecated en la respuesta de ese comando, y un aviso de una línea en stderr si usas lg. No tienes que hacer nada para enterarte de que algo va a desaparecer; ya está en tu log.
Entre el anuncio y la eliminación pasan al menos dos trimestres naturales. Durante toda la ventana, el comando antiguo sigue respondiendo y avisa en cada llamada. Cuando se retira un nombre de la CLI, su sucesor adopta ese nombre como alias: durante la ventana, el nombre antiguo llega al comando antiguo, y el día en que se elimina, la misma llamada aterriza en el nuevo, sin que tengas que publicar una nueva versión del cliente.
preview_invoice → get_invoice (anunciada el 3 de septiembre de 2026). get_invoice devuelve el mismo bloque de vista previa y añade las líneas, el desglose de impuestos, los pagos registrados, el saldo pendiente y el acceso por tu propia clave de ERP (external_ref). preview_invoice sigue funcionando, igual que lg invoices preview; ambos avisan.
sin cambios — Un comando nuevo · un parámetro OPCIONAL nuevo · un campo de respuesta nuevo · una clave de error nueva · un endpoint nuevo — No hagas nada. Debes ignorar los campos que no conoces; un parser que falla ante un campo desconocido no es conforme.
sin cambios — Un ANUNCIO de obsolescencia: aviso de que un comando va a desaparecer — Tu código sigue funcionando. Pon una tarea en tu calendario: la ventana es de al menos 6 meses.
aumenta — Eliminar un comando · retirar un nombre antiguo de la CLI · quitar un campo de respuesta · hacer obligatorio un parámetro opcional · restringir un enum — Significa que se te pasó la ventana; el aviso te llegó por tres sitios distintos.
El nombre de API de un comando (como list_loads) está congelado para siempre; es el nombre que usas en las llamadas HTTP.
error_code (transporte) y error_key (regla de negocio) son cadenas estables. Pueden aparecer otras nuevas: trata una clave que no encuentres en el diccionario como un fallo genérico, no como una ruptura.
La correspondencia entre el estado HTTP y el campo status del cuerpo es fija.
El número de versión nunca baja y se puede leer en cada respuesta, incluidas las 304 y 429 sin cuerpo.
El TEXTO de los errores y las descripciones. Está localizado y cambia sin aviso; ramificar según el texto del mensaje no está soportado.
La ausencia de campos que no conoces. Añadir un campo no sube la versión.
Los ids autoincrementales como claves de negocio. Lleva tu propia clave con external_ref.
Las claves de error dinámicas derivadas de nombres de clase; no forman parte del contrato.
Tabla de identidad de comandos
La tabla de abajo no está escrita a mano: se genera a partir del registro de comandos en vivo cada vez que se sirve esta página. Un comando añadido en el servidor aparece aquí solo. La columna «Control» te dice si un comando pide confirmación y si su efecto se puede deshacer; la columna «Roles» te dice qué tipos de cuenta lo encontrarán en su catálogo. Los distintivos marcan los comandos que necesitan una clave de nivel manager, los que reciben un archivo y los que solo se ejecutan desde lg.
El nombre de API (list_loads) está congelado y no cambiará; es el nombre que usas en las llamadas HTTP. La identidad de la CLI (loads list) se rige por la política de versionado: una vez anunciada, solo cambia con una subida de versión y una ventana de migración, durante la cual el catálogo sirve el par antiguo como alias. Las descripciones de aquí salen del propio registro de cada comando y están acortadas; para el texto completo, los tipos de parámetro y los valores enum, lee el endpoint del catálogo o ejecuta lg help . Los comandos exclusivos de afiliados no se listan aquí; una cuenta de afiliado los ve en su propio catálogo.
lg account-settings get — Read the account settings (Settings → Account): the company display name (and legal name, read-only), the signed-in user's own name and e-mail (e-mail is read-only here), the saved load code prefix and how the company… (lectura · — · cargador · API: get_account_settings) [clave manager]
lg account-settings update — Change account settings (Settings → Account): company_name (the company's display name, company-wide), first_name / last_name (the signed-in user's own name — when only one is given the other part is kept),… (escritura · confirmación · cargador · API: update_account_settings) [clave manager]
lg accounting-settings get — Read the company's accounting and invoicing settings and say whether they are set up (muhasebe ayarları, fatura ayarları, e-fatura / e-invoice profile, KDV / VAT tax regime, fatura numaralandırma serisi / invoice… (lectura · — · todos · API: get_accounting_settings)
lg accounting-settings set-status — Turn the company's accounting module on or off (muhasebe modülünü aç/kapa). (escritura · confirmación · todos · API: set_accounting_module)
lg accounting-settings update — Update the company's accounting/invoicing settings (muhasebe ve fatura ayarlarını değiştir): legal name, default currency, provider (local/parasut), country, tax regime (KDV/VAT/GST/none), default invoice line… (escritura · confirmación · todos · API: update_accounting_settings)
lg addresses list — Loading and delivery addresses already used on this company's previous loads (newest first): address_id, name, street, city and country. query filters by name, street or city. limit 1-50 (default 20). (lectura · — · todos · API: list_worked_addresses)
lg addresses search — Find a place for a route plan stop: the company's own address book first, then a geocoder (counted against the daily routing allowance) when the book has fewer than 3 hits. (lectura · — · transportista · API: lookup_address)
lg ai-settings get — Read our company's AI switches (Settings → AI), e.g. ai_file_classify ("AI document analysis"): whether files posted into our load chats are read by AI, sorted into document types and split into company documents, or… (lectura · — · cargador · API: get_ai_settings) [clave manager]
lg ai-settings update — Turn our company's AI switches on or off (Settings → AI) — e.g. "stop AI from analysing the files in our load chats" → settings=[{"slug":"ai_file_classify","enabled":false}]. settings is a list of {slug, enabled}; slugs… (escritura · confirmación · cargador · API: update_ai_settings) [clave manager]
lg announcements list — Show the system announcements Logistivo sent to this user (new features, maintenance, policy changes) — newest first. (lectura · — · todos · API: list_announcements)
lg announcements mark-read — Mark system announcements as read for this user. (escritura · — · todos · API: mark_announcements_read)
lg attachments get — Read a file the user attached to THIS conversation (listed in the user message as [Attachments] with their attachment_uuid). (lectura · — · todos · API: read_attachment) [recibe un archivo: attachment_uuid]
lg background-jobs get — Check a background job that another command queued and returned a job_id for (document consistency re-analysis, file classification, tariff inquiry, tariff invoice reading, receipt pack…): status pending / running /… (lectura · — · todos · API: get_background_job)
lg bank-accounts create — Add one of YOUR OWN company bank accounts to the account book (the accounts you get paid into). (escritura · confirmación + irreversible · todos · API: create_company_bank_account) [clave manager]
lg bank-accounts delete — Delete one of OUR OWN company bank accounts (for example a closed account). (escritura · confirmación + irreversible · todos · API: delete_company_bank_account) [clave manager]
lg bank-accounts extract — Read a supplier's bank accounts (IBAN, bank, holder, currency) from one of ITS invoices and save them on that business contact. (escritura · confirmación + irreversible · todos · API: extract_supplier_bank_accounts) [recibe un archivo: attachment_uuid]
lg bank-accounts list — List bank accounts. (lectura · — · todos · API: list_bank_accounts)
lg bank-accounts preview — Check an IBAN without saving anything: is it valid (country, length, checksum) and which bank it belongs to (detected offline from the bank code where known). (lectura · — · todos · API: preview_bank_account_iban)
lg bank-accounts set-default — Make one of OUR OWN bank accounts the default — the IBAN printed on our invoices and e-invoices. (escritura · confirmación + irreversible · todos · API: set_default_company_bank_account) [clave manager]
lg bank-accounts set-status — Confirm or reject a bank account that was read from a document by AI or written by an integration — your own account or a business contact's account (find the ones waiting with list_bank_accounts… (escritura · confirmación + irreversible · todos · API: decide_bank_account_verification) [clave manager]
lg bank-accounts update — Update one of OUR OWN company bank accounts (the accounts customers pay us into): IBAN, bank, account holder, branch code, account number or currency. (escritura · confirmación + irreversible · todos · API: update_company_bank_account) [clave manager]
lg banks list — List the banks of Turkey with their bank_id and SWIFT/BIC code — the bank_id that create_company_bank_account and update_company_bank_account need. (lectura · — · todos · API: list_banks)
lg bids accept — Accept a carrier's bid on one of this company's demands. (escritura · confirmación + irreversible · cargador · API: accept_demand_bid)
lg bids calculate — Before bidding: what this carrier would earn and how many credits a bid would cost if the customer accepts it. (lectura · — · transportista · API: calculate_bid_earnings)
lg bids cancel — Withdraw (geri çek) one of THIS carrier company's PENDING bids. (escritura · confirmación + irreversible · transportista · API: cancel_demand_bid)
lg bids create — Submit a bid (teklif ver) on an open demand. amount_per_vehicle is the freight PER VEHICLE, not the total. (escritura · confirmación + irreversible · transportista · API: create_demand_bid)
lg bids get — Detail of ONE bid this carrier company submitted: demand, status (pending / accepted / revised / cancelled / price_too_high), price per vehicle and total, currency, vehicle count, customs included or customs price,… (lectura · — · transportista · API: get_my_demand_bid)
lg bids list — List the bids (teklif) THIS carrier company has submitted, newest first, with their outcome. (lectura · — · transportista · API: list_my_bids)
lg bids revise — Revise this carrier's own PENDING bid on a demand: the old bid is marked revised and a NEW bid replaces it (it gets a new bid code). (escritura · confirmación + irreversible · transportista · API: revise_demand_bid)
lg carbon-reports calculate — Calculate the CO2 emission of an EXISTING load (load_code: weight and route from the load, including its Ro-Ro leg) OR of a route you describe (transport_mode road|roro + weight_kg + departure_address + arrival_address,… (lectura · — · todos · API: calculate_load_carbon_emission)
lg carbon-reports download — Export ALL of the company's saved CO2 emission reports to one Excel file (one row per report: date, route, mode, weight, distance, emission, factor, method) and return a short-lived download link. (lectura · — · todos · API: export_carbon_emission_reports)
lg carbon-reports generate — Produce the signed CO2 emission report (PDF, with QR code) for a load OR for a route, save it to the company's report list and return a download link. (escritura · confirmación + irreversible · todos · API: generate_carbon_emission_report)
lg carbon-reports get — Read one CO2 emission report in full: total emission in kg, transport mode, weight, distance, emission factor, calculation method and source, the departure/arrival addresses, the leg breakdown for multi-modal routes… (lectura · — · todos · API: get_carbon_emission_report)
lg carbon-reports list — List the CO2 emission reports this company has generated (newest first): report number, file name, who created it and when. (lectura · — · todos · API: list_carbon_emission_reports)
lg carrier-routes get — This carrier's route definitions (Rota Yönetimi): the countries served — always ↔ Türkiye in both directions — and the vehicle types and load types operated, with ids and names. (lectura · — · transportista · API: get_carrier_routes)
lg carrier-routes set — REPLACE this carrier's route definitions (Rota Yönetimi) with the given FULL sets: countries served (each to/from Türkiye, both directions), vehicle types and load types. (escritura · confirmación · transportista · API: set_carrier_routes) [clave manager]
lg chart-of-accounts list — List the chart of accounts available to this company (Turkish uniform chart: 100 Kasa, 102 Bankalar, 120 Alıcılar, 320 Satıcılar, 391 Hesaplanan KDV, 600/601 Satışlar…), optionally filtered by code/name text or type. (lectura · — · todos · API: list_chart_of_accounts)
lg checks assign-invoices — Allocate a pending, field-confirmed cheque to one or more open LOCAL invoices of the same contact and currency: in = sales invoices (collection), out = purchase invoices (payment). (escritura · confirmación + irreversible · todos · API: attach_check_to_invoices) [clave manager]
lg checks bounce — Record that a cheque BOUNCED (came back unpaid). (escritura · confirmación + irreversible · todos · API: mark_check_bounced)
lg checks cancel — CANCEL a pending cheque (e.g. registered by mistake, returned before use): no journal entry is written and any invoice reservation is released. (escritura · confirmación + irreversible · todos · API: cancel_settlement_check) [clave manager]
lg checks collect — Record that a cheque was COLLECTED (money reached the bank for an incoming cheque, or left the bank for an outgoing one) on its due date. (escritura · confirmación + irreversible · todos · API: mark_check_collected)
lg checks create — Register a cheque in the cheque portfolio. (escritura · confirmación · todos · API: create_settlement_check) [clave manager] [recibe un archivo: front_attachment_uuid, back_attachment_uuid]
lg checks get — Read one cheque in full: its identity (number, serial, bank and branch, drawer with tax number, IBAN), the face amount and currency, issue and due dates, the counterparty, the status with every timestamp (executed,… (lectura · — · todos · API: get_settlement_check)
lg checks list — List the cheque portfolio of this company: cheque number, direction (in = received from a customer, out = given to a supplier), drawer and bank, face amount with its currency, issue and DUE date, the counterparty… (lectura · — · todos · API: list_settlement_checks)
lg checks remove-invoices — Release a pending cheque's invoice allocation: the reservations are removed (invoices become payable again) and the cheque goes back to the unallocated pending cheques. (escritura · confirmación · todos · API: detach_check_from_invoices) [clave manager]
lg checks run — EXECUTE a pending, allocated cheque against its invoices: the reservations become payments (the invoice balances close), and the notes receivable (121, received cheque) or notes payable (321, given cheque) journal… (escritura · confirmación + irreversible · todos · API: execute_settlement_check) [clave manager]
lg checks update — Correct a pending cheque's fields and CONFIRM them — the human sign-off on what AI read from the photo (or on a manual entry). (escritura · confirmación · todos · API: update_settlement_check) [clave manager]
lg companies add-role — Add a role to this company (firmaya rol ekle): customer (shipper), carrier, customs (customs broker) or affiliate. (escritura · confirmación + irreversible · todos · API: add_company_role) [clave manager]
lg companies delete-logo — Remove this company's logo (firma logosu) from the branded login portal, documents and the panel. (escritura · confirmación + irreversible · todos · API: delete_company_logo) [clave manager]
lg companies get — This company's own profile (firma profili): legal name, tax number and tax office, address and postal code, city/country, payment term (vade), the company roles it has (customer/carrier/customs/affiliate) and the roles… (lectura · — · todos · API: get_company_profile)
lg companies invite — Invite a company that is NOT on Logistivo yet by e-mail (e.g. a carrier we want to give a load to). (escritura · confirmación + irreversible · todos · API: invite_company_to_platform)
lg companies list — Logistivo platform companies this company has already worked with on loads (shared load chats), by company_type: customer (shippers), carrier or customs (customs brokers). (lectura · — · todos · API: list_platform_companies)
lg companies search — Check whether a company is on Logistivo — by EXACTLY ONE of: tax_number (exact VKN / tax id), vat_number (exact EU/UK VAT number) or email (any e-mail of that company, matched by its domain; then company_type is… (lectura · — · todos · API: search_platform_companies)
lg companies set-brand-colors — Set the two colours of this company's branded login portal (markalı giriş portalı, /p//login) — primary_color and secondary_color as #RRGGBB hex. (escritura · confirmación · transportista, agente de aduanas · API: set_company_brand_colors) [clave manager]
lg companies set-logo — Make an uploaded image this company's logo (firma logosu) — shown on the branded login portal, documents and the panel. attachment_uuid is a JPEG or PNG image (max 8 MB) uploaded to this conversation or with `lg upload`. (escritura · confirmación + irreversible · todos · API: set_company_logo) [clave manager] [recibe un archivo: attachment_uuid]
lg companies update — Update this company's profile (firma profili) — send ONLY the fields that change: legal_name (ticaret unvanı), tax_number (VKN / VAT id), tax_branch (vergi dairesi), address_street, postal_code, city_id, country_code… (escritura · confirmación · todos · API: update_company_profile) [clave manager]
lg company-documents create — File a document the user attached (in this chat, or uploaded to the command surface) as one of the company's own documents (firma evrakı yükle): tax certificate (vergi levhası), signature circulars (imza sirküleri),… (escritura · confirmación · todos · API: upload_company_document) [recibe un archivo: attachment_uuid]
lg company-documents delete — Remove one of the company's own documents (tax certificate, signature circular, trade registry gazette, permits…) from its document list — e.g. a wrong or outdated upload. document_id is the one shown by… (escritura · confirmación + irreversible · todos · API: delete_company_document)
lg company-documents list — List this company's own filed documents (tax certificate, signature circulars, trade registry gazette, contracts, TIO/L2 permits, files uploaded to chats…) with their type, number, validity date and verification status. (lectura · — · todos · API: list_company_documents)
lg company-documents list-missing — Which company documents (tax certificate, signature circulars, trade registry gazette, TIO/L2/C2 permits …) this company is REQUIRED to have for its company type and country, which of them are on file and verified, and… (lectura · — · todos · API: list_missing_company_documents)
lg company-domains create — Add an e-mail domain to our company (e.g. firma.com.tr) and e-mail a 6-digit verification code to a mailbox ON that domain. (escritura · confirmación + irreversible · todos · API: create_company_domain) [clave manager]
lg company-domains delete — Remove one of our UNVERIFIED company domains (e.g. added by mistake). (escritura · confirmación + irreversible · todos · API: delete_company_domain) [clave manager]
lg company-domains list — List our company's e-mail domains (Company settings → Domains): each row has company_domain_id, domain, verified (true once the 6-digit code was entered) and, for unverified ones, the mailbox the last code was sent to. (lectura · — · todos · API: list_company_domains)
lg company-domains resend — E-mail a NEW 6-digit verification code for one of our unverified company domains (the previous code stops working). (escritura · confirmación + irreversible · todos · API: resend_company_domain_code) [clave manager]
lg company-domains verify — Verify one of our unverified company domains with the 6-digit code that was e-mailed to the mailbox on that domain. (escritura · confirmación + irreversible · todos · API: verify_company_domain) [clave manager]
lg company-relationships accept — Accept a connection proposal another company sent us (relationship_id from list_company_relationships direction=incoming). (escritura · confirmación + irreversible · todos · API: accept_company_relationship) [clave manager]
lg company-relationships create — Send a connection proposal to link one of our business contacts with its company on the Logistivo platform (company_id from search_platform_companies). (escritura · confirmación + irreversible · todos · API: create_company_relationship) [clave manager]
lg company-relationships list — List our company connections on the platform (direction=outgoing, default: the connections in our directory, with status and roles such as carrier/customs_broker/supplier) or the connection proposals other companies… (lectura · — · todos · API: list_company_relationships)
lg company-relationships reject — Reject a connection proposal another company sent us (relationship_id from list_company_relationships direction=incoming). (escritura · confirmación + irreversible · todos · API: reject_company_relationship) [clave manager]
lg company-relationships revoke — End a company connection we are a party of (either side may end it), or withdraw a pending proposal. (escritura · confirmación + irreversible · todos · API: revoke_company_relationship) [clave manager]
lg contacts add-address — Add an address to a business contact (e.g. a warehouse or branch): a label, the full street address and the country (ISO-2 code); postal code optional. (escritura · confirmación · todos · API: add_business_contact_address)
lg contacts add-bank-account — Add a bank account (IBAN) to a business contact so it can be used on payment instructions and invoices. (escritura · confirmación + irreversible · todos · API: add_business_contact_bank_account)
lg contacts add-person — Add a person (yetkili kişi) to a business contact: first name, last name and e-mail are required; phone, phone country code, job title and a note are optional. (escritura · confirmación · todos · API: add_business_contact_person)
lg contacts archive — Archive a business contact (cariyi arşivle): it disappears from lists and pickers and becomes read-only, but nothing is deleted — invoices, loads and bank accounts stay linked, and restore_business_contact brings it… (escritura · confirmación · todos · API: archive_business_contact)
lg contacts create — Create a new business contact (cari) in the company directory. (escritura · confirmación · todos · API: create_business_contact)
lg contacts delete-address — Delete one of a business contact's addresses. (escritura · confirmación + irreversible · todos · API: delete_business_contact_address)
lg contacts delete-bank-account — Delete one of a business contact's bank accounts (for example an old or wrong IBAN). (escritura · confirmación + irreversible · todos · API: delete_business_contact_bank_account)
lg contacts delete-person — Delete a person from a business contact, together with that person's notification preferences. (escritura · confirmación + irreversible · todos · API: delete_business_contact_person)
lg contacts extract — Read a business card, letterhead or invoice header (image or PDF) and return the company details on it — legal name, tax number and office, VAT number, e-mail, phone, IBAN (checksum-checked, bank detected), address,… (lectura · — · todos · API: extract_business_contact_from_image) [recibe un archivo: attachment_uuid]
lg contacts extract-text — Read pasted text (Excel/CSV rows, e-mail signatures, a typed list) and return up to 100 draft records of ONE kind: companies, persons, addresses or bank_accounts. (lectura · — · todos · API: extract_business_contacts_from_text)
lg contacts get — Read one business contact in full (identity, tax data, address, e-mail/phone, bank accounts, platform link) together with its account summary: ledger balance (positive = they owe us), open receivables and open payables. (lectura · — · todos · API: get_business_contact)
lg contacts invite — Invite a business contact to join Logistivo by e-mail. (escritura · confirmación + irreversible · todos · API: invite_business_contact)
lg contacts list — List the company's business contacts (customers, carriers, suppliers, consignees) with optional text search over name, legal name and tax number. (lectura · — · todos · API: list_business_contacts)
lg contacts list-addresses — List the saved addresses of one business contact (label, street address, postal code, country) with address_id, needed by update/delete. (lectura · — · todos · API: list_business_contact_addresses)
lg contacts list-person-notifications — Show which load notifications a contact person receives and on which channel (e-mail, push, SMS), plus the notification types that can be chosen with their allowed channels — use those slugs with… (lectura · — · todos · API: list_business_contact_person_notifications)
lg contacts list-persons — List the people (yetkili kişiler) saved on one business contact: name, e-mail, phone, job title, note, and which load notifications each one receives. (lectura · — · todos · API: list_business_contact_persons)
lg contacts list-routes — Show which countries a business contact that is linked to a carrier on the platform serves: its declared route pairs (from-country → to-country) and the distinct country list. (lectura · — · todos · API: list_business_contact_routes)
lg contacts remove-company-link — Remove the link between a business contact and its company on the Logistivo platform. (escritura · confirmación + irreversible · todos · API: unlink_business_contact_company) [clave manager]
lg contacts restore — Bring an archived business contact back (cariyi arşivden geri al): it returns to lists and pickers and can be edited again. (escritura · confirmación · todos · API: restore_business_contact)
lg contacts search — Resolve a business contact (customer/partner/recipient) by name, legal name or tax number to its contact_id. (lectura · — · todos · API: lookup_business_contact)
lg contacts set-default-bank-account — Make one of a business contact's bank accounts its DEFAULT account — the one pre-selected when you pay this contact. (escritura · confirmación + irreversible · todos · API: set_default_business_contact_bank_account)
lg contacts set-person-notifications — Turn load notifications on or off for a contact person, per notification type and channel (e-mail, push, SMS). (escritura · confirmación · todos · API: set_business_contact_person_notifications)
lg contacts update — Update fields of an existing business contact. (escritura · confirmación · todos · API: update_business_contact)
lg contacts update-address — Correct one of a business contact's addresses. (escritura · confirmación · todos · API: update_business_contact_address)
lg contacts update-bank-account — Correct one of a business contact's bank accounts: IBAN, account holder, bank name, BIC/SWIFT, currency, label, account type, branch code or account number. (escritura · confirmación + irreversible · todos · API: update_business_contact_bank_account)
lg contacts update-person — Correct a contact person's details. (escritura · confirmación · todos · API: update_business_contact_person)
lg containers calculate — Decode and validate a container number (konteyner numarası) per ISO 6346 — owner code, category, serial, check digit (is it correct, and what it should be) and, when known, the operating line with its public tracking… (lectura · — · todos · API: decode_container_number)
lg conversations add-file — Post a file into an OFFER (demand-bid) chat as this user — e.g. a price sheet or a vehicle photo for the other company. conversation_code comes from list_conversations (rows whose subject is demand_bid). (escritura · confirmación + irreversible · todos · API: send_conversation_file) [recibe un archivo: attachment_uuid]
lg conversations add-invitation — Invite a person from ANOTHER company into a load chat by e-mail (sohbete dışarıdan davet). (escritura · confirmación + irreversible · todos · API: invite_to_conversation)
lg conversations add-message — Post a message into a load/bid conversation AS THIS USER (not as an assistant). (escritura · confirmación + irreversible · todos · API: send_conversation_message)
lg conversations add-participants — Add people to a load/demand conversation (sohbete kişi ekle) — "Ayşe'yi FKZ8515 sohbetine ekle". (escritura · confirmación · todos · API: add_conversation_participants)
lg conversations create — Open the freight chat with a carrier that bid on one of OUR demands (navlun sohbetini başlat) — bid_code comes from get_demand / the bids of a demand. (escritura · confirmación + irreversible · cargador · API: start_bid_conversation)
lg conversations list — List the chat conversations this user is a member of (load chats, bid chats and private carrier channels), newest activity first. (lectura · — · todos · API: list_conversations)
lg conversations list-files — List the files shared in a load/bid chat, newest first: document type, title, file name, who posted it and when. (lectura · — · todos · API: list_conversation_files)
lg conversations list-invitations — Show the e-mail invitations to a load chat that have not been accepted yet: who was invited, by whom and when, and what they will be allowed to see. (lectura · — · todos · API: list_conversation_invitations)
lg conversations list-messages — Read the most recent messages of one conversation — give it a load code (e.g. (lectura · — · todos · API: list_conversation_messages)
lg conversations list-participants — Who is in this conversation — name and company of every participant. (lectura · — · todos · API: list_conversation_participants)
lg conversations mark-read — Mark one conversation as read for this user (clears its unread badge), or with all=true every load, bid and direct-message chat at once. (escritura · — · todos · API: mark_conversation_read)
lg conversations remove-message — Delete one of THIS user's own messages from a conversation (message_id from list_conversation_messages with `mine` true). (escritura · confirmación + irreversible · todos · API: delete_conversation_message)
lg conversations remove-participant — Remove someone from a load/bid chat, cancel a pending e-mail invitation to it, or leave it yourself (give your own user_id). (escritura · confirmación + irreversible · todos · API: remove_conversation_participant)
lg conversations update-message — Edit one of THIS user's own messages in a conversation (message_id comes from list_conversation_messages, where `mine` is true). (escritura · confirmación · todos · API: update_conversation_message)
lg countries search — Resolve a country by name (Turkish, English or the local/native name) or ISO 3166-1 alpha-2 code to its country_id, for the sending/receiving country on a load. (lectura · — · todos · API: lookup_country)
lg currencies list — The currencies the platform knows (currency_id, code, name, symbol) with the latest exchange rate against the Turkish lira (buying / selling, rate date). currency_id is what forms such as bank accounts take. (lectura · — · todos · API: list_currencies)
lg custom-reports generate — Custom report counted server-side over ALL records of a dataset: filter, group (dates by month etc.), count/sum/avg/min/max (money per currency) or list rows; format=xlsx|pdf|csv gives a file. (lectura · — · todos · API: build_report)
lg customs-companies list — Customs broker companies this customer can assign when accepting a bid (accept_demand_bid customs_company_id): the Logistivo customs companies you already work with in your chats. (lectura · — · cargador · API: list_customs_companies)
lg customs-locations search — Search customs offices / customs locations (gümrük müdürlüğü, gümrük lokasyonu) by name or street — for the exit and destination customs of a load. (lectura · — · todos · API: lookup_customs_location)
lg demand-bid-reports get — Bid report across ALL demands at once, counted server-side: for a customer the bids RECEIVED on its demands, for a carrier the bids it PLACED. (lectura · — · cargador, transportista · API: get_demand_bid_report)
lg demand-reports get — Demand report (Talep Raporu) with optional filters: status, demanding company, transport mode, pickup / delivery countries, loading-date window. (lectura · — · cargador, transportista · API: get_demand_report)
lg demand-settings get — This carrier company's demand settings: whether demands opened by forwarder companies reach the company (accept_demands_from_forwarders). (lectura · — · transportista · API: get_demand_settings) [clave manager]
lg demand-settings update — Change this carrier company's demand settings. accept_demands_from_forwarders=false stops demands opened by forwarder companies from reaching the company (only shippers' demands remain); true lets them in again. (escritura · confirmación · transportista · API: update_demand_settings) [clave manager]
lg demand-targets search — Resolve a pickup/delivery location for a demand to a target token ("5-" = district/postal area, "10-" = seaport address). (lectura · — · cargador · API: lookup_demand_target)
lg demands create — Open a freight demand (talep) so carriers can bid. (escritura · confirmación + irreversible · cargador · API: create_demand) [recibe un archivo: attachment_uuids]
lg demands download — File for ONE demand owned by this company. export_type=details_pdf: the demand's detail sheet (route, dates, cargo, pallets) as PDF. export_type=sales_xlsx: the sales report workbook — demand information, every bid… (lectura · — · cargador · API: download_demand_export)
lg demands extract — Read a freight request text (an e-mail body, a note, a voice transcript) and return the demand fields it contains in the demand wizard's shape: transport mode, countries, ports, locations, dates, load type, vehicle… (lectura · — · cargador · API: extract_demand_from_text)
lg demands get — Detail of ONE freight demand. (lectura · — · cargador, transportista · API: get_demand)
lg demands list — List freight demands (talep) this carrier is allowed to bid on, newest first. (lectura · — · transportista · API: list_open_demands)
lg demands list-own — List the freight demands (talep) OWNED by this customer company, newest first, with route, dates, vehicles, status and bid count. (lectura · — · cargador · API: list_demands)
lg demands options — Reference lists needed to build a freight demand (talep) with create_demand: vehicle types (id, name, transport mode), payment maturity options (id + days; company_default_maturity_option_id is what the company normally… (lectura · — · cargador · API: get_demand_form_options)
lg demands set-status — Close (make passive) one of this company's ACTIVE demands so carriers stop bidding. (escritura · confirmación + irreversible · cargador · API: close_demand)
lg demands update — Edit one of this company's ACTIVE demands that has NO bids yet (a demand with bids or a closed one cannot be edited). (escritura · confirmación · cargador · API: update_demand) [recibe un archivo: attachment_uuids]
lg direct-conversations add-message — Send a direct message AS THIS USER (never as an assistant) — either into an existing chat (conversation_code from list_direct_conversations) or to one person (to_user_id from list_direct_message_contacts; their private… (escritura · confirmación + irreversible · todos · API: send_direct_message)
lg direct-conversations create — Start a direct chat. (escritura · confirmación + irreversible · todos · API: create_direct_conversation)
lg direct-conversations download — Produce the whole direct-message or group chat as a PDF (the same file as the panel's export button: participants and every message with date and time) and return a short-lived download link. (lectura · — · todos · API: export_direct_conversation_pdf)
lg direct-conversations list — List this user's direct-message (DM) chats and group chats — person-to-person messaging, separate from load/bid chats (those are list_conversations). (lectura · — · todos · API: list_direct_conversations)
lg direct-conversations list-contacts — List the people this user can direct-message: their own teammates plus people they share a load/bid chat with. (lectura · — · todos · API: list_direct_message_contacts)
lg direct-conversations list-messages — Read the latest messages of one direct-message or group chat (conversation_code from list_direct_conversations), oldest→newest, with who wrote them. `mine: true` marks this user's own messages; only those, and only… (lectura · — · todos · API: list_direct_conversation_messages)
lg direct-conversations mark-read — Mark one direct-message or group chat as read for this user (clears its unread badge). (escritura · — · todos · API: mark_direct_conversation_read)
lg direct-conversations remove-message — Delete one of THIS user's own direct messages (message_id from list_direct_conversation_messages, mine and editable true), only within 5 minutes of sending. (escritura · confirmación + irreversible · todos · API: delete_direct_message)
lg direct-conversations update — Rename a GROUP direct chat (private one-to-one chats have no title). (escritura · confirmación · todos · API: rename_direct_conversation)
lg direct-conversations update-message — Edit one of THIS user's own direct messages (message_id from list_direct_conversation_messages, where mine and editable are true). (escritura · confirmación · todos · API: update_direct_message)
lg document-checks run — Cross-check documents the user attached to THIS conversation against each other and report the discrepancies: mismatched party names, quantities, weights, amounts, dates, container or reference numbers between an… (escritura · — · todos · API: check_document_compliance) [recibe un archivo: attachment_uuids]
lg document-types list — List the platform's document types (slug and name) — the values document_type_slug accepts in upload_company_document, add_driver_document and the vehicle document commands. (lectura · — · todos · API: list_document_types)
lg documents download — Get a short-lived (15 minute) download/preview link for one document by its document_id (from list_load_documents or list_company_documents). (lectura · — · todos · API: get_document_link)
lg drive-rest-estimates get — One driver's GPS-ESTIMATED driving/rest status and driving time left under EU 561/2006 / AETR: current activity and since when, driving_left_today_s = the legal driving time left today under the daily, weekly (56 h) AND… (lectura · — · transportista · API: get_driver_drive_rest_estimate)
lg drive-rest-estimates list — Fleet overview of the GPS-ESTIMATED driving/rest status and driving time left (EU 561/2006 / AETR): per driver the current activity, driving_left_today_s = the legal driving time left today under the daily, weekly (56… (lectura · — · transportista · API: list_driver_drive_rest_estimates)
lg driver-accounts get — Answer "how much do we owe this driver / how much does the driver owe us". (lectura · — · cargador, transportista · API: get_driver_account_summary)
lg driver-accounts list-candidates — Before opening or filling a driver settlement statement: which of ONE driver's receipts and advances can go on it, and why the others cannot. (lectura · — · cargador, transportista · API: list_driver_account_candidates)
lg driver-advances cancel — Cancel (void) a recorded driver money movement that did not really happen or was entered with the wrong amount. (escritura · confirmación + irreversible · cargador, transportista · API: cancel_driver_advance)
lg driver-advances create — Record a money movement between the company and a driver: an advance handed to the driver, money the driver gave back, a closing payout, or a carry-forward opening balance. (escritura · confirmación · cargador, transportista · API: create_driver_advance) [recibe un archivo: attachment_uuid]
lg driver-advances delete — Delete a driver money movement that was entered by mistake (duplicate, wrong driver). (escritura · confirmación + irreversible · cargador, transportista · API: delete_driver_advance)
lg driver-advances list — List the money movements between the company and its drivers: cash advances handed out, money paid back by the driver, closing payouts and carry-forward opening balances. (lectura · — · cargador, transportista · API: list_driver_advances)
lg driver-advances update — Correct the non-money details of a recorded driver money movement: its reference, note, or the load it belongs to. (escritura · confirmación · cargador, transportista · API: update_driver_advance)
lg driver-availabilities create — Record that a driver is unavailable on some days — "Ali is on leave 14-20 November", "Mehmet rests at home next week", "Kemal is sick from today". (escritura · confirmación · transportista · API: create_driver_availability)
lg driver-availabilities delete — Delete ONE availability period (id from list_driver_availabilities) — the driver counts as available again on those days. (escritura · confirmación + irreversible · transportista · API: delete_driver_availability)
lg driver-availabilities list — List drivers' leave, home-rest, sick and other unavailability periods (newest planning input), optionally for one driver and/or a date window. (lectura · — · transportista · API: list_driver_availabilities)
lg driver-availabilities update — Correct one availability period (id from list_driver_availabilities): kind, dates, Schengen presence or note. (escritura · confirmación · transportista · API: update_driver_availability)
lg driver-expense-settings get — Read this company's driver expense module settings: is the module switched on, which currency receipts and advances are converted into, whether receipts need approval (and above which amount), whether drivers may… (lectura · — · cargador, transportista · API: get_driver_expense_settings)
lg driver-expense-settings update — Change this company's driver expense module settings — only the fields you pass change. (escritura · confirmación · cargador, transportista · API: update_driver_expense_settings) [clave manager]
lg driver-expenses create — File one or MANY expense receipts the user attached to this conversation (fuel, toll, ferry, parking, repair, meal…) into the driver expense ledger as pending expenses of ONE of this company's drivers. (escritura · confirmación + irreversible · cargador, transportista · API: process_receipt) [recibe un archivo: attachment_uuid, attachment_uuids]
lg driver-expenses declare — Record a driver expense WITHOUT a receipt (fişsiz şoför harcaması) — "Mehmet dün 40 EUR otopark ödedi, fişi yok", "log 120 PLN toll for driver X". (escritura · confirmación · cargador, transportista · API: create_driver_expense)
lg driver-expenses delete — Delete a driver expense entered by mistake (duplicate receipt, wrong driver, test entry). (escritura · confirmación + irreversible · cargador, transportista · API: delete_driver_expense)
lg driver-expenses download — Get the download link of a receipt pack that generate_driver_receipt_pack prepared in the background. (lectura · — · cargador, transportista · API: download_driver_receipt_pack)
lg driver-expenses generate — Produce ONE PDF that contains the driver receipts of a selection — for a trip, a load, a driver statement or a date window — e.g. to hand to accounting or the customer. (lectura · — · cargador, transportista · API: generate_driver_receipt_pack)
lg driver-expenses get — Read one driver expense (receipt) by its id: merchant, amount, currency, converted amount, category, payment channel, whether it is charged to the driver, and the approval status. (lectura · — · cargador, transportista · API: get_driver_expense)
lg driver-expenses list — List driver expense receipts (fuel, toll, ferry, parking, food, repair…) with a converted total. (lectura · — · cargador, transportista · API: list_driver_expenses)
lg driver-expenses list-loads — For ONE driver: which loads they carried and, per load, how many receipts there are, how many still await approval, how much is reimbursable to the driver, how much is company-billed (fuel card / DKV / UTA — never the… (lectura · — · cargador, transportista · API: list_driver_expense_loads)
lg driver-expenses list-trips — For ONE driver: which trips (load groups) they drove and, per trip, the number of loads and the driver's OWN receipt figures (count, awaiting approval, reimbursable, company-billed fuel-card / DKV / UTA, still… (lectura · — · cargador, transportista · API: list_driver_expense_trips)
lg driver-expenses review — Approve or reject ONE driver expense (receipt) from the chat, or send an already-decided one back to pending. status=approved means the company accepts the expense (an approved reimbursable receipt can then be counted… (escritura · confirmación · cargador, transportista · API: review_driver_expense)
lg driver-expenses set-in-account — Count driver receipts INTO the driver's account (include=true, default) or take them OUT of it (include=false). (escritura · confirmación · cargador, transportista · API: set_driver_expenses_in_account)
lg driver-expenses update — Correct a recorded driver expense (receipt or no-receipt): amount, currency, date, category, how it was paid, merchant, description or the load it belongs to — "the parking was 45 EUR not 40", "that fuel was paid with… (escritura · confirmación · cargador, transportista · API: update_driver_expense)
lg driver-expenses update-conversion — Retry the currency conversion of ONE driver receipt whose exchange rate could not be resolved (it then sits outside every total and cannot go into a driver statement). (escritura · — · cargador, transportista · API: retry_driver_expense_conversion)
lg driver-schedules accept — Apply ONE schedule suggestion (suggestion_id from get_driver_schedule): the proposed driver is assigned to the load (or every consignment of the trip — consignments still held by another driver are taken over, and the… (escritura · confirmación · transportista · API: apply_driver_schedule_suggestion)
lg driver-schedules generate — Compute schedule suggestions for a 7-90 day window starting within 30 days: which driver should take each unassigned load, trip and route plan so that nobody runs out of Schengen days, leave is respected and vehicles do… (escritura · confirmación · transportista · API: generate_driver_schedule)
lg driver-schedules get — Read one schedule run (schedule_id from generate_driver_schedule / list_driver_schedules): summary (jobs covered, unassignable jobs and why, vehicle idle days before → after, lowest Schengen margin), the suggestions in… (lectura · — · transportista · API: get_driver_schedule)
lg driver-schedules list — List the company's schedule-suggestion runs, newest first: id (schedule_id), status (queued | running | completed | failed), the planned window, objective and whether the run is out of date (is_stale — planning inputs… (lectura · — · transportista · API: list_driver_schedules)
lg driver-schedules reject — Dismiss ONE open schedule suggestion (suggestion_id from get_driver_schedule) so it is no longer offered; nothing is assigned or changed elsewhere. (escritura · — · transportista · API: dismiss_driver_schedule_suggestion)
lg driver-statements cancel — Cancel a statement that should not exist (opened by mistake, duplicated). (escritura · confirmación + irreversible · cargador, transportista · API: cancel_driver_account)
lg driver-statements create — Open a NEW draft settlement statement for a driver. (escritura · confirmación · cargador, transportista · API: create_driver_account)
lg driver-statements download — Give a short-lived download link to the PDF statement of a FINALISED driver settlement statement — the document the driver sees and signs, with every line, the fuel-card block that is outside the driver maths, and the… (lectura · — · cargador, transportista · API: download_driver_account_pdf)
lg driver-statements finalize — FINALISE a draft settlement statement — it freezes the document, makes it visible to the driver and (for settle_cash) writes the counter-entry into the advance ledger. (escritura · confirmación + irreversible · cargador, transportista · API: finalize_driver_account) [clave manager]
lg driver-statements get — Read one driver settlement statement in full: its status and revision, the driver, the currency, every total (expenses, advances, repayments, receiptless declarations), the NET balance with the sentence that says which… (lectura · — · cargador, transportista · API: get_driver_account)
lg driver-statements list — List the driver settlement statements (mutabakat belgesi) of this company: code, which driver, status (draft / finalized / cancelled), currency, the net balance and what it means, how many expense and advance lines it… (lectura · — · cargador, transportista · API: list_driver_accounts)
lg driver-statements reopen — Reopen a FINALISED statement so it can be corrected (a late receipt arrived, a line was wrong). (escritura · confirmación · cargador, transportista · API: reopen_driver_account) [clave manager]
lg driver-statements update — Change the note printed on a DRAFT driver settlement statement (e.g. "September trips, fuel excluded"). (escritura · confirmación · cargador, transportista · API: update_driver_account)
lg driver-statements update-lines — Attach receipts/advances to a DRAFT statement, or detach ones that should not be on it. (escritura · confirmación · cargador, transportista · API: update_driver_account_lines)
lg driver-statuses list — Fleet command centre — every driver's live operational status in one list: last position and its AGE, signal health (streaming / delayed / stale / no_signal / permission_denied / app_missing), duty (on_trip / assigned /… (lectura · — · cargador, transportista · API: list_fleet_driver_statuses)
lg drivers add-document — Record a driver paper — visa, passport, residence permit, driving licence, SRC certificate, psychotechnic certificate, travel health insurance — for ONE of this carrier's drivers, so its expiry is tracked. (escritura · confirmación · transportista · API: add_driver_document) [recibe un archivo: attachment_uuid]
lg drivers archive — Archive (deactivate) a driver: their account is disabled, open mobile sessions are revoked and the login link stops working. (escritura · confirmación + irreversible · transportista · API: archive_driver)
lg drivers calculate — Check whether ONE driver can take a job: Schengen 90/180 days left at the end of the trip (expected and worst case, counting the drive back out and the driver's later planned work), leave / home-rest / sick periods,… (lectura · — · transportista · API: check_driver_for_trip)
lg drivers create — Create a new driver account for this carrier company. (escritura · confirmación · transportista · API: create_driver)
lg drivers delete-document — Remove a driver paper from the driver's file. (escritura · confirmación + irreversible · transportista · API: delete_driver_document)
lg drivers get — Full detail of ONE driver of this carrier: identity, archive state, mobile app state, last GPS position, assigned load codes, ALL driver documents (passport, visa, licence, SRC… with expiry and days_to_expiry) and the… (lectura · — · transportista · API: get_driver)
lg drivers list — List this carrier company's drivers with their status, current country, expiring/expired document counts, assigned load codes and vehicle plates. (lectura · — · transportista · API: list_drivers)
lg drivers list-candidates — Rank the company's drivers for a job — which drivers are available and can do it (Schengen days at trip end incl. the drive back, leave/home-rest, other jobs, estimated driving/rest readiness, distance to the start)… (lectura · — · transportista · API: list_trip_driver_candidates)
lg drivers list-documents — List ONE driver's documents (passport, visa, residence permit, licence, SRC, ADR, health insurance…) with document number, issuing country, valid_until, days_to_expiry, is_expired and AI extraction status. (lectura · — · transportista · API: list_driver_documents)
lg drivers list-locations — A driver's GPS trail — the raw position pings from the driver app in a time window, oldest to newest, with the first and last timestamps and the point count. (lectura · — · transportista · API: list_driver_locations)
lg drivers login-link — Produce the driver's 48-hour mobile app login link (sensitive credential). (escritura · confirmación · transportista · API: get_driver_login_link)
lg drivers request-location — Ask a driver's phone for a fresh position ("where is Ahmet right now — ping him"). (escritura · — · transportista · API: request_driver_location)
lg drivers search — Resolve one of this company's drivers by name to its driver_id. (lectura · — · transportista · API: lookup_driver)
lg drivers update — Correct a driver's first/last name. (escritura · confirmación · transportista · API: update_driver)
lg drivers update-document — Correct a driver paper already on file — most often its expiry date (valid_until) after a renewal, but also the document number, the issuing country, the type or the note. (escritura · confirmación · transportista · API: update_driver_document)
lg drivers update-login-link — Generate a NEW 48-hour mobile login link for a driver and kill the old one (lost phone, expired or leaked link). (escritura · confirmación + irreversible · transportista · API: refresh_driver_login_link)
lg equipment-damages create — Open a damage record on one of the company's own vehicles or trailers (dorse hasar kaydı aç) — "33ABC12 dorsesinin sol arka kapısında ezik var", "record a scratch on the rear bumper of the truck". (escritura · confirmación · todos · API: create_equipment_damage)
lg equipment-damages delete — Delete a damage record that was opened by mistake (a duplicate, the wrong vehicle). (escritura · confirmación + irreversible · todos · API: delete_equipment_damage)
lg equipment-damages generate — Produce the equipment damage ledger as an Excel file (the same file as the panel's export button) and return a short-lived download link — e.g. "give me this year's open trailer damages as Excel". (lectura · — · todos · API: export_equipment_damages)
lg equipment-damages list — List the equipment/trailer damages recorded for this company: which vehicle, where on it (area and angle), damage type and severity, whether it is still open or repaired, the estimated and actual repair cost, who is… (lectura · — · todos · API: list_equipment_damages)
lg equipment-damages update — Update an existing damage record: mark it repaired (with repair date, cost and note), dismissed or disputed, change severity/type/area/description, set the estimated cost, or set/clear the responsible driver. (escritura · confirmación · todos · API: update_equipment_damage)
lg equipment-inspection-links create — Create a one-time link so a driver or agent who is NOT on the platform (port agent, another company's driver) can upload the hand-over photos of one of the company's trailers/vehicles from a phone, without an account. (escritura · confirmación · todos · API: create_equipment_inspection_link)
lg equipment-inspections create — Record an equipment hand-over inspection of one of the company's own trailers or vehicles on behalf of a driver or the office — "record the pickup inspection of trailer 34ABC12 with these 4 photos, driver Ali".… (escritura · confirmación · todos · API: create_equipment_inspection) [recibe un archivo: photos[].attachment_uuid]
lg equipment-inspections delete — Delete an equipment inspection that was recorded by mistake (wrong vehicle, duplicate), together with its photos. (escritura · confirmación + irreversible · todos · API: delete_equipment_inspection)
lg equipment-inspections get — Full detail of ONE equipment hand-over inspection: vehicle, event (pickup / dropoff / interim), who did it and where and when, the AI analysis status with its overall condition and summary, the damages that inspection… (lectura · — · todos · API: get_equipment_inspection)
lg equipment-inspections list — List the equipment hand-over inspections (teslim-tesellüm controls) of this company: which vehicle, the event type (hand-over, take-over, interim), when and where it happened, who performed it (driver or office user, or… (lectura · — · todos · API: list_equipment_inspections)
lg equipment-inspections run — Run the AI damage analysis again on the photos of one equipment inspection (for example after the analysis failed, or photos were added later). (escritura · confirmación · todos · API: reanalyze_equipment_inspection)
lg equipment-settings get — Read the company's equipment inspection settings: whether the module is on, at which hand-overs an inspection is required (pickup / dropoff), whether photos are required, the minimum photo count, which angles are… (lectura · — · todos · API: get_equipment_settings)
lg equipment-settings update — Change the company's equipment inspection settings — e.g. "turn on equipment inspection and require at least 4 photos with front, rear, left and right at pickup". (escritura · confirmación · todos · API: update_equipment_settings) [clave manager]
lg equipment-timelines get — Who has one trailer/vehicle right now (custody: in custody of a driver since the last pickup, or released at the last dropoff), the inspections it went through (newest first) and its OPEN damages — in one read. (lectura · — · todos · API: get_equipment_timeline)
lg export-documents add-item — Append a line item to an export document. (escritura · — · todos · API: add_export_document_item)
lg export-documents create — Create a new export document draft. (escritura · — · todos · API: create_export_document_draft)
lg export-documents create-set — Create SEVERAL export document drafts (a set, e.g. commercial invoice + packing list) from ONE source in one go: the source is read once by AI and every chosen document is filled from it. (escritura · — · todos · API: create_export_document_set) [recibe un archivo: attachment_uuid]
lg export-documents delete — Delete one export document of this company (draft or generated). (escritura · confirmación + irreversible · todos · API: delete_export_document)
lg export-documents duplicate — Copy an existing export document into a NEW draft of the same type (same parties, items and terms; no document number, not generated). (escritura · — · todos · API: duplicate_export_document)
lg export-documents extract — Read a pasted order e-mail, offer or confirmation — or an Excel/CSV/TXT item list given as attachment_uuid — and fill an export document from it. (escritura · — · todos · API: extract_export_document_from_text) [recibe un archivo: attachment_uuid]
lg export-documents generate — Produce the final PDF of an export document AND return a short-lived signed download link for it, so the user gets the file straight from the chat. (escritura · confirmación + irreversible · todos · API: generate_export_document)
lg export-documents generate-set — Generate several export documents as PDFs in one go and return a short-lived download link for each generated one. (escritura · confirmación + irreversible · todos · API: generate_export_document_set)
lg export-documents get — Read one export document in full: every filled field as dot-paths, the line items with their 1-based positions, the server-computed totals and which required fields are still empty. (lectura · — · todos · API: get_export_document)
lg export-documents list — List the export documents of the current company (proforma invoice, commercial invoice, packing list, shipping instruction, delivery note, certificate/movement applications, exporter declaration, insurance request). (lectura · — · todos · API: list_export_documents)
lg export-documents options — List the export document types and the ready-made document sets with their credit cost. (lectura · — · todos · API: get_export_document_options)
lg export-documents preview — Before generating several export documents as PDFs, show what it would cost: which documents would spend a credit, which are free (already generated), the total, the remaining balance and the required fields still empty… (lectura · — · todos · API: plan_export_document_generation)
lg export-documents remove-item — Delete one line item by its 1-based position. (escritura · — · todos · API: remove_export_document_item)
lg export-documents set — Set one or more fields on an export document draft. (escritura · — · todos · API: set_export_document_fields)
lg export-documents update-item — Change columns of one existing line item, addressed by its 1-based position from get_export_document. (escritura · — · todos · API: update_export_document_item)
lg finance calculate — Build a budget / financial forecast (bütçe tahmini, gelecek yıl bütçesi, nakit/ciro projeksiyonu) from the company's MEASURED history, month by month. (lectura · — · todos · API: generate_budget_forecast)
lg finance get — One call that returns the measured financial BASE for a period — the numbers a budget, a forecast, a business plan, a cash-flow projection or a board summary is built on, instead of chaining six separate reads. (lectura · — · todos · API: get_financial_snapshot)
lg fleet-documents list — List fleet documents that expire soon (or already expired): vehicle papers (insurance, inspection, permits) and — for carriers — driver papers (passport, visa, licence, SRC). (lectura · — · cargador, transportista · API: list_expiring_documents)
lg freight-invoices archive — Archive (remove from the active list) a freight invoice YOUR company uploaded — e.g. a duplicate or the wrong file. (escritura · confirmación + irreversible · todos · API: archive_freight_invoice)
lg freight-invoices create — Attach 1-20 freight invoices (navlun faturası) to a load. (escritura · confirmación · todos · API: upload_freight_invoices) [recibe un archivo: attachment_uuids]
lg freight-invoices list — List the freight invoices (navlun faturaları) of a load that your company is a party to: who uploaded it, amount and currency, invoice date, the AI reading status, and which load parties it is shared with. (lectura · — · todos · API: list_freight_invoices)
lg freight-invoices set-visibility — Choose which load parties can see a freight invoice YOUR company uploaded — e.g. "share the invoice with the receiver too", "only we should see it". (escritura · confirmación · todos · API: set_freight_invoice_visibility)
lg freight-reports get — Freight (navlun) cost report over the loads this company can see: agreed freight totals per currency plus the EUR equivalent, freight-invoice totals, how many loads have NO freight recorded (listed by code), a breakdown… (lectura · — · cargador, transportista · API: get_freight_cost_report)
lg fuel-cards create — Register a fuel card (DKV, UTA and the like) in the fleet card book, optionally tied to a driver or a vehicle. (escritura · confirmación · cargador, transportista · API: create_fuel_card)
lg fuel-cards delete — Delete a fuel / toll card (DKV, UTA, Shell…) that was entered BY MISTAKE. (escritura · confirmación + irreversible · cargador, transportista · API: delete_fuel_card)
lg fuel-cards list — List the company's fuel and toll cards (DKV, UTA, Eurowag, E100, Shell, OMV, Aral, Petrol Ofisi, Opet…) with the last four digits, the driver or vehicle they are tied to, and whether they are active. (lectura · — · cargador, transportista · API: list_fuel_cards)
lg fuel-cards update — Update a fuel card: move it to another driver or vehicle, change its label or note, or DEACTIVATE it (is_active false) when the card is cancelled. (escritura · confirmación · cargador, transportista · API: update_fuel_card)
lg handoff-links generate — Get the logistivo.com link for work that deliberately stays in the browser: package_purchase (buy or upgrade a package; optional package_slug from list_packages and billing_period monthly|yearly pre-select it — the… (lectura · — · todos · API: get_browser_handoff_link)
lg import-duties get — Read the Turkish import duty table for one GTİP code: customs duty (İthalat Rejimi Kararı) and additional customs duty / İGV, with every country-group column, plus the statutory duty from the nomenclature. (lectura · — · todos · API: get_import_duty_rates)
lg integration-keys list — List the company's integration (API) keys: name, uuid, which teammate it acts as, scope (read/write) and allowed domains, access level (manager/employee), environment (live/sandbox), status (active/revoked/expired),… (lectura · — · todos · API: list_integration_keys) [clave manager]
lg integration-keys revoke — Revoke one of the company's integration (API) keys by its uuid from list_integration_keys: the key stops working immediately and cannot be re-enabled (issue a new key instead). (escritura · confirmación + irreversible · todos · API: revoke_integration_key) [clave manager]
lg invitations create — Invite colleagues to this company by e-mail — one address in email, or up to 20 at once in emails (all-or-nothing: the seat limit and every address's domain are checked before anything is sent). (escritura · confirmación + irreversible · todos · API: invite_teammate) [clave manager]
lg invitations list — List teammate invitations of this company that are not completed yet (pending / e-mail verified / account created), with invitation_code, e-mail, role and expiry. (lectura · — · todos · API: list_pending_invitations)
lg invitations resend — Re-send a pending teammate invitation e-mail and extend its expiry by 14 days. (escritura · confirmación + irreversible · todos · API: resend_invitation) [clave manager]
lg invitations revoke — Cancel a pending teammate invitation so its link stops working (it can later be re-sent). (escritura · confirmación · todos · API: revoke_invitation) [clave manager]
lg invoice-settings get — Read the invoice document settings (fatura ayarları, fatura şablonu ayarları): which invoice templates exist, which template configuration is the company default, which fields of it are filled (logo, seller address,… (lectura · — · todos · API: get_invoice_settings)
lg invoice-templates create — Create a new invoice template configuration for your company: a base template plus field values (colours, font, header / footer text, IBANs shown, QR code, language; logo and signature from uploaded images). (escritura · confirmación + irreversible · todos · API: create_invoice_template) [clave manager] [recibe un archivo: logo_attachment_uuid, signature_image_attachment_uuid]
lg invoice-templates delete — Delete one of your invoice template configurations. (escritura · confirmación + irreversible · todos · API: delete_invoice_template) [clave manager]
lg invoice-templates get — Show the fillable fields of an invoice template (logo, colours, font, header / footer text, IBANs shown, QR code, signature, language) with their types, options and defaults — and, for one of your configurations, its… (lectura · — · todos · API: get_invoice_template)
lg invoice-templates set-default — Make one of your invoice template configurations the company default; the previous default stops being default. (escritura · confirmación · todos · API: set_default_invoice_template) [clave manager]
lg invoice-templates update — Edit one of your invoice template configurations: switch its base template, rename it, change field values (merged over the stored ones — only the keys you pass change), replace the logo / signature image, or make it… (escritura · confirmación + irreversible · todos · API: update_invoice_template) [clave manager] [recibe un archivo: logo_attachment_uuid, signature_image_attachment_uuid]
lg invoices add-line — Add a line item to a DRAFT invoice and recompute totals (tax auto-resolved if tax_rate_id omitted). (escritura · — · todos · API: add_invoice_line)
lg invoices add-payment — Record money received (sales invoice) or paid (purchase invoice) against ONE issued invoice: writes the payment, posts the balanced journal entry and reduces the remaining balance. (escritura · confirmación + irreversible · todos · API: record_invoice_payment)
lg invoices cancel — Cancel an ISSUED invoice this company issued: posts the reversing journal entry and marks the invoice cancelled. (escritura · confirmación + irreversible · todos · API: cancel_invoice)
lg invoices create — Create a DRAFT invoice (reversible) issued by the current company to a recipient business contact. (escritura · — · todos · API: create_invoice_draft)
lg invoices delete-draft — Delete a DRAFT invoice of this company together with its lines and taxes. (escritura · confirmación + irreversible · todos · API: delete_invoice_draft)
lg invoices download — Get a short-lived download link for the PDF of an invoice visible to this company (and the e-invoice XML when one exists). (lectura · — · todos · API: download_invoice_pdf)
lg invoices get — Read one invoice in full: parties, load link, dates, every line with tax, tax breakdown, totals, remaining balance and the payments recorded against it. (lectura · — · todos · API: get_invoice)
lg invoices issue — Issue (finalize) a DRAFT invoice: assigns a number and posts accounting entries. (escritura · confirmación + irreversible · todos · API: issue_invoice)
lg invoices list — List invoices visible to this company — the ones it issued and the ones issued to it (as a linked party). (lectura · — · todos · API: list_invoices)
lg invoices preview — Show the user a full preview of a DRAFT invoice (recipient, line items, tax breakdown, totals) WITHOUT issuing it. (lectura · — · todos · API: preview_invoice · obsoleto: 2026-09-03 · usa get_invoice)
lg invoices remove-line — Remove one line from a DRAFT invoice your company issued; the totals are recalculated. (escritura · confirmación · todos · API: remove_invoice_line)
lg invoices reverse-payment — Undo ONE payment/collection recorded on an invoice: posts the reversing journal entry, gives the amount back to the invoice's remaining balance and removes the payment row. (escritura · confirmación + irreversible · todos · API: reverse_invoice_payment)
lg invoices update — Edit the header of a DRAFT invoice your company issued: recipient contact, currency, issue / due date, the printed note and the invoice template. (escritura · — · todos · API: update_invoice_draft)
lg invoices update-line — Edit one line of a DRAFT invoice your company issued (text, quantity, unit, net unit price, discount, tax rate, order). (escritura · — · todos · API: update_invoice_line)
lg join-requests approve — Approve a pending join request: the applicant becomes a user of our company with the EMPLOYEE role, takes one team seat and is e-mailed the decision. (escritura · confirmación + irreversible · todos · API: approve_join_request) [clave manager]
lg join-requests list — List PENDING requests from people asking to join our company (they signed up with an e-mail on one of our verified domains and picked our company). (lectura · — · todos · API: list_join_requests) [clave manager]
lg join-requests reject — Reject a pending join request: the applicant does not join our company and is e-mailed the decision. (escritura · confirmación + irreversible · todos · API: reject_join_request) [clave manager]
lg journal-entries create — Post a manual double-entry journal entry (yevmiye fişi). (escritura · confirmación + irreversible · todos · API: create_journal_entry)
lg journal-entries get — Read one journal entry with its lines (account code/name, debit, credit, counterparty) and totals. (lectura · — · todos · API: get_journal_entry)
lg journal-entries list — List journal entries (yevmiye fişleri) of the company, newest first, with optional date window. (lectura · — · todos · API: list_journal_entries)
lg language-settings get — Read the signed-in user's own language settings (dil ayarları). (lectura · — · todos · API: get_language_settings)
lg language-settings update — Change the signed-in user's OWN language settings — "dilimi İngilizce yap", "e-postalarım Türkçe gelsin", "sohbet mesajlarını Almancaya çevir". (escritura · — · todos · API: set_language)
lg load-ai-settings get — Read our company's load AI reminder setting (Settings → Loads): whether the assistant posts reminders into load chats about loads whose status was not updated (ai_warning_enabled) and on which days (warning_frequency:… (lectura · — · todos · API: get_load_ai_settings)
lg load-ai-settings update — Change our company's load AI reminders (Settings → Loads): ai_warning_enabled turns the reminders the assistant posts into load chats on or off; warning_frequency picks the days (daily, mon_wed_fri, weekly_wed,… (escritura · confirmación · todos · API: update_load_ai_settings) [clave manager]
lg load-containers create — Add a sea container number to a load (yüke konteyner ekle) — "add MSC container MSCU1234565 to FKZ8515". (escritura · confirmación · cargador, transportista · API: add_load_container)
lg load-containers delete — Delete a container record from a load (konteyneri sil) — only while its vessel tracking has NOT started (otherwise refused with INVALID_STATUS). (escritura · confirmación + irreversible · todos · API: delete_load_container)
lg load-containers get — Show one container of a load and the last known position of the ship carrying it (konteyner konumu): ship name/IMO, latitude/longitude, speed, course, destination, ETA and the position time. (lectura · — · todos · API: get_load_container)
lg load-containers list — List the sea containers recorded on a load (konteynerler) with their shipping line, whether vessel tracking has started and which ship carries them. (lectura · — · todos · API: list_load_containers)
lg load-containers set-tracking — Start vessel tracking for a load from its containers (konteyner takibini başlat): the shipping line is queried for each container until the vessel carrying it is found; that ship is then tracked on the load's map and… (escritura · confirmación · todos · API: start_load_container_tracking)
lg load-documents create — File one or MANY documents the user attached to this conversation onto a load: each file is stored as a company document and posted into the load's chat, where every participant (customer, carrier, customs broker) sees… (escritura · confirmación + irreversible · todos · API: attach_chat_file_to_load) [recibe un archivo: attachment_uuid, attachment_uuids]
lg load-documents list — List the documents (CMR, invoice, packing list, customs papers, photos…) filed on a load — i.e. the files shared in that load's chat. (lectura · — · todos · API: list_load_documents)
lg load-groups add-loads — Merge EXISTING loads into a groupage trip you own as consignments (they keep their own code, chat, documents and participants; only the trip membership changes — nothing is duplicated and NO credit is used). (escritura · confirmación · cargador, transportista · API: add_loads_to_group)
lg load-groups create — Create a groupage trip (parsiyel/sefer): ONE truck carrying several ISOLATED consignments; each consignment is its own load with its own chat/documents/status and receivers never see each other. (escritura · confirmación + irreversible · cargador, transportista · API: create_load_group)
lg load-groups download — Download the route report of a groupage trip (sefer / parsiyel, code like LGV00253): route_pdf = detailed route report with map and itinerary, route_xlsx = the same as Excel, driver_sheet_pdf = the simplified driver… (escritura · — · cargador, transportista · API: download_load_group_report)
lg load-groups get — Detail of one groupage trip: consignments visible to you (load code, status, receiver, route, driver), planned date, optimised master route summary and stop count. (lectura · — · cargador, transportista · API: get_load_group)
lg load-groups list — List groupage trips (parsiyel / sefer: one truck, several isolated consignment loads) this company owns or — for carriers — carries, newest first, with visible consignment count and route optimisation state. (lectura · — · cargador, transportista · API: list_load_groups)
lg load-groups optimize — Re-optimise the master route of a groupage trip you own and RETURN the new itinerary: the ordered stops (pickup → export customs → import customs → dropoff), each stop's address and consignment codes, the total distance… (escritura · — · cargador, transportista · API: optimize_trip_route)
lg load-groups remove-load — Take one consignment out of a groupage trip you own. (escritura · confirmación · cargador, transportista · API: remove_load_from_group)
lg load-heatmaps generate — Produce the load heatmap report (PDF, with QR code and the list of your active loads: code, departure, arrival, date, weight), save it to the company's reports and return a download link. (escritura · confirmación + irreversible · todos · API: generate_load_heatmap_report)
lg load-heatmaps get — Load heatmap data in words: the densest departure and arrival areas of your active loads, ranked by number of loads and by total kilograms. (lectura · — · todos · API: get_load_heatmap)
lg load-locations create — Report a position for a load on behalf of the carrier (konum bildir) — "FKZ8515 is at Kapıkule now", "the truck is at 41.0, 28.9". (escritura · confirmación + irreversible · transportista · API: report_load_location)
lg load-locations list — Show a load's position history (konum geçmişi) and its last known position — "where is FKZ8515 now", "where was it yesterday", "show the truck's track". (lectura · — · todos · API: list_load_locations)
lg load-locations list-routes — Show the road route segments drawn on a load's tracking map (rota parçaları), each with distance (metres) and duration (seconds): from the pickup address to the first reported position, between reported positions, and… (lectura · — · todos · API: list_load_route_segments)
lg load-notifications list-recipients — Show which load parties can receive a load notification (departure, arrival, daily location) and how many of their people are subscribed per channel (e-mail, push, SMS). (lectura · — · todos · API: list_load_notification_recipients)
lg load-notifications send — Send a departure / arrival / daily-location notification about a load to chosen load parties — e.g. "notify the receiver that FRT6470 arrived". (escritura · confirmación + irreversible · todos · API: send_load_notification)
lg load-notifications send-email — E-mail a departure / arrival / location update about a load to people you choose from YOUR OWN company directory (business contact persons) — e.g. "e-mail Mehmet at Arkas the location of FKZ8515". (escritura · confirmación + irreversible · todos · API: send_load_email_notification)
lg load-participants create — Add a party to a load (yüke taraf ekle) — "FKZ8515'e Arkas'ı alıcı olarak ekle" — or assign a sub-carrier. business_contact_id comes from lookup_business_contact (your own directory). (escritura · confirmación · todos · API: add_load_participant)
lg load-participants delete — Remove a party or a sub-carrier from a load (yükten taraf çıkar) — "FKZ8515'ten alt taşıyıcı Yılmaz Nakliyat'ı kaldır". participant_id comes from list_load_participants. (escritura · confirmación · todos · API: remove_load_participant)
lg load-participants list — List a load's parties (yük tarafları): sender, receiver, carrier and sub-carriers, organizer, sender/receiver customs brokers — with participant_id (needed by every other load-participant command), position (0 = primary… (lectura · — · todos · API: list_load_participants)
lg load-participants set-order — Put the parties of one role in a new order (load owner only); the first id becomes the primary. participant_ids must list ALL current rows of that role (from list_load_participants). (escritura · confirmación · todos · API: reorder_load_participants)
lg load-participants set-primary — Make a party the primary one in its role (load owner only) — e.g. the main receiver or main customs broker. participant_id from list_load_participants. (escritura · confirmación · todos · API: set_primary_load_participant)
lg load-participants update — Change one load party's settings (load owner only) — "Arkas FKZ8515'i görmesin": share_with_assigned_company (can the linked company see the load; cannot be turned off for a sub-carrier), conversation_user_ids (only… (escritura · confirmación · todos · API: update_load_participant)
lg load-party-suggestions approve — Accept a party suggestion: link the suggested business contact to your OWN load as sender or receiver (business_contact_id and party_role from list_load_party_suggestions). (escritura · confirmación · todos · API: confirm_load_party_suggestion)
lg load-party-suggestions list — Show sender/receiver suggestions for one of your OWN loads: parties named in the load's documents that match a contact in your directory but are not linked to the load yet. (lectura · — · todos · API: list_load_party_suggestions)
lg load-party-suggestions reject — Close wrong party suggestions on your OWN load so they are not suggested again — "bu önerileri bir daha gösterme". (escritura · — · todos · API: dismiss_load_party_suggestions)
lg load-reports get — Build a report of your ACTIVE loads, optionally filtered by sender, receiver, transport mode, departure country or arrival country. format=summary (default) answers in chat: the number of loads and how many are in each… (lectura · — · todos · API: get_load_report)
lg load-reports options — List the companies you can filter the load report by — the senders, receivers, carriers and other parties that appear on your active loads — with their company id and role. (lectura · — · todos · API: get_load_report_options)
lg load-types search — Resolve a load/transport type (e.g. (lectura · — · todos · API: lookup_load_type)
lg load-vehicles delete — Detach the fleet equipment from a load: both slots by default, or only the tractor unit / only the trailer. (escritura · confirmación · todos · API: clear_load_equipment)
lg load-vehicles get — Show which tractor unit (or truck/van) and which trailer are attached to a load, whether they belong to your own fleet, and whether the load can still be changed. (lectura · — · todos · API: get_load_equipment)
lg load-vehicles set — Attach one of your own fleet vehicles to a load: the tractor unit / truck slot (plate) and/or the trailer slot (trailer_plate). (escritura · confirmación · todos · API: assign_vehicle_to_load)
lg loads add-order-reference — Attach an order reference to a load (sipariş referansı ekle) — "FKZ8515'e satın alma siparişi PO-4471 ekle". order_type is the kind of order (e.g. purchase, sales), order_no the number. (escritura · confirmación + irreversible · todos · API: add_load_order_reference)
lg loads analyze-documents — Re-run the background AI consistency analysis of a load's documents (does the invoice contradict the CMR, the packing list, the declared weight…) and refresh the load's problem flag with the outcome. (escritura · — · todos · API: reanalyze_load_documents)
lg loads archive — Archive one of the company's OWN loads (yükü arşivle) — "FKZ8515'i arşive al". (escritura · confirmación + irreversible · todos · API: archive_load)
lg loads assign-driver — Assign one of this company's drivers to a load so the driver sees it in the mobile app and starts reporting position. (escritura · confirmación · transportista · API: assign_driver_to_load)
lg loads audit-documents — Cross-check the documents already attached to loads and report, PER LOAD, whether their package counts and gross weights agree. (lectura · — · todos · API: audit_load_documents)
lg loads close-problem — Close the open document-consistency flag of ONE load, from the chat. action=resolved means the contradiction was actually fixed (a corrected document was uploaded); action=dismissed means it was a false alarm and should… (escritura · confirmación · todos · API: resolve_load_problem_flag)
lg loads create — Open a freight load (yük). (escritura · confirmación + irreversible · todos · API: create_load)
lg loads download — Generate a load's CMR consignment note as a PDF and return a short-lived download link — "FKZ8515'in CMR'ını ver". (lectura · — · todos · API: download_load_cmr)
lg loads extract — Read a booking/order text (an e-mail body, a note, an ERP export line) and return the load fields it contains, in the quick-load form's shape: transport mode, countries, dates, load type, vehicle type, weight, goods… (lectura · — · cargador · API: extract_load_from_text)
lg loads get — Read one load in full by its code: route, dates, weight, current status, parties (sender/receiver/carrier), agreed freight (freight_amount + freight_currency) with its freight invoices (number, date, total), latest… (lectura · — · todos · API: get_load)
lg loads list — List the freight loads (yük) this company can see, newest first. (lectura · — · todos · API: list_loads)
lg loads list-associated — List the loads of the same multi-vehicle order as a given load (aynı siparişin diğer araçları) — every active load that shares its vehicle group code (LG…) and that your company can see, with status, date and carrier. (lectura · — · todos · API: list_associated_loads)
lg loads list-billing-targets — Show who you can invoice for a load: its commercial parties (sender, receiver, carrier) you are allowed to bill, each with recipient_contact_id to pass to create_invoice_draft and in_my_directory (true = already in your… (lectura · — · todos · API: list_load_billing_targets)
lg loads list-problems — List loads whose uploaded documents the AI consistency check found to CONTRADICT each other (e.g. invoice weight vs CMR weight). (lectura · — · todos · API: list_load_problem_flags)
lg loads list-status-history — Show a load's status history (durum geçmişi) in order — when it went pending, in transport, transit, delivered (done). (lectura · — · todos · API: list_load_status_history)
lg loads list-stops — List the stops of a multi-stop load (çok duraklı yük — several pickups/drop-offs on one load) in route order, with type (pickup, dropoff, customs_exit, customs_entry), company, address, leg distance/duration and whether… (lectura · — · todos · API: list_load_stops)
lg loads optimize — Re-order the stops of a multi-stop load for the shortest driving route (pickups first, then drop-offs) and store the new order with leg distances — "optimise FKZ8515's stops". (escritura · — · todos · API: optimize_load_stops)
lg loads options — Read a load's editable fields, their current values and the allowed options (load types, vehicle types, goods classes, stackability, incoterms, movement types) — "FKZ8515'te neyi değiştirebilirim?". (lectura · — · todos · API: get_load_edit_form)
lg loads preview-copy — Prepare a copy draft of one of your company's OWN loads (yükü kopyala) — "FKZ8515'in aynısından bir tane daha açalım": transport mode, countries, addresses, load type, vehicle type, weight, goods class, incoterms, ports… (lectura · — · todos · API: get_load_copy_template)
lg loads remove-driver — Remove the driver from a load (the opposite of assign_driver_to_load): the load disappears from the driver's app and GPS tracking of the load stops. (escritura · confirmación · transportista · API: unassign_driver_from_load)
lg loads search — Full-text search across your loads (yük ara) — company names, pickup/delivery address, order references, load code, text written in the load chat and text read from documents shared in the chat: "içinde PO-4471 geçen… (lectura · — · todos · API: search_loads)
lg loads set-status — Move a load to a new transport status and append it to the load's status history (this is what the customer sees on the tracking screen). (escritura · confirmación + irreversible · transportista · API: update_load_status)
lg loads set-stop-status — Mark one stop of a multi-stop load as completed, or undo it (completed=false) — "FKZ8515's second drop-off is done". (escritura · confirmación · transportista · API: mark_load_stop_completed)
lg loads set-tracking — Turn a load's GPS location tracking on or off (konum takibi) — "stop location tracking for FKZ8515", "resume tracking". (escritura · confirmación · transportista · API: set_load_location_tracking)
lg loads update — Edit an existing load (yükü düzenle): loading date, weight, load type, vehicle types, goods class, stackability, pickup/delivery address, incoterms, movement type, loading/destination port. (escritura · confirmación + irreversible · todos · API: update_load)
lg maturity-options list — The selectable payment terms (vade): maturity_option_id and the number of days (0 = cash / peşin). maturity_option_id is what update_company_profile takes. (lectura · — · todos · API: list_maturity_options)
lg notification-settings get — Read our company's notification switches (Settings → Notifications): which e-mail notifications (type "notification") and push notifications (type "web-push") are on for the whole company — e.g. message, load, demand… (lectura · — · cargador · API: get_notification_settings) [clave manager]
lg notification-settings update — Turn our company's notification switches on or off (Settings → Notifications) — e.g. stop load chat push notifications or message e-mails for the whole company. settings is a list of {slug, enabled}; slugs come from… (escritura · confirmación · cargador · API: update_notification_settings) [clave manager]
lg notifications list — Read the signed-in user's own notification inbox (the bell icon): what happened, which kind of event it was, when, whether it is still unread, and the panel address the notification points at. (lectura · — · todos · API: list_notifications)
lg notifications mark-read — Mark ALL of the signed-in user's unread notifications as read (empty the bell). (escritura · — · todos · API: mark_notifications_read)
lg packages get — Read this company's package and CREDIT balance: how many credits are left, how many the package grants per year, how many were used, the renewal date, and the assistant token usage of the current period (1,000,000… (lectura · — · todos · API: get_credit_balance)
lg packages list — List the Logistivo packages this company can buy: slug, name, monthly price and yearly upfront total in the company's BILLING currency (TRY for Türkiye-billed companies, EUR otherwise — never converted with an exchange… (lectura · — · todos · API: list_packages)
lg pallets add-measurement — Record a NEW measurement for an existing pallet (dimensions in centimetres and/or gross weight in kilograms). (escritura · confirmación · todos · API: add_pallet_measurement)
lg pallets add-proof — Attach a proof photo to one of this company's pallets (e.g. the wrapped pallet, its label, damage on arrival). (escritura · — · todos · API: add_pallet_proof) [recibe un archivo: attachment_uuid]
lg pallets calculate — Suggest the missing base side of a pallet from a standard footprint (EUR 120×80, industrial 120×100, half 80×60; ±5 cm) when only one base side is known, and compute the volume when length, width and height are all… (lectura · — · todos · API: complete_pallet_dimensions)
lg pallets create — Register a NEW pallet in a warehouse, optionally with its first measurement. warehouse_id is required — resolve the warehouse name with lookup_warehouse first. (escritura · confirmación · todos · API: create_pallet)
lg pallets delete — Delete one of this company's pallet records. (escritura · confirmación + irreversible · todos · API: delete_pallet)
lg pallets delete-proof — Remove one proof photo from one of this company's pallets. (escritura · confirmación + irreversible · todos · API: delete_pallet_proof)
lg pallets extract — Estimate a pallet's content label, dimensions (cm) and gross weight (kg) from photo(s) the user attached to THIS conversation. (escritura · — · todos · API: extract_pallet_from_photos) [recibe un archivo: attachment_uuids]
lg pallets get — Read one pallet in full: its identity (code, label, SKU, barcode), status, warehouse and area, the FULL measurement history (each row with its id, source — manual, lidar, arcore or ai_photo — and confidence), its proof… (lectura · — · todos · API: get_pallet)
lg pallets list — List the pallets of this company: code, label, SKU/barcode, status, which warehouse and area it sits in, its latest measured dimensions (cm) and gross weight, and how many proof photos it has. (lectura · — · todos · API: list_pallets)
lg pallets update — Update an existing pallet: its status (in_stock, in_transit, reserved, shipped, disposed), its label/SKU/barcode/note, or MOVE it to another warehouse or area. (escritura · confirmación · todos · API: update_pallet)
lg parasut-contacts create — Create a new customer or supplier contact IN PARAŞÜT and keep its local copy. (escritura · confirmación + irreversible · todos · API: create_parasut_contact)
lg parasut-contacts list — List the customer / supplier contacts held in Paraşüt (the local copy synchronised from Paraşüt): parasut_contact_id (the Paraşüt id used by create_parasut_sales_invoice — NOT a business contact id), name, short name,… (lectura · — · todos · API: list_parasut_contacts)
lg parasut-invoices create — Issue a SALES invoice in Paraşüt for one of this company's Paraşüt contacts, as an e-invoice (scenario commercial or basic — the recipient must be an e-invoice user) or an e-archive invoice (scenario e_archive); check… (escritura · confirmación + irreversible · todos · API: create_parasut_sales_invoice)
lg parasut-invoices list — List invoices held in Paraşüt (local copy): sales invoices (default) or purchase bills, newest issue date first — invoice id and number, item type, description, issue / due date, net / gross / VAT totals, currency,… (lectura · — · todos · API: list_parasut_invoices)
lg parasut-invoices options — Return the options of the Paraşüt invoice form: income/expense categories (category_id), the Paraşüt bank and cash accounts, and — with tax_number — whether that VKN is a registered e-invoice user (then use scenario… (lectura · — · todos · API: get_parasut_invoice_options)
lg parasut-settings delete — Disconnect Paraşüt from this company: the saved credentials are removed, the accounting provider switches back to local when it was Paraşüt, and the LOCAL copies pulled from Paraşüt (contacts, invoices, bank accounts,… (escritura · confirmación + irreversible · todos · API: disconnect_parasut) [clave manager]
lg parasut-settings get — Show the Paraşüt integration status of this company: whether it is connected, the Paraşüt firm number, the user name, the client id/secret MASKED (last 4 characters only), when it was connected, the token status and the… (lectura · — · todos · API: get_parasut_settings) [clave manager]
lg parasut-settings update — Connect this company's Paraşüt account or renew its credentials (replaces an existing connection). (escritura · confirmación · todos · API: connect_parasut) [clave manager] [solo CLI]
lg payables list — Payables ("whom do we owe how much"): per-supplier totals of recorded purchase invoices — invoiced, paid, remaining, earliest due date — with a per-currency breakdown and an overall summary. (lectura · — · todos · API: list_payables)
lg payment-cards delete — Remove a saved payment card (card_id from list_payment_cards). (escritura · confirmación + irreversible · todos · API: delete_payment_card) [clave manager]
lg payment-cards list — List the company's saved payment cards, MASKED (last four digits only), with the card holder name, expiry and which one is the default card the monthly subscription is charged to. (lectura · — · todos · API: list_payment_cards)
lg payment-cards set-default — Make one of the saved cards (card_id from list_payment_cards) the DEFAULT card: the monthly package payment is charged to it from now on, and every other card loses the default flag. (escritura · confirmación + irreversible · todos · API: set_default_payment_card) [clave manager]
lg payment-instructions cancel — CANCEL a pending bank payment instruction: the reservation on its invoices is released so they can be paid another way, and the instruction becomes "cancelled". (escritura · confirmación + irreversible · todos · API: cancel_settlement_instruction)
lg payment-instructions download — Get the bank payment instruction document (PDF) with a short-lived download link. (lectura · — · todos · API: download_settlement_instruction)
lg payment-instructions get — Read one bank payment instruction: its code, template, effective date, status with timestamps and cancel reason, its note, and — when the PDF has already been rendered — a short-lived signed link to it so the user gets… (lectura · — · todos · API: get_settlement_instruction)
lg payment-instructions list — List the bank payment instructions of this company: instruction code, which template (bank format) it uses, its effective date, status (pending, executed, cancelled) and when it was executed or cancelled. (lectura · — · todos · API: list_settlement_instructions)
lg payment-instructions run — EXECUTE a pending bank payment instruction (banka talimatını yürüt / uygula): the reserved invoices are paid, the payments and journal entries are written with the instruction's effective date, and the instruction… (escritura · confirmación + irreversible · todos · API: execute_settlement_instruction)
lg planning-boards get — The planning calendar: for every driver, the stretches of days with planned work inside the Schengen area (planned_in), days assumed inside (drive back, assumed_in), planned work outside (planned_out), leave / rest… (lectura · — · transportista · API: get_planning_board)
lg plans archive — Close a plan because the user says the work is finished or abandoned. (escritura · — · todos · API: archive_plan)
lg plans create — Write down a multi-step job so it survives between conversations ("link these 5 loads to a trip, then invoice them"). (escritura · confirmación · todos · API: create_plan)
lg plans get — Read one plan: the steps that were agreed AND the commands that actually ran while it was active. (lectura · — · todos · API: get_plan)
lg plans list — List this company's plans, newest first. (lectura · — · todos · API: list_plans)
lg ports search — Find a seaport by name or UN/LOCODE (liman ara) — "Mersin", "TRMER", "Trieste". (lectura · — · todos · API: lookup_port)
lg preferences create — Remember a lasting preference of THIS user, so it applies to every future conversation too ("always show amounts in EUR", "write driver names surname first", "I want the weekly summary on Mondays"). (escritura · — · todos · API: remember_preference)
lg preferences delete — Forget one stored preference of this user. (escritura · — · todos · API: forget_preference)
lg preferences list — List what you have been asked to remember about THIS user, with the labels. (lectura · — · todos · API: list_preferences)
lg product-brands create — Create a new product brand for this company (the panel's "new brand"). (escritura · confirmación · cargador · API: create_product_brand)
lg product-brands list — List this company's product brands (id, name, code, active flag, number of products). (lectura · — · cargador · API: list_product_brands)
lg product-categories create — Create a new product category for this company (the panel's "new category"). (escritura · confirmación · cargador · API: create_product_category)
lg product-categories list — List this company's product categories (id, name, code, active flag, number of products). (lectura · — · cargador · API: list_product_categories)
lg products add-image — Add a photo to a product's gallery. (escritura · — · cargador · API: add_product_image) [recibe un archivo: attachment_uuid]
lg products create — Define a new product in this company's catalogue so stock can be recorded against it: name plus optionally its unit of measure, SKU, barcode, category, brand, minimum stock level, reorder quantity and lot tracking. (escritura · confirmación · cargador · API: create_product)
lg products delete — Delete a product from this company's catalogue. (escritura · confirmación + irreversible · cargador · API: delete_product)
lg products delete-image — Remove one photo from a product's gallery (image_id from get_product). (escritura · confirmación + irreversible · cargador · API: delete_product_image)
lg products extract — Read product details (name, description, SKU, barcode, unit, category, brand) from 1-5 photos of the product or its label — the panel's "fill from photo" button. (escritura · — · cargador · API: extract_product_from_photos) [recibe un archivo: attachment_uuids]
lg products get — Show one product of this company in full: code, SKU, barcode, unit, category and brand, low-stock threshold and reorder quantity, lot tracking, its photos (with image_id for delete_product_image /… (lectura · — · cargador · API: get_product)
lg products list — List the products of this company: code, name, SKU/barcode, unit, category and brand, whether it is active, and its low-stock threshold. (lectura · — · cargador · API: list_products)
lg products list-low-stock — List the products whose quantity on hand is BELOW their low-stock threshold (strictly below — a product exactly at the threshold is not listed), with the quantity on hand and the threshold itself. (lectura · — · cargador · API: list_low_stock_products)
lg products options — List the units of measure a product can be held in (slug for create_product / update_product unit, with Turkish and English names). (lectura · — · cargador · API: get_product_options)
lg products search — Resolve a product to its product_id + on-hand quantity. (lectura · — · cargador · API: lookup_product)
lg products set-primary-image — Make one of a product's photos its cover image (image_id from get_product). (escritura · — · cargador · API: set_product_primary_image)
lg products update — Correct an existing product: its name, unit, SKU, barcode, category, brand, minimum stock level, reorder quantity, lot tracking, note, or whether it is active. (escritura · confirmación · cargador · API: update_product)
lg receivables get — Account statement of one contact: every sales invoice issued to them and every collection, in date order with a running balance, plus totals (invoiced, paid, open balance, open invoice count). (lectura · — · todos · API: get_receivable_statement)
lg receivables list — Receivables ("who owes us how much"): per-contact totals of issued sales invoices — invoiced, paid, remaining — with a per-currency breakdown and an overall summary. (lectura · — · todos · API: list_receivables)
lg report-files create — Turn a table you compiled from tool results into a downloadable Excel (default), PDF or CSV file — any custom table, list, comparison or export, with optional charts. (lectura · — · todos · API: create_report_file)
lg reports get — Financial reports from posted journal entries: trial_balance (per-account debit/credit/balance as of a date), balance_sheet (as of a date) or income_statement (revenues/expenses/net income for a date range; defaults to… (lectura · — · todos · API: get_accounting_report)
lg reservations approve — As the warehouse owner, approve a pending reservation received at your warehouse (the booker is notified). (escritura · confirmación · cargador · API: approve_reservation)
lg reservations cancel — Cancel (withdraw) a warehouse reservation you booked, or — as the warehouse owner (customer) — cancel a reservation received at your warehouse. (escritura · confirmación + irreversible · todos · API: cancel_reservation)
lg reservations complete — As the warehouse owner, mark an APPROVED reservation at one of your warehouses as completed (the vehicle came and the work is done). (escritura · confirmación + irreversible · cargador · API: complete_reservation)
lg reservations create — Book a warehouse dock time slot. (escritura · confirmación · todos · API: create_reservation)
lg reservations get — Detail of one warehouse reservation you booked or (customer) one received at your warehouse: warehouse, area, time window, status, contact, notes, rejection reason. (lectura · — · todos · API: get_reservation)
lg reservations list — List warehouse dock reservations. side=booked_by_me (default): reservations this user/company booked at other companies' warehouses. side=received (customer role only): reservations other companies made at ONE of your… (lectura · — · todos · API: list_reservations)
lg reservations list-slots — Available dock time slots of one day with remaining capacity. (lectura · — · todos · API: list_reservation_slots)
lg reservations reject — As the warehouse owner, reject a pending reservation received at your warehouse, with an optional reason shown to the booker. (escritura · confirmación + irreversible · cargador · API: reject_reservation)
lg reservations reschedule — As the warehouse owner, move a PENDING or APPROVED reservation at one of your warehouses to a new time. (escritura · confirmación · cargador · API: reschedule_reservation)
lg roro-routes list — For a load you are carrying, list the Ro-Ro (ferry) lines closest to its PICKUP address, nearest first: the line name, its departure and arrival ports and how many kilometres the pickup point is from the departure port. (lectura · — · transportista · API: list_nearby_roro_routes)
lg roro-routes select — Select the Ro-Ro (ferry) line a load you are carrying will use. (escritura · confirmación · transportista · API: select_roro_route)
lg roro-routes set-required — Mark whether a load you are carrying will travel by Ro-Ro (ferry) or not. (escritura · confirmación · transportista · API: set_load_roro_required)
lg route-plans assign-driver — Assign a driver (and, on a double-crew plan, a co-driver; optionally the vehicle/trailer) to a saved route plan (route_plan_id or route_plan_code). (escritura · confirmación · transportista · API: assign_driver_to_route_plan)
lg route-plans calculate — Calculate a multi-stop truck journey WITHOUT saving it: truck driving time (car time × hgv_factor, capped speed), the EU 561/2006 / AETR breaks, daily and weekly rests, weekend/holiday driving bans and border waits, and… (escritura · confirmación · transportista · API: calculate_route_plan)
lg route-plans create — Save a route plan as a DRAFT (same arguments as calculate_route_plan, plus name, vehicle_id, trailer_id, start_flex_days). (escritura · confirmación · transportista · API: create_route_plan)
lg route-plans delete — Cancel and delete a route plan (route_plan_id or route_plan_code). (escritura · confirmación + irreversible · transportista · API: delete_route_plan)
lg route-plans get — One saved route plan: stops with arrival/departure ranges, the summary (distance, truck driving time, arrival optimistic / expected / conservative, breaks, daily/weekly rests, reduced rests, border waits), Schengen days… (lectura · — · transportista · API: get_route_plan)
lg route-plans list — List the company's saved route plans, newest first: code, name, status (draft | assigned | converted | cancelled), departure, crew, driver, vehicle, linked load/trip, stops, arrival range and Schengen day count. (lectura · — · transportista · API: list_route_plans)
lg route-plans preview — Compare 1-6 variants of the same journey side by side — different drivers, departure days or a double crew: arrival range, driving and rest counts, Schengen days left at the end for every crew member, availability /… (escritura · confirmación · transportista · API: compare_route_plan_scenarios)
lg route-plans remove-driver — Take the driver (and co-driver) off an assigned route plan (route_plan_id or route_plan_code); the plan goes back to draft and stops counting as planned Schengen days for them. (escritura · confirmación · transportista · API: unassign_driver_from_route_plan)
lg route-plans select — Link a saved route plan (route_plan_id or route_plan_code) to the load or trip it was planned for — give load_code OR trip_code; give neither to remove the link. (escritura · confirmación · transportista · API: link_route_plan)
lg route-plans update — Change a saved route plan (route_plan_id or route_plan_code): any create_route_plan field — name, departure, stops, crew, options, vehicle. (escritura · confirmación · transportista · API: update_route_plan)
lg schengen-stays calculate — Project ONE driver's Schengen 90/180 days into the future: days used today, then how the remaining days move with the loads, trips and route plans already assigned to him (plus the drive back out) and his leave /… (lectura · — · transportista · API: get_driver_schengen_projection)
lg schengen-stays create-set — Import drivers' past Schengen entry/exit periods (passport stamps) from an Excel/CSV file — one row per stay: driver code or name, entry date, exit date (empty = still inside). (escritura · confirmación · transportista · API: import_driver_schengen_periods) [recibe un archivo: attachment_uuid]
lg schengen-stays download — Give a short-lived download link to the Schengen history import template, pre-filled with the company's active drivers (user code + name; entry/exit date cells empty). (lectura · — · transportista · API: download_schengen_import_template)
lg schengen-stays get — One driver's full Schengen 90/180 picture: days used (confirmed / declared / inferred), days left (signed; negative = overstay), latest exit date, breach date, when days come back (regain schedule), per-country day… (lectura · — · transportista · API: get_driver_schengen_detail)
lg schengen-stays list — Fleet-wide Schengen 90/180 compliance: which drivers breached the 90-days-in-180 rule or are close to it, how many days each has left (days_remaining is SIGNED — negative means overstay), the latest exit date… (lectura · — · transportista · API: list_schengen_compliance)
lg schengen-stays list-periods — List the Schengen stay periods DECLARED for a driver (passport stamps / starting balance) with their period_id, entry and exit dates and day count. (lectura · — · transportista · API: list_driver_schengen_periods)
lg schengen-stays remove-period — Delete ONE wrongly entered declared Schengen period of a driver (period_id from list_driver_schengen_periods). (escritura · confirmación + irreversible · transportista · API: delete_driver_schengen_period)
lg schengen-stays set-baseline — Set a driver's Schengen starting balance — what happened BEFORE GPS tracking: either the exact periods inside the zone from passport stamps (baseline_mode=periods) or just "X days used in the last 180"… (escritura · confirmación · transportista · API: set_driver_schengen_baseline)
lg schengen-stays set-exemption — Exempt a driver from Schengen 90/180 tracking (EU/EFTA passport, residence permit, national long-stay visa) or switch the rule back on. (escritura · confirmación · transportista · API: set_driver_schengen_exemption)
lg settlements cancel — CANCEL a bulk collection / payment (settlement batch). (escritura · confirmación + irreversible · todos · API: cancel_settlement_batch) [clave manager]
lg settlements create — Close several open invoices of ONE contact in ONE currency in a single bulk collection (direction in) or bulk payment (direction out). instrument transfer = money already moved by bank transfer (payments + journal… (escritura · confirmación + irreversible · todos · API: create_settlement_batch)
lg settlements get — Read one bulk collection / payment (settlement batch) in full: code, direction (in = collection, out = payment), instrument (transfer, bank instruction or cheque), status, counterparty, currency and total, value date,… (lectura · — · todos · API: get_settlement_batch)
lg settlements list — List bulk collection/payment batches (code, direction, instrument, contact, currency, total, value date, status), newest first. (lectura · — · todos · API: list_settlement_batches)
lg settlements list-counterparties — List the business contacts that have OPEN local invoices in one money direction — in = customers owing us (sales invoices), out = suppliers we owe (purchase invoices) — each with its default open-invoice currency and… (lectura · — · todos · API: list_settlement_counterparties)
lg settlements list-invoices — Open LOCAL invoices of one contact in one currency that can be allocated in a bulk collection (direction in = sales invoices) or bulk payment (direction out = purchase invoices), each with payable_remaining (remaining… (lectura · — · todos · API: list_settlement_invoices)
lg settlements options — Return the options of the bulk collection / payment form: allowed currencies, this company's OWN bank accounts (bank_account_id for create_settlement_batch / attach_check_to_invoices), bank instruction templates, batch… (lectura · — · todos · API: get_settlement_options)
lg ship-trackings create — Attach a ship to a load and track it on the load's map (yüke gemi bağla), or swap the ship (replace_ship_id = the ship being replaced) — "FKZ8515 sails on MSC Gülsün, track it". (escritura · confirmación · cargador, transportista · API: track_ship_for_load)
lg ship-trackings delete — Stop tracking a ship on a load (gemi takibini durdur). (escritura · confirmación · cargador, transportista · API: stop_ship_tracking)
lg ship-trackings get — Show the ship(s) tracked on a load and their position history since the load was created (yükün gemi takibi) — "where is FKZ8515's ship now". (lectura · — · todos · API: get_load_ship_tracking)
lg ships search — Search the ship registry (gemi sicili) by name, IMO or MMSI — "what is MSC Gülsün's IMO", "find the vessel 9839430". (lectura · — · todos · API: lookup_ship)
lg stock adjust — Record a stock count correction (sayım düzeltme) or write-off (fire). mode=set sets the absolute on-hand at the slot; mode=delta applies a signed change (negative reduces). reason is required. (escritura · confirmación + irreversible · cargador · API: create_stock_adjustment)
lg stock list — Read current on-hand stock levels. (lectura · — · cargador · API: check_stock_level)
lg stock list-movements — List the stock movements of this company, newest first: which product moved, in or out (or a transfer or a count adjustment), how much, in which warehouse and area, on which pallet, who performed it and when. (lectura · — · cargador · API: list_stock_movements)
lg stock move — Record a stock movement: inbound (giriş), outbound (çıkış), or transfer between locations. (escritura · confirmación + irreversible · cargador · API: create_stock_movement)
lg stock options — List the stock movement types (receipt, issue, transfer, count adjustment …) with their slug and Turkish/English names — the values create_stock_movement and list_stock_movements use. (lectura · — · cargador · API: get_stock_options)
lg sub-companies create — Add a group / sub company (alt firma) to this customer company: legal_name (ticaret unvanı), tax_office (vergi dairesi), tax_number and the full address — all four required. (escritura · confirmación · cargador · API: create_sub_company) [clave manager]
lg sub-companies delete — Delete one of this customer company's group / sub companies (alt firma) by sub_company_id from list_sub_companies. (escritura · confirmación + irreversible · cargador · API: delete_sub_company) [clave manager]
lg sub-companies list — This customer company's group / sub companies (alt firmalar, grup şirketleri — Settings › Sub Companies): sub_company_id, legal name, tax office, tax number and address. (lectura · — · cargador · API: list_sub_companies)
lg tariff-chapters get — Answer "which chapter is this GTİP in / what does chapter 76 cover / what do the chapter notes say?". (lectura · — · todos · API: get_tariff_chapter)
lg tariff-matrices get — FREE. (lectura · — · todos · API: get_tariff_matrix)
lg tariff-matrices list — FREE. (lectura · — · todos · API: list_tariff_matrix_runs)
lg tariff-matrices preview — FREE. (lectura · — · todos · API: plan_tariff_matrix)
lg tariff-matrices run — Run an official duty + anti-dumping inquiry for ONE tariff code across MANY origin and destination countries at once, and record it. (escritura · confirmación + irreversible · todos · API: run_tariff_matrix)
lg tariffs coverage — FREE. (lectura · — · todos · API: get_tariff_coverage)
lg tariffs extract — Read an invoice or proforma the user attached to THIS conversation and pull out its product lines with candidate GTİP/HS codes, plus the origin and destination it names. (escritura · — · todos · API: extract_tariff_codes_from_invoice) [recibe un archivo: attachment_uuid]
lg tariffs get — Read the result of a tariff inquiry that was already run: duty rate, the column it came from, the statutory rate, anti-dumping measures and the data notes. (lectura · — · todos · API: get_tariff_inquiry)
lg tariffs inquiry — Start an official duty / anti-dumping inquiry for one GTİP/HS code and a COUNTRY PAIR (origin → destination). (escritura · confirmación + irreversible · todos · API: run_tariff_inquiry)
lg tariffs list — List this company's recent tariff inquiries (code, direction, counterpart country, status, date) so the user can find an earlier one by code or country instead of running a new inquiry. (lectura · — · todos · API: list_tariff_inquiries)
lg tariffs search — Search the Turkish customs nomenclature (GTİP / HS) by goods description or by a partial code, and return matching codes with their official descriptions. (lectura · — · todos · API: lookup_tariff_code)
lg teammates delete — Remove a person from the company team. (escritura · confirmación + irreversible · todos · API: remove_teammate) [clave manager]
lg teammates list — List the other users of this company (drivers excluded) with e-mail, active state and RBAC role (manager | employee | fleet-manager), plus seat_usage (team seats used / limit / remaining under the package). role narrows… (lectura · — · todos · API: list_teammates)
lg teammates set-role — Change a team member's role (for example make them a manager, or move them back to employee). (escritura · confirmación · todos · API: update_teammate_role) [clave manager]
lg teammates set-status — Activate or deactivate a team member. (escritura · confirmación · todos · API: set_teammate_status) [clave manager]
lg tender-bids create — Submit YOUR bid for a tender using a file the user attached to THIS conversation (the filled specification spreadsheet, a PDF offer, or a zip). (escritura · confirmación + irreversible · transportista · API: submit_tender_bid) [recibe un archivo: attachment_uuid]
lg tender-bids get — Read YOUR OWN bid on a tender: its status (submitted, revision requested, accepted, rejected), when it was submitted and which files it carries. (lectura · — · transportista · API: get_my_tender_bid)
lg tender-bids set-status — As the tender owner, ACCEPT a carrier's bid, REJECT it, or ask for a REVISION. (escritura · confirmación + irreversible · cargador · API: decide_tender_bid)
lg tenders add-document — Attach a file to one of YOUR tenders as an additional specification document (accepted: pdf, xlsx, xls, doc, docx; at most 10 MB). (escritura · confirmación · cargador · API: add_tender_document) [recibe un archivo: attachment_uuid]
lg tenders create — Open a NEW document-based freight tender and generate its specification Excel from the lanes the user gives (origin → destination, vehicle/load type, monthly volume). (escritura · confirmación · cargador · API: create_tender) [recibe un archivo: attachment_uuid]
lg tenders delete-document — Remove a specification file from one of YOUR tenders (document_id from get_tender → documents[]). (escritura · confirmación + irreversible · cargador · API: delete_tender_document)
lg tenders extract — Draft the specification (terms) text of a tender from a tender document the user supplies (accepted: pdf, xlsx, xls; at most 10 MB). (lectura · — · cargador · API: extract_tender_specification) [recibe un archivo: attachment_uuid]
lg tenders generate — Generate a specification Excel for an EXISTING tender from the lanes/items the user gives and attach it to the tender as a document; returns a short-lived download link. (escritura · confirmación · cargador · API: generate_tender_excel)
lg tenders get — Read one tender in full: specification text, dates, attached specification files (with short-lived download links) and — for the tender owner — every carrier bid with its status; a carrier sees only its own bid. (lectura · — · cargador, transportista · API: get_tender)
lg tenders list — List document-based freight tenders. (lectura · — · cargador, transportista · API: list_tenders)
lg tenders update — Edit one of YOUR tenders: title, description, specification text, the bidding window (start_date / end_date), the price-validity window, whether it still accepts bids (is_active), its status, and who it is shared with. (escritura · confirmación · cargador · API: update_tender)
lg trade-measures get — Answer "is there an anti-dumping / countervailing / safeguard measure on this GTİP code when importing INTO TURKEY?" straight from the Ministry of Trade's measures-in-force list, which we sync every day. (lectura · — · todos · API: get_trade_measures)
lg trade-measures list — Browse Türkiye's trade-defence measures WITHOUT a GTİP code: by origin country ("which measures apply to goods from China"), by product ("which countries have a measure on aluminium foil"), by measure type, or by end… (lectura · — · todos · API: list_trade_measures)
lg user-accounts preview — Show what closing MY OWN account would do, without closing it: whether I am a manager, whether I am the only user (then the company is deactivated too), whether I must first hand the manager role to a teammate… (lectura · — · todos · API: preview_account_closure)
lg users get — Who am I? (lectura · — · todos · API: get_current_user)
lg vehicle-assignments create — Hand a fleet vehicle over to a driver (open an assignment), so their expense receipts and trips are attached to the right tractor unit or trailer. (escritura · confirmación · cargador, transportista · API: assign_vehicle_to_driver)
lg vehicle-assignments list — List which driver currently holds which vehicle (tractor unit / trailer). (lectura · — · cargador, transportista · API: list_vehicle_assignments)
lg vehicle-assignments revoke — Close an open vehicle assignment: the driver hands the vehicle back. (escritura · confirmación · cargador, transportista · API: end_vehicle_assignment)
lg vehicle-expenses create — Record a cost against one of the company's own vehicles without an invoice file — category, amount and currency are required, the rest is optional. (escritura · confirmación · cargador, transportista · API: create_vehicle_expense) [recibe un archivo: attachment_uuid]
lg vehicle-expenses delete — Delete a vehicle cost entered by mistake (duplicate, wrong plate, test entry). (escritura · confirmación + irreversible · cargador, transportista · API: delete_vehicle_expense)
lg vehicle-expenses list — List the cost records of the company's own vehicles (maintenance, tyres, repair, roadworthiness test, insurance, fuel, tolls, parts) with a EUR total and a breakdown per category and per currency. (lectura · — · cargador, transportista · API: list_vehicle_expenses)
lg vehicle-expenses update — Correct a recorded vehicle cost: category, amount, currency, vendor, invoice number, invoice date or description — "the tyre invoice was 580 not 850". (escritura · confirmación · cargador, transportista · API: update_vehicle_expense)
lg vehicles add-document — File a paper of one of the company's own vehicles — registration (ruhsat), traffic or kasko insurance, roadworthiness inspection, tachograph calibration, CMR insurance, green card, ADR certificate — from an uploaded… (escritura · confirmación · cargador, transportista · API: add_vehicle_document) [recibe un archivo: attachment_uuid]
lg vehicles archive — Take a vehicle out of service (archive it) or put an archived one back into service. (escritura · confirmación · cargador, transportista · API: archive_vehicle)
lg vehicles create — Add a vehicle to this company's fleet: plate plus its kind (truck, tractor unit, trailer, van, pickup, car), optionally brand, model, model year, VIN and a note. (escritura · confirmación · cargador, transportista · API: create_vehicle) [recibe un archivo: attachment_uuid]
lg vehicles delete — Delete a vehicle record that was created BY MISTAKE (wrong plate, duplicate). (escritura · confirmación + irreversible · cargador, transportista · API: delete_vehicle)
lg vehicles delete-document — Remove a paper from a vehicle's file (a duplicate row, a paper filed on the wrong vehicle, an old registration). (escritura · confirmación + irreversible · cargador, transportista · API: delete_vehicle_document)
lg vehicles get — Full detail of ONE fleet vehicle: identity (plate, kind, brand, model, model year, VIN), whether it is active or archived, ALL of its papers with their expiry date and days_to_expiry, how many papers expire soon or… (lectura · — · cargador, transportista · API: get_vehicle)
lg vehicles list — List this company's fleet vehicles with plate, kind (truck / tractor unit / trailer / van / pickup / car), brand, model, model year, VIN and how many of their papers (insurance, inspection, permits) expire soon or have… (lectura · — · cargador, transportista · API: list_vehicles)
lg vehicles search — Resolve one of this company's fleet vehicles (truck, tractor unit, trailer, van, pickup, car) to its vehicle_id by plate, brand, model or VIN. (lectura · — · cargador, transportista · API: lookup_vehicle)
lg vehicles update — Correct a fleet vehicle's fields: plate, kind, brand, model, model year, VIN or note. (escritura · confirmación · cargador, transportista · API: update_vehicle)
lg vehicles update-document — Correct a vehicle paper already on file — most often its expiry date (valid_until) after a renewal or a wrong AI reading, but also its type, number, issue date, issuer, the plate printed on it, issuing country, title or… (escritura · confirmación · cargador, transportista · API: update_vehicle_document)
lg wallets get — Read this company's Logistivo WALLET balance — the prepaid MONEY balance (amount + currency). (lectura · — · todos · API: get_wallet_balance)
lg wallets list-transactions — List this company's Logistivo WALLET movements, newest first: top-ups and money spent on packages or paid features, with the amount, the balance before/after, who did it and when. (lectura · — · todos · API: list_wallet_transactions)
lg warehouse-areas create — Add a new area to one of this company's warehouses — an open area, a closed area or a loading ramp — with how many vehicles it can take at the same time (its booking slot capacity). (escritura · confirmación · cargador · API: create_warehouse_area)
lg warehouse-areas delete — Delete one area/ramp of a warehouse. (escritura · confirmación + irreversible · cargador · API: delete_warehouse_area)
lg warehouse-areas update — Change a warehouse area's name, type (open_area, closed_area, ramp), vehicle capacity, display order or active flag. (escritura · confirmación · cargador · API: update_warehouse_area)
lg warehouse-links create — Create a public booking link for one of this company's warehouses, to share with a carrier, supplier or customer: anyone holding the URL can book a slot (the booking still waits for your approval). (escritura · confirmación · cargador · API: create_warehouse_link)
lg warehouse-links list — List the public booking links shared for one of this company's warehouses: the full URL (anyone holding it can book a slot), the area it is limited to (if any), the expiry, and whether it is active. (lectura · — · cargador · API: list_warehouse_links)
lg warehouse-links revoke — Permanently revoke a warehouse booking link: the URL stops working for everyone and cannot be brought back (create a new link if needed). (escritura · confirmación + irreversible · cargador · API: revoke_warehouse_link)
lg warehouse-links set-status — Turn a warehouse booking link off (nobody can book through it) or back on. (escritura · confirmación · cargador · API: set_warehouse_link_status)
lg warehouses create — Define a new warehouse for this company so stock can be held and dock slots booked there: a name and its street address are enough. (escritura · confirmación · cargador · API: create_warehouse)
lg warehouses delete — Delete one of this company's warehouses. (escritura · confirmación + irreversible · cargador · API: delete_warehouse)
lg warehouses get — Read one warehouse in full: its identity and address, working days and hours, holiday opening, capacity, reservation slot rules (slot length, minimum and maximum duration), its safety and driver rules, the… (lectura · — · cargador · API: get_warehouse)
lg warehouses list — List the warehouses of this company: name, address, whether it is active, its working days and hours, open/closed area capacity, the dock slot length and how many areas (racks/bays) it has. (lectura · — · cargador · API: list_warehouses)
lg warehouses search — Resolve a warehouse by name to its warehouse_id, with its areas. (lectura · — · cargador · API: lookup_warehouse)
lg warehouses set-equipment — Set a warehouse's equipment list IN FULL (forklift, transpallet = pallet truck, other; with quantity and an optional name/specification). (escritura · confirmación · cargador · API: set_warehouse_equipment)
lg warehouses update — Update a warehouse: its name or address, working days and hours, holiday opening, capacity, dock slot rules, the driver/safety flags or the active flag. (escritura · confirmación · cargador · API: update_warehouse)
Integración con ERP y CRM — Identidad: nada de cuentas de servicio, un usuario real en su lugar
Un ERP o un CRM se conecta a Logistivo como un usuario real de la empresa con un token de acceso personal emitido desde el panel. Nunca se crea una cuenta de servicio sintética (sin empresa, exenta del acotamiento y sin nadie responsable de ella).
Esto es arquitectura, no preferencia. El aislamiento multi-tenant descansa por completo en la empresa del usuario; para una identidad sin empresa, el ámbito de aislamiento queda inerte, y una sola consulta errónea con ese token lee datos que no le pertenecen. La segunda razón es la auditoría: la columna de usuario del registro vincula «quién ejecutó esto» con una persona; una cuenta de servicio vacía de sentido esa columna y deja sin dueño una integración que emite facturas. La tercera es la revocación: si un token pertenece a una persona, la integración se calla cuando esa persona se va. Un puente sin dueño es el puente que sigue escribiendo en silencio durante años.
En la práctica: la empresa crea un usuario normal en el panel (por ejemplo, «Puente ERP», a cargo de un empleado con nombre y apellidos), le da un rol restringido, emite un token desde la sesión de ese usuario y lo pone en el ERP.
Ese usuario es visible en el sistema de permisos, sus derechos se pueden recortar y su token se puede revocar por separado. Lo que está prohibido no es crear una cuenta, sino crear una cuenta que no esté vinculada a un tenant.
Una integración por token. Si dos sistemas comparten un token, se pierde la granularidad de la revocación: cortar el CRM significa cortar también el ERP.
Integración con ERP y CRM — Versionado y obsolescencia
La respuesta del catálogo lleva un entero contract_version; las filas de comandos llevan since, deprecated_at y replaced_by. La versión del contrato solo sube con cambios incompatibles.
La versión NO sube por: un comando nuevo, un parámetro opcional nuevo, un campo nuevo en una respuesta. Un consumidor debe ignorar los campos que no conoce; un cliente que da error ante un campo desconocido no cumple el contrato.
La versión SÍ sube por: eliminar o renombrar un comando, eliminar un campo de respuesta, hacer obligatorio un parámetro opcional, restringir un enum. La forma antigua sigue viva durante al menos dos trimestres naturales (6 meses) con deprecated_at y replaced_by.
La obsolescencia se anuncia en el catálogo, no solo en un changelog. Como el cliente se construye a partir del catálogo, un comando con deprecated_at definido imprime un aviso sin ninguna nueva versión del cliente, y el integrador lo ve en sus logs.
El nombre de API está congelado para siempre. La identidad de la CLI (dominio/verbo) se podía rehacer libremente antes de anunciarse; tras el anuncio solo cambia con una subida de versión y una ventana de migración, durante la cual el par antiguo se sirve como alias.
En la práctica: la respuesta del catálogo y la cabecera X-Contract-Version llevan la versión; cada fila de comando lleva since, deprecated_at, replaced_by y aliases (pares dominio/verbo antiguos). Llamar a un comando obsoleto sigue funcionando y responde con una cabecera X-Deprecated: name; deprecated_at=…; replaced_by=… más un objeto deprecated en el cuerpo. ?domain= en el catálogo resuelve un dominio alias antiguo al comando actual.
Un cliente que entiende la versión 1 y se encuentra con un número mayor debe registrar un aviso y seguir adelante; lg hace exactamente eso. Las retiradas vigentes se enumeran en la promesa de estabilidad de arriba.
Integración con ERP y CRM — Identificadores estables: nunca le des a tu ERP un id autoincremental como clave
Los ids autoincrementales internos son opacos y están acotados al tenant: el id válido de otra empresa te devuelve «no encontrado», no datos. Pero ser opacos no los convierte en claves de negocio. Lo que un ERP guarda en su propio registro tiene que ser una clave de negocio.
Carga: code (el código de cliente, p. ej. FSK2158). loads get ya funciona por código.
País: ISO 3166-1 alpha-2. countries search devuelve el código.
HS / arancel: el propio código; la nomenclatura ya es universal.
Factura: el número de factura, una vez emitida. Un borrador solo tiene un id de superficie, y un id de borrador NO es una clave de negocio: el ERP debe llevar su propia referencia y nunca guardar un id de borrador.
Producto, almacén, contacto: hoy solo un id de superficie. La regla para los comandos nuevos es explícita: cualquier comando que devuelva un id de superficie devuelve también la propia clave de negocio del tenant (SKU, código, número fiscal) para que el ERP pueda hacer la correspondencia en su lado.
Integración con ERP y CRM — Paginación, filtrado y sincronización incremental
Los comandos de listado reciben limit y devuelven count. Para una sincronización nocturna, el contrato se compromete a lo siguiente; un comando de listado que lo ha adoptado anuncia cursor y updated_since en su JSON Schema, y hasta que lo haga, trátalo como una ventana pequeña (máximo 20 filas, sin cursor).
Petición: limit (de 1 al máximo de cada comando) más cursor (opaco, solo hacia delante, firmado por el servidor). offset NO se usa: en una tabla viva, un offset se desplaza; un registro insertado entre dos páginas hace que el ERP se salte una fila o la cuente dos veces, y lo hace en silencio.
Respuesta: { count, total?, next_cursor|null }. count es el número de filas de esta respuesta; cuando next_cursor es null, la lista está completa. Devuelve next_cursor sin cambios: no es un número de página y no te corresponde construirlo.
Un cursor manipulado o ajeno se rechaza con 422 invalid_request; un cursor está vinculado a la empresa que lo recibió y no puede paginar datos de otro tenant.
Filtrado: los parámetros con nombre del JSON Schema, combinados con AND. No hay un lenguaje de consulta libre: un DSL sería una segunda superficie de consulta que tendríamos que defender.
Sincronización incremental: updated_since (ISO-8601, UTC) más el cursor. Guarda el updated_at más reciente que hayas visto y devuélvelo en la siguiente ejecución; sin él, cada ERP vuelve a descargarlo todo cada hora.
Referencia externa: los comandos de escritura aceptan external_ref (tu propia clave de documento), única por empresa; un segundo create con el mismo external_ref se rechaza en lugar de duplicarse, y list/get lo devuelven para que puedas hacer la correspondencia de registros en tu lado.
Integración con ERP y CRM — Límites de peticiones
La clave del límite es el token, no la IP: un ERP llega desde detrás de un único NAT, y un límite basado en IP contaría a toda una empresa como un solo usuario. Dos integraciones con dos claves nunca se comen la cuota la una a la otra; es la segunda razón de «una integración por clave».
Descubrimiento sin autenticación (public/cli/catalog): 30 por minuto. Es un diccionario, no una fuente de datos; léelo una vez mientras escribes tu puente, nunca en un bucle de producción.
Endpoints del catálogo (GET common/commands, GET common/commands/{name}): 120 por minuto y token. El catálogo cambia poco y responde 304 a If-None-Match; no lo vuelvas a descargar antes de cada comando: lg lo guarda en caché durante una hora.
Comandos de lectura (POST common/commands/{name} con read_only: true): 120 por minuto y token.
Comandos de escritura (POST common/commands/{name} con read_only: false; un nombre desconocido también cuenta aquí): 30 por minuto y token. Las escrituras tienen efectos secundarios; un bucle desbocado se factura.
Comandos que gastan créditos (el credit_cost de la fila del catálogo no es cero; por ejemplo, tariffs inquiry y export-documents generate): el límite real son los CRÉDITOS, no el número de peticiones. Una respuesta 200 puede haber gastado un crédito.
Topes diarios por empresa, compartidos con el panel: los comandos que envían correos o push a personas de fuera de tu empresa consumen de 300 notificaciones salientes al día, y los que inician el seguimiento de pago de contenedores o buques, de 100 al día. Por encima del tope, un comando responde DAILY_LIMIT_REACHED con retry_after; las subidas de archivos tienen sus propios topes (consulta Comandos que reciben archivos).
429 siempre lleva Retry-After y un cuerpo { error_code: "rate_limited", retry_after, limit, bucket }; respétalo en lugar de inventarte un retraso fijo. El catálogo publica las cifras actuales en rate_limits.
Integración con ERP y CRM — Cosas que no haremos
Esta suele ser la parte más útil de un contrato: saber lo que nunca llegará te permite diseñar teniéndolo en cuenta.
Ninguna cuenta de servicio ni ninguna identidad que no esté vinculada a un tenant.
Ningún pago, número de tarjeta ni consentimiento legal a través de la API o de un chat. Esos pasos se quedan en el navegador de la persona; un comando te da el enlace.
Ninguna segunda vía: no hay acceso directo a la base de datos, ni acceso a shell, ni ningún endpoint masivo que se salte el único punto de aplicación. El control de rol, el control de confirmación, la idempotencia y el registro de auditoría solo se aplican ahí.
Ramificar según el texto de los mensajes de error no está soportado; el texto está localizado y cambia sin aviso.
Ninguna paginación por offset.
Usar un id de superficie como clave de negocio en tu ERP no está soportado.
Los webhooks salientes no se meten a presión en este contrato, pero ya EXISTEN y están documentados en esta página (la sección de webhooks de arriba). El catálogo es una superficie PULL y el flujo de eventos es un contrato SEPARADO: los nombres de los eventos y el esquema del payload se versionan con sus propias reglas y no están atados a la versión del contrato del catálogo de comandos.
El catálogo legible por máquina
Esta página se escribió para personas. Para un asistente de IA o un cliente automatizado, la misma información existe como copia estructurada y sin autenticación.
GET /api/public/cli/catalog no requiere autenticación y devuelve la identidad pública de los comandos: el nombre de API congelado, la identidad dominio/verbo de la CLI, la descripción, los parámetros en JSON Schema, los indicadores read_only, confirmation_needed e irreversible, el credit_cost y los campos de acceso key_level, permission, file_params, secret_parameters y cli_only. No devuelve datos personales, ni datos de tenant, ni registros de ejemplo: solo lo que es la superficie.
La forma correcta de que un agente externo lo use: leer el catálogo, explicar con SUS PROPIAS palabras qué trabajos son posibles y, cuando haga falta ejecutar algo, indicar al usuario que lo ejecute en su propio entorno con su propio token. El agente nunca pide, genera ni retransmite el token de un usuario.
Conectar Logistivo a un asistente de IA para el registro y las solicitudes de transporte es un canal aparte con su propia página:
El catálogo no requiere autenticación; la ejecución, sí. No hay forma de ejecutar un comando en nombre de un agente: lo que se ejecuta es siempre la propia identidad del usuario.
Una contraseña de Logistivo, un código de verificación o un token de acceso nunca pasan por un chat. No construyas un flujo que pida, genere o retransmita ninguno de ellos.
Si un comando es irreversible está escrito en el catálogo. Nunca sugieras «probémoslo» en un comando con irreversible: true.
Los comandos cuyo credit_cost no es cero (por ejemplo, tariffs inquiry y export-documents generate) tienen un resultado monetario; no los llames en un bucle automatizado.
Los pagos, los números de tarjeta y el consentimiento legal nunca pasan por un chat ni por un agente. Ofrece en su lugar el enlace de handoff-links generate; la persona termina el paso en su propio navegador.
Un agente que actúa con la clave de un usuario debería llamar primero a users get: devuelve el rol, el nivel de acceso de la clave, los permisos efectivos y si un consentimiento pendiente o una verificación de teléfono está bloqueando las escrituras; así prevés los rechazos en lugar de ir acumulándolos.
Un gemelo en texto plano de esta página está en /cli.md; úsalo si analizas markdown con más fiabilidad que HTML.
La definición legible por máquina: OpenAPI 3.1 y Postman
El catálogo de arriba es el formato propio de Logistivo. La misma información se publica también en dos formatos estándar del sector que tus herramientas ya entienden: una definición OpenAPI 3.1 y una colección de Postman. Ninguna de las dos está escrita a mano: ambas se generan a partir del registro de comandos en vivo en cada petición, así que no pueden quedarse desfasadas.
La definición ES el catálogo, no una segunda realidad. Cada comando aparece como una operación POST /api/common/commands/; el esquema del cuerpo es el propio JSON Schema del comando (byte a byte lo que ve el asistente), el esquema de la respuesta es el sobre compartido, los indicadores de control (read_only, confirmation_needed, irreversible y el distintivo de créditos) están en la extensión x-logistivo, y las claves de error de negocio están bajo x-error-keys. Un comando retirado se marca como deprecated: true y sigue pudiéndose llamar durante su ventana de seis meses.
Junto a la superficie de comandos, en la definición también están los endpoints REST que llevan el contrato de integración: 10 endpoints de listado con sincronización incremental (updated_since + cursor + limit) y 7 endpoints de escritura que aceptan tu propia clave (external_ref). La superficie REST de Logistivo es mucho mayor; el resto se deja fuera A PROPÓSITO. Esos payloads son el contrato propio del producto, y un esquema escrito a base de suposiciones rompería tu cliente generado en la primera llamada, y buscarías el error en tu código, no en el nuestro.
La definición se genera para el ROL de quien la pide: el comando de otro rol nunca entra en el documento, porque una definición es un contrato y no un diccionario, y todo lo que contiene debe poder llamarse con ese token. La versión sin autenticación es la unión de los tres roles, y en ella cada operación indica qué roles la ven en x-logistivo.roles.
No te fíes de nuestra palabra, compruébalo: npx @redocly/cli lint logistivo-openapi.json pasa sin ningún aviso.
GET /api/common/spec/openapi.json — La definición OpenAPI 3.1 para el rol de tu token. Lleva un ETag; If-None-Match te da un 304, así que no la vuelves a descargar en cada build.
GET /api/common/spec/postman.json — El mismo alcance como colección de Postman v2.1, con las variables base_url y token y carpetas ya agrupadas por dominio de comando.
GET /api/public/cli/openapi.json — La versión sin autenticación: la unión de los tres roles. Para diseñar y presupuestar el puente antes de tener un token.
GET /api/public/cli/postman.json — La colección de Postman sin autenticación: un solo archivo que puedes pasarle a tu equipo.
559 operaciones — 519 comandos + 36 operaciones REST y del plano de control + 4 endpoints de catálogo e identidad. Las cifras de esta página no se escriben a mano; se cuentan a partir del documento en vivo en cada petición, así que el día en que se lanza un comando suben también aquí, y cuadran.
El esquema de seguridad — bearerAuth: un token de Passport emitido para un usuario real. Una clave con alcance de lectura solo puede llamar a las operaciones marcadas con x-logistivo.read_only: true; un intento de escritura devuelve 403 ANTES del control de confirmación, así que una clave de solo lectura nunca ve un 409.
Cada rama de error está descrita — Cada operación describe 401/403/404/409/422/429/500 por separado. Los dos significados de 409 (confirmación requerida / conflicto de idempotencia) y los dos significados de 422 (error de esquema / rechazo de negocio) son distintos en el documento, así que tu generador no los funde en una sola rama.
Sin marca de tiempo — El documento no lleva hora de generación. El mismo catálogo produce los mismos bytes; por eso el ETag funciona de verdad y una definición que guardas en el control de versiones no aparece como «cambiada» en cada descarga.
No inventamos payloads del producto — En los endpoints REST de escritura solo se describe el campo del contrato (external_ref); el resto del cuerpo queda abierto como additionalProperties: true y se remite al lector a la documentación del producto. Una definición incompleta pero verdadera es mejor que una completa pero inventada.
La lista de claves de error por operación NO es exhaustiva — x-error-keys enumera solo las claves que se deducen con certeza del propio registro del comando, y lo indica con x-error-keys-exhaustive: false. El diccionario completo está en la raíz del documento; trata cualquier clave que no reconozcas como un fallo genérico. Una «lista completa» inventada te habría empujado a no escribir nunca la rama por defecto.
Las herramientas de descubrimiento no están en la definición — search_commands, run_command y list_capabilities solo existen dentro del bucle del chat y no se pueden llamar por HTTP. Si se hubieran incluido, tu generador habría escrito tres métodos que nunca podrían funcionar.
Generación de código: un cliente tipado a partir de la definición
Ya tienes la definición; ahora genera código que funcione a partir de ella. `lg codegen` lee el documento OpenAPI y escribe un cliente de un solo archivo y sin dependencias: TypeScript (declaraciones de tipos más un envoltorio fino de llamadas) o PHP (una clase cliente con array shapes de PHPDoc). Sin `npm install`, sin composer: `fetch` en el lado de TypeScript, `ext-curl` en el lado de PHP.
La generación ocurre en TU máquina, no en nuestro servidor. No es una preferencia: fija la definición en tu repositorio una vez (`lg spec --out=...`) y el mismo comando se ejecuta en cada build sin red y sin token, así que tu CI nunca depende de nuestra disponibilidad. Y como el código generado es código que SE EJECUTA en tu ERP, tenerlo en tu repositorio en lugar de descargarlo de una API hace que cada cambio aparezca en `git diff`.
El cliente generado maneja correctamente las tres vías de Logistivo, y sabe cuál es cuál por el documento en lugar de adivinarlo: cada operación declara su vía en `x-logistivo.surface`. La vía de comandos desenvuelve el sobre `{success, data:{…}}`; un listado de sincronización REST NO lleva sobre y se devuelve tal cual (desenvolverlo eliminaría `next_cursor`); una escritura REST devuelve el propio cuerpo de producto del endpoint. Un generador de uso general no conoce esta distinción; el nuestro sí.
Los tipos no son suposiciones: la interfaz de argumentos de cada comando se genera a partir del mismo JSON Schema que ve el asistente. Lo obligatorio sigue siendo obligatorio, los enums se convierten en tipos unión y los objetos anidados en tipos anidados. En la práctica: si el servidor exige un campo, la llamada que lo olvida no falla con un 422 en producción, sino en tiempo de compilación.
En el archivo no se escribe ninguna marca de tiempo de generación: la misma definición con los mismos flags produce los mismos bytes. Por eso regenerar no hace ruido en `git diff`, y lo único que de verdad cambió (el contrato) sigue siendo visible.
1. Fija la definición — La definición se genera para tu rol; todas las operaciones que contiene se pueden llamar con ese token. Haz commit del archivo. lg login --api-key= lg spec --out=logistivo-openapi.json
2. Genera el cliente — Sale un solo archivo que lleva como método TODAS las operaciones de la definición que fijaste: los comandos que tu rol puede llamar, los endpoints REST que llevan el contrato de integración y los endpoints de descubrimiento. La cifra es la de TU rol, no el total de la plataforma: hoy una clave de cargador da 448 métodos de comando, una de transportista 452, una de agente de aduanas 312. Si generas a partir de la definición pública sin autenticación, el máximo es de 559 operaciones. lg codegen ts --from=logistivo-openapi.json --out=logistivo-client.ts lg codegen php --from=logistivo-openapi.json --out=LogistivoClient.php --namespace="Acme\\Logistivo" # or straight from the server, without downloading first: lg codegen ts --out=logistivo-client.ts
3. Verifica y luego úsalo — Si el código generado no compila, el fallo es nuestro, no tuyo: la integridad de la definición está protegida por una comprobación ejecutable en el servidor. npx tsc --noEmit --strict --target ES2022 --module ESNext --moduleResolution bundler logistivo-client.ts php -l LogistivoClient.php
Un método por operación — Cada comando del documento, cada endpoint REST que lleva el contrato de integración y los endpoints de descubrimiento. Si generas a partir de la definición de tu rol, obtienes solo lo que puedes llamar (448 comandos para un cargador); si generas a partir de la definición pública, obtienes las 559 operaciones. El día en que se añade un comando en el servidor, regenerar lo incorpora; no hay que esperar ninguna nueva versión del cliente.
Tipos de argumentos — El esquema `args` de cada comando se convierte en una interfaz (un array shape en PHP). Los campos obligatorios siguen siendo obligatorios y los enums se convierten en uniones. En TypeScript, olvidar un campo obligatorio es un error de compilación; en PHP, tu IDE y PHPStan ven la misma forma.
Clases de error — La taxonomía de transporte (`error_code`) y la de negocio (`error_key`) son campos separados; el control de confirmación y el límite de peticiones son tipos de error distintos. La unión de claves de error se mantiene abierta a valores desconocidos: cuando el servidor declara una clave nueva, tu código no deja de compilar, sino que cae en la rama `default`.
Una política de reintentos correcta — Los reintentos automáticos solo se aplican a las llamadas seguras: lecturas, y escrituras que llevan una clave de idempotencia. Que una escritura sin clave agote el tiempo de espera no significa «no se escribió nada», así que el cliente nunca la repite a ciegas. Ante un 429 espera el `Retry-After` del servidor en lugar de inventarse un retraso.
Los cuerpos de los resultados no están tipados — Los resultados de los comandos vuelven como `unknown` (`mixed` en PHP), por la misma razón que en la propia definición: la forma de los resultados es la salida de negocio del comando, no parte del contrato. Un tipo de resultado supuesto empezaría a mentir la primera vez que un campo se moviera.
El archivo generado no se edita a mano — Es una salida, no una fuente. Si necesitas un comportamiento adicional, envuelve la clase generada; todo lo que escribas dentro se pierde en la siguiente generación.
Las herramientas de descubrimiento no se generan — `search_commands`, `run_command` y `list_capabilities` solo viven dentro del bucle del chat y no se pueden llamar por HTTP; no están en la definición y, por tanto, tampoco en el cliente. Incluirlas habría supuesto escribir tres métodos que nunca funcionan.
Alcance honesto
Preferimos ampliar esta sección antes que reducirla. El valor de un contrato de integración está menos en lo que promete que en la claridad con la que dice lo que no hace.
La CLI se ejecuta en el contexto de un usuario de un tenant — Cada comando se ejecuta con la empresa y el rol del usuario cuyo token se presenta. Un modo de operador de plataforma (un modo administrativo que lee entre empresas) queda fuera de esta superficie y no se abrirá desde aquí.
Tu lista de comandos depende de tu rol — Una cuenta de cargador ve 448 comandos, un transportista 452, un agente de aduanas 312, un afiliado 55. Si falta un comando en tu catálogo, revisa primero el rol; si aparece pero se rechaza, revisa el alcance y el nivel de acceso de la clave. Las cuentas de conductor no tienen ningún acceso a esta superficie.
Algunos comandos gastan créditos — Las consultas arancelarias, la generación de documentos y algunos otros comandos basados en IA consumen del saldo de créditos de tu plan. Cada fila del catálogo lleva credit_cost {mode, credits}: fixed es el cargo exacto por llamada, read_only nunca cobra, y computed significa que el cargo depende de la llamada; entonces credits es null y la cifra real aparece en la tarjeta de confirmación. Una verificación previa (dry_run) te dice cuánto cobraría una llamada y si tu saldo lo cubre.
Las claves de integración no pueden manejar el chat del panel — El asistente de IA del panel es para personas. Iniciar o continuar una ejecución del asistente con una clave de integración se rechaza con 403; los agentes usan los endpoints de comandos, lg o el canal MCP, donde cada comando se ejecuta con el nivel de acceso de la clave y sus escrituras se registran como escrituras de integración.
El catálogo no sustituye a la API REST existente — La superficie REST que mueve las apps web y móviles de Logistivo se queda donde está y sigue sujeta a la regla de compatibilidad con versiones anteriores. El catálogo de comandos no sustituye al CRUD de recursos; es la capa de los VERBOS: la forma única y auditada de hacer una cosa.
Hoy los comandos de listado devuelven ventanas pequeñas — Hasta que un comando de listado anuncie cursor y updated_since en su esquema, su máximo es de 20 filas sin cursor. No está pensado para extraer una copia completa de tus datos; la sincronización incremental se está desplegando comando a comando.
Preguntas frecuentes
¿Para qué sirve Logistivo CLI?
Ejecuta el trabajo de tu cuenta de Logistivo desde una terminal, un script o tu propio agente de IA: cargas y viajes, solicitudes, ofertas y licitaciones, flota, conductores y sus gastos, documentos, contactos y cuentas corrientes, facturas y contabilidad, almacén y stock, miembros del equipo, aranceles HS y derechos antidumping. Cada acción de escritura del panel tiene un comando; los pagos, el consentimiento legal y el cierre de la cuenta se quedan deliberadamente en el navegador. Los mismos comandos se pueden llamar por HTTP para integraciones con ERP/CRM y a través del canal MCP.
¿Cómo se nombran los comandos en Logistivo CLI?
La forma es lg --parameter=value. El dominio es una entidad en plural (loads, demands, invoices, export-documents) y el verbo sale de un vocabulario cerrado que solo crece por decisión deliberada (list, get, create, update, search, set-status, generate, etc.). Todos los verbos de una entidad viven en un mismo dominio, y el par (dominio, verbo) es único en todo el catálogo.
¿Cómo me autentico en la CLI?
De forma interactiva, lg login muestra un código de aprobación que confirmas en tu navegador después de iniciar sesión en Logistivo: no se escribe ninguna contraseña ni clave en la terminal, y la sesión sigue iniciada y se renueva sola hasta que ejecutes lg logout. lg login --password (correo y contraseña) sigue disponible como alternativa de respaldo. En servidores y en CI, usa una clave de integración emitida en el panel o con lg keys create: lg login --api-key la guarda en un perfil local, o bien ponla en la variable de entorno LOGISTIVO_TOKEN. Por HTTP, el token viaja en la cabecera Authorization: Bearer.
¿Puedo crear una cuenta de servicio para mi integración con el ERP?
No. Una integración se conecta con el token de un usuario real de la empresa creado en el panel. Una identidad sintética sin empresa deja inerte el aislamiento multi-tenant, vacía de sentido la columna «quién ejecutó esto» del registro de auditoría y deja un puente que no se calla cuando su dueño se va. El patrón correcto es un usuario dedicado con un rol restringido y un responsable con nombre y apellidos.
¿Tiene Logistivo un entorno de pruebas (sandbox)?
Sí, y es de autoservicio: se abre un tenant sandbox separado para tu empresa, con el mismo código, el mismo catálogo de comandos y su propio registro de créditos. El entorno se deduce de la empresa de la clave y no se puede indicar en la petición; una llamada hecha con el perfil equivocado se detiene en el servidor con 403 ENVIRONMENT_MISMATCH. Una solicitud que abras en el sandbox nunca llega a transportistas reales, un evento del sandbox nunca se entrega a tu suscripción de webhooks live y tu saldo live no se mueve. Endpoints: POST /api/common/integration-sandbox (abrir), POST /api/common/integration-sandbox/keys (clave), GET /api/common/integration-sandbox/go-live (lista de comprobación para pasar a producción). En el lado de lg, lg --sandbox y lg --live son selectores de perfil para una sola ejecución.
¿Cómo leo la salida de lg --json en un script?
La salida es el sobre HTTP completo: { "success": bool, "data": { "contract_version", "command", "status", "result" }, "code", "message" }. La carga útil de negocio está bajo .data.result; en los comandos de listado, las filas son .data.result., el recuento es .data.result.count y la página siguiente es .data.result.next_cursor. Así que la ruta jq correcta tiene este aspecto: lg loads list --json | jq -r '.data.result.loads[].load_code'. Una ruta que se salta el sobre no da error: devuelve null en silencio, y en un script de vigilancia eso se convierte en una alarma que nunca deja de sonar. La única excepción es /api/public/status, cuyo cuerpo no lleva sobre a propósito.
Si envío la misma petición dos veces, ¿obtengo registros duplicados?
No, si enviaste un idempotency_key. Una segunda llamada con la misma clave no vuelve a ejecutar el comando; devuelve el primer resultado con el estado replayed. La clave debería ser un UUID y debe ser la MISMA en todos los reintentos: generar una clave nueva en cada intento equivale a no usar idempotencia.
¿Qué hace --yes?
Supera el control de confirmación. Cuando se llama a un comando con control sin --yes, no cambia nada: el servidor resume en una frase lo que va a hacer, indica si es irreversible y se detiene (HTTP 409, código de salida 4 en la CLI). Al repetir el comando con --yes se realiza el trabajo.
¿Cómo detecto en un script que un comando ha fallado?
Lee el código de salida, nunca el texto del mensaje: 0 éxito, 1 rechazo por regla de negocio, 2 error de comando o de argumento, 3 error de autenticación o de rol, 4 confirmación requerida. Por HTTP, los equivalentes son 200, 422, 404, 403 y 409, y el campo error_code del cuerpo es estable. El MENSAJE de error está localizado y cambia sin aviso.
¿Cómo descubro los comandos disponibles de forma programática?
GET /api/public/cli/catalog para el descubrimiento sin autenticación, y GET /api/common/commands para la lista que tu cuenta puede ver realmente. Ambos devuelven los parámetros en JSON Schema de cada comando; construye tu cliente a partir de ellos en lugar de codificar a mano una lista de comandos.
¿Tengo que actualizar mi cliente cuando se añade un comando nuevo?
No. El cliente obtiene su lista de comandos del catálogo, así que un comando añadido en el servidor aparece sin una nueva versión del cliente. Solo hace falta actualizar ante un cambio incompatible que sube la versión del contrato, y en ese caso la forma antigua sigue viva durante al menos seis meses.
¿La CLI sustituye a la API REST existente?
No. La superficie REST que mueve las apps web y móviles sigue en su sitio. El catálogo de comandos no sustituye al CRUD de recursos; es la capa de los verbos: la forma única, con control de rol, con control de confirmación y auditada de realizar una acción.
¿Cómo obtengo una clave de API de Logistivo y qué puede hacer?
La emite un responsable con permiso de gestión del equipo en el panel, en Settings › Integration keys, o desde una terminal con lg keys create. La clave actúa en nombre de un miembro real del equipo y tiene tres ajustes independientes: el alcance (read abre el catálogo y los comandos que no escriben; write abre todos los comandos, y el control de confirmación se mantiene igual), permisos opcionales por dominio y un nivel de acceso: employee, el predeterminado, para la operativa diaria, o manager para equipo, configuración, claves y dinero. Se muestra una sola vez y no se guarda en el servidor; se puede rotar, transferir y revocar. Cuando el miembro en cuyo nombre actúa se va, la clave también se cierra. No existe la cuenta de servicio.
¿Qué pasa si reutilizo una clave de idempotencia para otro comando?
El servidor responde 409 idempotency_conflict e indica el comando para el que se usó la clave por primera vez; no se ejecuta nada y no se repite nada. Las claves están acotadas a tu empresa, vinculadas a un comando y bloqueadas durante 24 horas; después, la misma clave inicia una ejecución nueva.
¿Cómo se aplican los límites de peticiones a mi integración?
Por token y por minuto, en tres grupos: lecturas del catálogo 120, comandos de lectura 120, comandos de escritura 30. Un 429 siempre lleva Retry-After y un cuerpo con retry_after, limit y bucket; espera ese tiempo y reintenta. El catálogo publica las cifras actuales en rate_limits.
¿Cómo distingo un rechazo de negocio de un error de transporte?
Ramifica primero según error_code: failed (422) es un rechazo de negocio y lleva un error_key estable como INSUFFICIENT_CREDITS o NOT_FOUND; server_error (5xx) y los errores de red se reintentan con la misma clave de idempotencia; ante rate_limited (429) se espera. Nunca ramifiques según el texto del error.
¿Envía Logistivo webhooks? ¿Para qué eventos?
Sí. Registras una dirección https y eliges los eventos que te interesan; cuando ocurren, llega un POST firmado. Hoy se puede suscribir a 13 eventos: carga creada/cambio de estado/conductor asignado, solicitud creada y cambio de estado, oferta presentada/revisada/aceptada, factura en borrador/emitida/anulada, y reserva de almacén creada/cambio de estado. Cada nombre está respaldado por una clase de evento que realmente se despacha: nada se anuncia para luego no dispararse nunca, porque un evento así es un fallo silencioso que el integrador espera para siempre. Las suscripciones se crean en Settings › Integration › Webhooks, o desde una terminal con lg webhooks create.
¿Cómo verifico la firma de un webhook de Logistivo?
Cada petición lleva una cabecera X-Logistivo-Signature: t=,v1=. La cadena firmada es «.», el algoritmo es HMAC-SHA256 y la clave es el secreto de la suscripción. Cuatro reglas: (1) verifica los bytes EN BRUTO: decodificar y volver a serializar el cuerpo (JSON.stringify / json_encode) convierte los mismos datos en bytes distintos y la firma deja de coincidir; es el error más común; (2) comprueba la marca de tiempo y descarta todo lo que cumpla |now − t| > 300 s aunque la firma sea correcta; (3) compara en tiempo constante con hash_equals / timingSafeEqual; (4) deduplica por event_id, no por el id de entrega: event_id se conserva en un reenvío, mientras que el id de entrega cambia. En el repositorio, en examples/webhook-receiver/, hay receptores para Node y PHP que funcionan y se prueban a sí mismos con --selftest.
¿Qué pasa si un webhook no se puede entregar? ¿Pierdo el evento?
No. Si tu receptor no devuelve 2xx, la entrega entra en el calendario de reintentos: 60 · 300 · 1800 · 7200 · 21600 segundos, 6 intentos en total, una ventana de aproximadamente 8,6 horas. Se reintenta CUALQUIER fallo salvo 410 Gone, incluidos los 4xx: perder un evento de negocio cuesta más que unas pocas peticiones de más. Tras 10 entregas agotadas consecutivas, la suscripción se silencia y se registra el motivo, así que la pregunta «¿por qué no llega nada?» sigue teniendo respuesta. El registro de entregas guarda cada intento (código de estado, duración, error) y puedes reenviar una sola entrega desde el panel o con lg webhooks replay. La sincronización incremental (updated_since + cursor) sigue ahí como red de seguridad.
¿Puede mi agente de IA hacer todo lo que un usuario puede hacer en el panel?
Casi todo. Cada acción de escritura del panel tiene un comando (medido contra los endpoints de escritura del panel, el 100 % de los que entran en el alcance está cubierto), y los mismos comandos están abiertos a lg, a HTTP y al canal MCP. Las excepciones deliberadas son los pasos de identidad y de dinero: iniciar sesión, comprar un paquete, añadir una tarjeta con 3D Secure, aprobar textos legales y cerrar una cuenta se quedan en el navegador de la persona, y lg handoff-links generate devuelve el enlace para ellos. Las claves de integración, los webhooks y el sandbox se gestionan con comandos integrados de lg porque devuelven secretos una sola vez.
¿Puedo pasar archivos, como PDF o fotos, a los comandos desde la CLI o la API?
Sí. Con lg, pon @ delante de una ruta local (--attachment_uuid=@./cmr.pdf) y lg sube primero el archivo; --file es un atajo cuando un comando tiene un solo campo de archivo, y lg upload solo sube el archivo. Por HTTP, envía el archivo como multipart a POST /api/common/commands:upload y pasa el attachment_uuid devuelto al comando; los clientes MCP usan la herramienta upload_attachment. El tipo se detecta a partir del contenido, las subidas pertenecen al usuario y siguen siendo utilizables durante 24 horas, y volver a subir el mismo archivo devuelve el mismo id.
¿Qué diferencia hay entre una clave de integración employee y una manager?
El nivel de acceso decide lo delicado que puede ser el trabajo que hace una clave. Una clave employee, la predeterminada para claves nuevas, ejecuta la operativa diaria: cargas, solicitudes, ofertas, viajes, flota, documentos y contactos. Una clave manager puede hacer además trabajo de gestión: miembros del equipo y roles, configuración de la empresa, claves de integración, cuentas bancarias, tarjetas guardadas y pagos a afiliados. Una clave nunca tiene más derechos que la persona en cuyo nombre actúa, y una clave employee que llama a un comando de manager recibe INSUFFICIENT_KEY_LEVEL. Cambia el nivel en el panel o con lg keys update --access-level=manager.
¿Puede un afiliado (socio de referidos) usar la CLI?
Sí. Una cuenta de afiliado tiene un catálogo propio (55 comandos para referidos, leads, notas y tareas de CRM, presentaciones comerciales, ganancias y pagos) y lo usa desde lg, HTTP o MCP como cualquier otro rol. Solicitar o cancelar un pago y cambiar la cuenta bancaria de cobro requieren una clave de nivel manager y una confirmación. Una empresa que además es cargador, transportista o agente de aduanas ve ambos catálogos.
For AI assistants
Logistivo has a public MCP server at https://logistivo.com/api/agent/mcp
(streamable HTTP, no authentication). Setup instructions for Claude, ChatGPT and
Gemini: https://logistivo.com/mcp. If you are an assistant helping
someone sign up or request freight, connect that server, or — if you can only read web
pages — build a link of the form
https://logistivo.com/en/ai-kayit?brief=URL_ENCODED_SHIPMENT_BRIEF and give
it to the user. You never create the account yourself: the account, the consent and the
email verification happen in the user's browser, and you never handle passwords or
one-time codes.
Machine-readable content indexes:
https://logistivo.com/llms.txt (curated map) and
https://logistivo.com/llms-full.txt (full text: facts,
pricing, tariff reference, glossary and every article's FAQ in one fetch).
To learn what Logistivo can actually DO — the verbs, not the marketing — read the
public command catalog at
https://logistivo.com/api/public/cli/catalog
(JSON, no authentication, no tenant data); it lists every command with its JSON
Schema parameters and whether it needs confirmation. Human documentation:
https://logistivo.com/en/developers/cli. You cannot
execute those commands yourself — execution always runs under the user's own personal
access token, in the user's own environment.