Logistivo CLI: run your logistics operation from a terminal and from your ERP

One command catalog feeds three surfaces: the lg terminal client, the AI assistant inside the dashboard, and the channel external AI assistants connect to. A capability is written once and appears in all three. This page is a contract. The command table below is not hand-written; it is generated from the live command registry on every request.

What is the Logistivo CLI?

The Logistivo CLI (lg) is a command line client that runs the freight, demand, bid, export-document, stock, invoice and customs-tariff operations of your Logistivo account from a terminal or a script. The commands are not baked into the client: the client pulls the command catalog from the server and draws itself from it. The same commands can be called over HTTP without installing anything — that is the path ERP and CRM integrations use.

What is live today, and what is on the way

This section sits at the top of the page on purpose. The most expensive mistake an integration document can make is to describe an endpoint that is not open yet as if it were: the integrator writes the code, the endpoint returns 404, and trust does not come back.

Because the contract is frozen, the integration code you write today will keep working as the remaining pieces open.

What makes this different: the client knows no commands, it draws them

This is the single decision that makes the rest of the page meaningful. In an ordinary CLI the commands live inside the client; in Logistivo they live on the server.

In the classic arrangement, when the server gains a capability the client needs a new release and the user needs to install it. In between, the two sides know different things — and that is the quietest failure mode in integrations: the script runs, the exit code is 0, and the command simply does not describe what the server can do.

In Logistivo a command's definition is a single record: its name, what it does, its JSON Schema parameters, which roles may see it, whether it needs confirmation and whether its effect is reversible. When lg starts it pulls that catalog and generates its help text, its flags and its input validation from it. The moment a command is added on the server, lg knows it — with no client update.

The same catalog feeds the AI assistant in the dashboard and the channel external AI assistants connect to. A capability is written once and appears in three places — and all three pass through the same role gate, the same confirmation gate and the same audit ledger. There is no separate CLI command inventory; if there were, the three surfaces would quietly diverge within six months.

The naming rule — how command names grow

The catalog will grow. New commands are not named ad hoc; six rules are applied. We publish them here because these are the names your integration will be writing for years, and their predictability is worth something to you.

Install and identity

lg is a single-file, dependency-free Node script (Node 18+). It was written that way so it can be copied onto a customer's ERP server as one file: a client that needs npm install never gets there. The client is in early access and the download link will be added to this section when it opens. You do not have to wait for it to build an ERP/CRM integration — the same commands are available over HTTP.

1. Log in — lg login asks for your email and password, writes the returned access token to ~/.logistivo/config.json and fetches the catalog straight away. If email verification is enabled on your account it asks for the code here too — skipping that step would leave you holding a token while every protected endpoint refuses it.

2. For servers and CI: a token, not a password — Never use lg login in a non-interactive environment. Create a user dedicated to the integration in the panel, give it a narrow role, and put its personal access token in the LOGISTIVO_TOKEN environment variable. While that variable is set the config file is never read. That user must have email verification switched off: an integration that mails a code to an inbox nobody watches stops on every restart.

3. Verify and explore the catalog — lg commands lists every command your role can see, grouped by domain; lg help prints that domain's verbs, and lg help prints one command's full parameter list with types and which ones are required. None of that text lives inside the client — all of it comes from the catalog.

Never put the token in version control, a CI log or a chat window. lg logout deletes only the LOCAL copy — the token stays valid on the server, and permanent revocation happens in the panel. The audit ledger stores your arguments but masks fields whose key contains token, password, IBAN, card or OTP as ***.

The command model

There is one grammar and it has no exceptions. To know how to call a command, the only thing you need is what the catalog says about it.

lg loads list --status=in_transport --limit=20 --json

Flag names are schema names and may contain underscores (--load_code, --amount_per_vehicle). That is deliberate: seeing a flag tells you which JSON field it lands in, so moving from the CLI to HTTP requires no name translation. A boolean parameter written without a value is true (--only_open); the opposite is --no-only_open. Write an argument whose value starts with a dash as --flag=value, otherwise a forgotten flag silently swallows the next one as its value.

Real examples

Every command below exists in the catalog today; no name or parameter here is invented. Outputs are abbreviated.

Without the client: the HTTP command API

lg is a convenience, not the door. Catalog and execution both go through three HTTP endpoints; an ERP or CRM integration connects here directly. Identity is a personal access token carried in Authorization: Bearer.

Asking for confirmation with 200 + ok:false is forbidden and will never happen. The reason is simple: clients treat 200 as success, so a confirmation request returned as 200 would kill the flow silently and nobody would notice. Confirmation is always 409.

The confirmation gate and irreversible commands

Every command in the catalog carries two flags: confirmation_needed (does it require explicit approval before running) and irreversible (can its effect be undone). They are separate questions, and both are enforced on the server rather than left to the client's good manners.

The gate is about responsibility, not about business rules. Placing a bid is the first step toward a freight contract; issuing an invoice creates an accounting entry; a stock movement changes a ledger. None of these should ever be something you can run twice by accident.

The gate is read from the EFFECTIVE command. When one command wraps another — as the generic executor in the chat does — the gate comes from the flags of the command that will actually run, not from the wrapper. With a fixed flag one of two failures would be inevitable: either the invoice command would run unconfirmed, or every country lookup would raise a confirmation card.

read_only and ungated are not the same thing. There are three distinct states: invoices preview is ungated and writes nothing; loads create is gated and writes; invoices create is ungated but writes — a draft comes into being. One test settles it: when the command returns, has a row in the database changed?

It is technically possible for an integration to pass the gate automatically on every call, but it is not advisable. The right pattern is to automate the gate only for commands you know to be reversible, and to route irreversible ones into a human's queue.

Idempotency: why retrying does not create duplicates

An ERP does not read your error message, does not see your screen, and will resend the same request after a timeout. This section exists for exactly that behaviour.

A call carrying an idempotency_key runs at most once. The second call does not re-execute the command; it returns the recorded result with status replayed. When the network drops, when a request times out, or when a queue picks up the same job twice, you get the first result instead of a duplicate invoice.

Use a key on every writing command. The catalog's read_only field gives you that distinction for free: every command with read_only: false deserves an idempotency key.

Your retry strategy should use exponential backoff and carry the SAME key on every attempt. Generating a fresh key per attempt is the same as not using idempotency at all.

Errors and exit codes

What a machine branches on is a stable string. The text in the error field targets a human, is localised, and changes without notice — an integration that branches on message text is not supported, and its breaking is not a bug.

An honest gap: the business error inside failed is free text today. A machine cannot tell "insufficient stock" from "contact not found". Adding a stable error_key to command results is planned; until then, branch only at the error_code level.

Command identity table

The table below is not hand-written: it is generated from the live command registry every time this page is served. A command added on the server appears here on its own. The "Gate" column tells you whether a command asks for confirmation and whether its effect can be undone; the "Roles" column tells you which account types will find it in their catalog.

The API name (list_loads) is frozen and will not change; it is the name you use in HTTP calls. The CLI identity (loads list) is governed by the versioning policy: once announced it changes only with a version bump and a migration window, during which the catalog serves the old pair as an alias. The descriptions here come from each command's own record and are shortened — for the full text, parameter types and enum values, read the catalog endpoint or run lg help .

ERP and CRM integration — Identity: no service accounts, a real user instead

An ERP or CRM connects to Logistivo as a real company user holding a personal access token minted from the panel. A synthetic service account — no company, exempt from scoping, nobody responsible for it — is never created.

This is architecture, not preference. Multi-tenant isolation rests entirely on the user's company; for an identity with no company the isolation scope becomes inert, and one wrong query on that token reads data that does not belong to it. The second reason is audit: the user column in the ledger ties "who ran this" to a person; a service account makes that column meaningless and leaves an invoice-issuing integration with no owner. The third is revocation: if a token belongs to a person, the integration falls silent when that person leaves. An ownerless bridge is the bridge that keeps writing quietly for years.

ERP and CRM integration — Versioning and deprecation

The catalog response carries a contract_version integer; command rows carry since, deprecated_at and replaced_by. The contract version rises only on breaking changes.

ERP and CRM integration — Stable identifiers: never hand an auto-increment id to your ERP as a key

Internal auto-increment ids are opaque and tenant-scoped: another company's valid id returns "not found" to you, not data. But being opaque does not make them business keys. What an ERP stores in its own record has to be a business key.

ERP and CRM integration — Pagination, filtering and incremental sync

Today list commands take limit (ceiling 20) and return count. That is enough for a human conversation and not enough for a nightly sync. The contract commits to this:

ERP and CRM integration — Rate limits

The limit key is the token, not the IP: an ERP arrives from behind a single NAT, and an IP-based limit would count a whole company as one user.

ERP and CRM integration — Things we will not do

This is often the most useful part of a contract: knowing what will never arrive lets you design around it.

The machine-readable catalog

This page was written for people. For an AI assistant or an automated client, the same information exists as a structured, unauthenticated copy.

GET /api/public/cli/catalog requires no authentication and returns the public identity of the commands: the frozen API name, the CLI domain/verb identity, the description, the JSON Schema parameters, and the read_only, confirmation_needed and irreversible flags. It returns no personal data, no tenant data and no sample records — only what the surface is.

The right way for an external agent to use it: read the catalog, explain in YOUR OWN words which jobs are possible, and when execution is needed, point the user at running it in their own environment with their own token. The agent never asks for, generates or relays a user's token.

Connecting Logistivo to an AI assistant for signup and freight requests is a separate channel with its own page:

Honest scope

We would rather grow this section than shrink it. The value of an integration contract lies less in what it promises than in how clearly it states what it does not.

Frequently asked questions

What is the Logistivo CLI used for?

It runs the operational work in your Logistivo account — listing and reading loads, seeing open freight demands, placing bids, moving a load's status forward, assigning drivers, preparing export documents, recording stock movements, issuing invoices, looking up HS tariffs and anti-dumping duties — from a terminal or a script. The same commands are callable over HTTP for ERP/CRM integrations.

How are commands named in the Logistivo CLI?

The shape is lg --parameter=value. The domain is a plural entity (loads, demands, invoices, export-documents) and the verb comes from a closed vocabulary (list, get, create, search, set, issue, generate and so on). Every verb of one entity lives in one domain, and the (domain, verb) pair is unique across the whole catalog.

How do I authenticate to the CLI?

With a personal access token minted from the Logistivo panel. lg login asks for the token and writes it to a local config file; in scripted environments set the LOGISTIVO_TOKEN environment variable instead. Over HTTP the token travels in the Authorization: Bearer header.

Can I create a service account for my ERP integration?

No. An integration connects with the token of a real company user created in the panel. A synthetic identity with no company makes multi-tenant isolation inert, makes the "who ran this" column in the audit ledger meaningless, and leaves a bridge that does not fall silent when its owner leaves. The right pattern is a dedicated user with a narrow role and a named owner.

If I send the same request twice, do I get duplicate records?

Not if you sent an idempotency_key. A second call with the same key does not re-run the command; it returns the first result with status replayed. The key should be a UUID and must stay the SAME across retries — generating a fresh key per attempt is the same as not using idempotency.

What does --yes do?

It passes the confirmation gate. When a gated command is called without --yes nothing changes: the server summarises what it is about to do in one sentence, says whether it is irreversible, and stops (HTTP 409, CLI exit code 4). Repeating the command with --yes performs the work.

How do I detect a failed command in a script?

Read the exit code, never the message text: 0 success, 1 business rule rejection, 2 command or argument error, 3 authentication or role error, 4 confirmation required. Over HTTP the equivalents are 200, 422, 404, 403 and 409, and the error_code field in the body is stable. The error MESSAGE is localised and changes without notice.

How do I discover the available commands programmatically?

GET /api/public/cli/catalog for unauthenticated discovery, and GET /api/common/commands for the list your account can actually see. Both return each command's JSON Schema parameters; draw your client from them rather than hard-coding a command list.

Do I have to update my client when a new command is added?

No. The client pulls its command list from the catalog, so a command added on the server appears without a new client release. An update is needed only for a breaking change that raises the contract version, and in that case the old shape stays alive for at least six months.

Does the CLI replace the existing REST API?

No. The REST surface that powers the web and mobile apps stays in place. The command catalog does not replace resource CRUD; it is the verbs layer — the single, role-gated, confirmation-gated and audited way to perform an action.

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.