Unofficial CLI for Dolibarr ERP — full REST API coverage from your terminal.
Requires Node.js 20+ and npm.
npm install -g https://github.com/VidGuiCode/dolibarr-cli/releases/download/v0.2.6/dolibarr-cli-0.2.6.tgz
dolibarr --version
dolibarr config initThis installs the dolibarr command as a normal npm global CLI. It does not require sudo, does not install a system service, and does not modify system configuration.
On Windows PowerShell, dolibarr may resolve to npm's .ps1 shim and be blocked by the execution policy. Use dolibarr.cmd from PowerShell, or run dolibarr from cmd.exe / a shell that resolves the .cmd shim.
On Linux and macOS, avoid sudo npm install -g for this CLI. If npm global installs fail with permission errors, use a user-level Node.js setup such as nvm or fnm, or configure npm's global prefix to a user-owned directory.
Or for development:
git clone https://github.com/VidGuiCode/dolibarr-cli.git
cd dolibarr-cli
npm install
npm run build
npm linkOnce installed, the CLI can upgrade itself from GitHub Releases:
dolibarr upgrade # show installed + latest version (checks GitHub live)
dolibarr upgrade check # fetch + cache the latest release info from GitHub
dolibarr upgrade install # download + install the latest .tgz via npm install -gdolibarr upgrade performs a best-effort live check against GitHub and falls back to the last cached result when offline, so "Latest" reflects new releases immediately. Self-update works on Windows, macOS, and Linux (the installer runs through the platform shell so npm.cmd resolves correctly on Windows).
Every dolibarr command also prints a one-line reminder to stderr when a newer version is available (cache refreshed at most once every 24h). The reminder is suppressed automatically for piped / --json / non-TTY output, and can be turned off entirely:
export DOLIBARR_NO_UPDATE_CHECK=1dolibarr config initEnter your Dolibarr instance URL and API key. The CLI tests the connection before saving.
Your API key is stored at ~/.config/dolibarr-cli/config.json. Treat this file as a secret and do not share or commit it.
For CI, containers, or scripts where you do not want a saved config file, set both environment variables instead:
export DOLIBARR_URL="https://your-dolibarr.example.com"
export DOLIBARR_API_KEY="your-api-key"Environment variables are supplied by your shell, CI system, or container runtime. The CLI reads them but does not create an .env file.
Getting an API key: In Dolibarr, go to Users & Groups > [your user] > API tab > Generate key. Or ask your admin to create a dedicated API user.
# Check connection
dolibarr status
# Thirdparties (customers & suppliers)
dolibarr thirdparties list
dolibarr thirdparties list --supplier
dolibarr thirdparties get 5
dolibarr thirdparties create --name "Acme Corp" --supplier --dry-run
# Customer invoices
dolibarr invoices list --status 2 --output json
dolibarr invoices get 12
dolibarr invoices get FA2501-0001 # look up by ref
dolibarr invoices update 12 --date 2025-06-15 --socid 4 --due-date 2025-07-15 # re-date / re-assign
dolibarr invoices update-line 12 34 --subprice 40 --qty 2 # edit a draft line; totals recompute
dolibarr invoices validate 12
dolibarr invoices pay 12 --amount 500.00 --date 2025-12-01 --payment-type CB # or a numeric id
dolibarr invoices unpay 12 # reverse a paid invoice back to unpaid
dolibarr invoices set-draft 12 # send a validated invoice back to draft
dolibarr invoices payments 12 # list payments on an invoice
dolibarr invoices create-from-order 45
dolibarr invoices credit-notes list
dolibarr invoices contacts add 12 7 BILLING
# Supplier invoices
dolibarr supplier-invoices list --thirdparty 3
dolibarr supplier-invoices get 7
dolibarr supplier-invoices update 7 --date 2025-03-01 --ref-supplier INV-2025-03 # re-date a purchase invoice
# Bank
dolibarr bank list
dolibarr bank transactions 1
dolibarr bank add-transaction 1 --date 2026-05-05 --type VIR --label "Bank fee" --amount -3.50
dolibarr bank update-transaction 1 240 --label "Corrected label" # only the label is API-editable
dolibarr bank transfer --from 1 --to 2 --amount 100.00 --date 2026-05-05 --description "Internal transfer"
# Customer orders
dolibarr orders create-from-proposal 9
dolibarr orders update-line 42 310 --qty 3 # edit a draft order line; totals recompute
dolibarr orders contacts list 42
dolibarr orders reopen 42
# Product variants (needs the Products module + API-user product rights)
dolibarr products attributes create --ref COL --label Color
dolibarr products variants create 42 --price-impact 5 --feature 1:3 --feature 2:7
dolibarr products subproducts add 42 88 --qty 2
dolibarr products purchase-prices set 42 --supplier 3 --buyprice 12.50 # upserts by supplier
dolibarr products multiprices show 42 --by segment
dolibarr products stock-movements --product 42
dolibarr products correct-stock 42 --warehouse 1 --qty -3 --dry-run # preview; mutates inventory when run
# Categories & links
dolibarr categories link 12 customer 3 # link thirdparty 3 to category 12
dolibarr categories of-object customer 3 # categories a thirdparty belongs to
dolibarr thirdparties categories list 3
dolibarr thirdparties representatives add 3 8
dolibarr setup extrafields --type societe
# Supplier orders (path fixed in v0.3.4)
dolibarr supplier-orders list
dolibarr supplier-orders make-order 8 --date 2025-06-15
dolibarr supplier-orders receive 8 --close
# Proposals / supplier-invoice line editing
dolibarr proposals update-line 15 220 --qty 4
dolibarr supplier-invoices update-line 7 88 --subprice 42 # maps to pu_ht; totals recompute
# Thirdparty banking (RIB / SEPA / gateways)
dolibarr thirdparties bank-accounts list 3
dolibarr thirdparties bank-accounts create 3 --label Main --iban LU28... --bic BCEELULL --rum RUM-0001
dolibarr thirdparties outstanding 3 --mode supplier # unpaid purchase invoices for a supplier
# Accounting
dolibarr accounting ledger --period currentyear --format CSV
# Products
dolibarr products list --type service
dolibarr products create --label "Consulting" --price 150.00 --type service
# Documents
dolibarr documents list --module facture --ref FA2501-0001
dolibarr documents upload --module facture --ref FA2501-0001 --file ./scan.pdf
dolibarr documents download --module facture --file invoices/FA2501-0001/scan.pdf --output scan.pdf
# Setup
dolibarr setup modules
dolibarr setup company
dolibarr setup conf MAIN_INFO_SOCIETE_NOM
# Projects
dolibarr projects list --status 1
dolibarr projects get PJ2501-001 # ref-lookup
dolibarr projects tasks 12 --with-timespent
# Tickets
dolibarr tickets list --thirdparty 5
dolibarr tickets get --track-id abc123def456
dolibarr tickets reply abc123def456 --message "Looking into this now."
# Contracts
dolibarr contracts list --thirdparty 5
dolibarr contracts validate 12
dolibarr contracts activate-line 12 42 --date-start 2026-01-01
# Shipments & receptions
dolibarr shipments create --socid 5 --order 123 --date 2026-01-15
dolibarr shipments validate 7 --no-trigger
dolibarr receptions close 3
# Interventions (fichinter)
dolibarr interventions list --thirdparty 5
dolibarr interventions create --socid 5 --description "On-site repair" --date 2026-03-01
dolibarr interventions add-line 12 --description "Diagnostics" --hours 1.5
dolibarr interventions validate 12
# Expense reports
dolibarr expensereports list --user 2
dolibarr expensereports create --user 2 --date-start 2026-03-01 --date-end 2026-03-31
dolibarr expensereports set-status 4 --status approved --confirm
dolibarr expensereports payments list
# Members
dolibarr members list --type 1
dolibarr members by-email member@example.com
dolibarr members subscriptions add 7 --start 2026-01-01 --end 2026-12-31 --amount 50
dolibarr members types list
# Stock & warehouses
dolibarr stock warehouses list
dolibarr stock warehouses create --label "Main depot" --location "Aisle 1"
dolibarr stock movements list --product 12
# Same endpoint as `products correct-stock`, warehouse-first — guarded, so preview first:
dolibarr stock movements create --product 12 --warehouse 1 --qty -3 --dry-run
# Supplier proposals (price requests)
dolibarr supplier-proposals list --thirdparty 8
dolibarr supplier-proposals create --socid 8 --date 2026-02-01 --ref-supplier SUP-77
dolibarr supplier-proposals lines 4
# Tasks & time spent
dolibarr tasks list --project 3 --with-timespent
dolibarr tasks create --ref T1 --label "Design" --project 3 --workload-hours 3
# Time spent wants a datetime; pass a plain date and the CLI converts it:
dolibarr tasks timespent add 9 --date 2026-03-01 --hours 1.5
# Agenda (calendar events)
dolibarr agenda list --user 2
dolibarr agenda create --label "Client call" --start 2026-04-01 --type AC_RDV
# Multi-currency & knowledge base
dolibarr multicurrencies list
dolibarr multicurrencies set-rate 2 --rate 1.08 --dry-run
dolibarr knowledge list
dolibarr knowledge create --question "How do I reset?" --answer "Click reset."
# MRP — bills of materials & manufacturing orders
dolibarr mrp boms list
dolibarr mrp boms add-line 3 --product 7 --qty 2
dolibarr mrp mos create --product 5 --qty 100 --bom 3 --date-start 2026-05-01
dolibarr mrp workstations list # read-only
# MO production is intentionally not wrapped (it irreversibly consumes stock):
dolibarr raw POST mos/12/produceandconsumeall --data '{}'
# Raw API (escape hatch)
dolibarr raw GET /thirdparties
dolibarr raw POST /invoices --data '{"socid": 1}'
dolibarr raw PUT /thirdparties/5 --data '{"fournisseur": 1}'
dolibarr raw POST /invoices --data-file body.json
# Convert YYYY-MM-DD body fields to the Unix epoch Dolibarr wants — no hand-computing:
dolibarr raw PUT /supplierinvoices/18 --data '{"date":"2026-03-01"}' --date dateWindows / Git Bash (MSYS) note: Git Bash rewrites a leading-slash argument like
/thirdpartiesinto a Windows path (C:/Program Files/Git/thirdparties) before the CLI ever sees it, which Dolibarr rejects. The CLI now detects and un-mangles this automatically (printing a one-line notice). To avoid it entirely, either drop the leading slash (dolibarr raw GET thirdparties) or setMSYS_NO_PATHCONV=1for the session.
All list and get commands support --output <format> where format is table (default), json, or csv. --json is kept as a back-compat alias for --output json.
dolibarr invoices list # table (default)
dolibarr invoices list --output json # JSON
dolibarr invoices list --json # JSON (shorthand)
dolibarr invoices list --output csv # CSV (RFC 4180, raw field keys as headers)--compact only changes JSON indentation. It does not select JSON output by itself; use --json --compact or --output json --compact.
dolibarr bank list shows bank account metadata. Dolibarr's account-object balance / solde fields may be stale or zero on some server versions, so they are omitted from bank list table, JSON, and CSV output. For reconciliation, use dolibarr bank transactions <account-id> or raw /bankaccounts/{id}/lines output and sum transaction lines independently.
Pick exactly the columns you want, using the raw Dolibarr field keys. Works across all three output formats.
dolibarr invoices list --fields id,ref,total_ttc
dolibarr invoices list --fields id,ref,status --output csv > invoices.csv
dolibarr thirdparties get 5 --fields id,name,email,town --output jsonWith --fields, values pass through raw — e.g. --fields status emits the numeric code (0 / 1 / 2) rather than the mapped label (Draft / Validated / Paid). Missing keys render as empty strings.
Command flags such as create --date and pay --date accept YYYY-MM-DD and convert it to the Unix epoch (seconds) Dolibarr stores. When you need a date inside a raw request body, pass --date <keys> to convert the named body fields for you, so you never have to hand-compute a timestamp:
dolibarr raw PUT /supplierinvoices/18 --data '{"date":"2026-03-01"}' --date dateDate-only values are interpreted as UTC midnight. get views already render stored epoch dates back as YYYY-MM-DD.
get accepts a human ref in place of a numeric id for resources whose Dolibarr API exposes /ref/{ref} — invoices, orders, proposals, categories, projects, and tickets. All-digit input is still treated as an id. Tickets also support public track ID lookup via --track-id.
dolibarr invoices get FA2501-0001
dolibarr orders get CO2501-0042
dolibarr proposals get PR2501-0007
dolibarr projects get PJ2501-001
dolibarr tickets get TICKET-001
dolibarr tickets get --track-id abc123def456All mutating commands support --dry-run to preview what would happen:
dolibarr thirdparties create --name "Test" --supplier --dry-run
# Would create thirdparty: { name: "Test", fournisseur: 1 }
# No changes made.Every mutating subcommand that takes a record id as its only positional argument also accepts a comma-separated id list, so one call can act on many records:
dolibarr invoices validate 12,13,14 --confirm
dolibarr thirdparties update 20,21 --town "Berlin" --confirm
dolibarr orders delete 5,6,7 --confirmA single id behaves exactly as it always has — the batch path is only taken when the argument contains a comma.
PowerShell users: quote every comma-separated value. PowerShell parses a bare
12,13,14as an array literal and rewrites it before the CLI ever sees it, so--fields id,refsilently becomes a single field namedid refand a batch id list collapses into one argument. Always quote:dolibarr invoices validate "12,13,14" --confirm dolibarr invoices list --fields "id,ref"Bash, zsh and fish need no quoting.
Batch runs are deliberately loud:
--dry-runprints every resolved target and the request each one would send — not a count, not a sample.- Confirmation is required. Non-interactively, a batch refuses to run without
--confirmand exits3. - Failures do not stop the batch. Each item is attempted in turn and reported individually, so a half-applied batch is always detectable.
- Partial success exits
5(see the exit-code table below).
Under --output json the whole run collapses to a single machine-readable envelope:
dolibarr invoices validate 12,13,14 --confirm --output json{
"batch": true,
"action": "invoices validate",
"dryRun": false,
"total": 3,
"succeeded": 2,
"failed": 1,
"exitCode": 5,
"results": [
{ "id": "12", "ok": true },
{ "id": "13", "ok": true },
{
"id": "14",
"ok": false,
"exitCode": 1,
"error": "API error 404: Not Found: Invoice not found",
"detail": { "httpStatus": 404, "method": "POST", "path": "invoices/14/validate" }
}
]
}Re-running a batch with the failed ids converges rather than double-applying, so the usual
recovery is to fix the cause and re-run just the ids that reported "ok": false.
Ids must be positive integers in a list; a malformed list is rejected before any record
is touched. Read commands (get, list, …) are not batched — their output shape is
unchanged.
Status transitions can select their own targets instead of taking ids. Each resource
exposes one --all-<status> flag per status it actually has:
# validate every draft invoice
dolibarr invoices validate --all-draft --confirm
# preview first — always do this
dolibarr invoices validate --all-draft --dry-run
# close every validated order
dolibarr orders close --all-validated --confirmThe status vocabulary is per-resource and is not a uniform 0..n sequence — expense
reports run 0/2/4/5/6/99, members -2/-1/0/1, BOMs 0/1/9. --help on any status-scoped
command lists that resource's real statuses.
Scope and cap the selection:
| Flag | Purpose |
|---|---|
--filter <expr> |
Narrow the selection with an SQL filter, ANDed with the status |
--max <n> |
Cap on records selected (default 100) |
# only this month's drafts, at most 20 of them
dolibarr invoices validate --all-draft \
--filter "(t.datef:>=:'20260701')" --max 20 --confirmSelection rules:
- The resolved selection is printed before anything happens — with
--dry-runyou get every target id and the request each would send. - A cap is never silent. If more records matched than
--maxallowed, the run says so explicitly and tells you how to continue. - An id and a selector are mutually exclusive, as are two selectors.
- Zero matches is a success (exit
0), not an error.
Selection filters server-side on the resource's own status column, so nothing that matched can be silently skipped. Note that Dolibarr's own
list --statusquery param expects string tokens (draft,paid) and silently ignores a numeric value — the status-scoped flags avoid that trap entirely.
list commands can narrow by date and amount at the server, so scripts and agents stop
pulling everything and filtering locally:
dolibarr invoices list --from 2026-01-01 --to 2026-12-31
dolibarr invoices list --min-amount 1000 --max-amount 5000
dolibarr orders list --from 2026-03-01 --to 2026-03-31 --fields id,ref,total_ttc| Flag | Meaning |
|---|---|
--from <YYYY-MM-DD> |
Records on or after this date |
--to <YYYY-MM-DD> |
Records on or before this date (the whole day is included) |
--min-amount <n> |
Amount at or above n |
--max-amount <n> |
Amount at or below n |
These compile to Dolibarr sqlfilters and are ANDed with any --filter you pass, so the
two compose rather than one overriding the other. They also apply to v0.5.1's status-scoped
selection, which is what makes this work:
# validate just this month's drafts — preview first
dolibarr invoices validate --all-draft --from 2026-03-01 --to 2026-03-31 --dry-run
dolibarr invoices validate --all-draft --from 2026-03-01 --to 2026-03-31 --confirmThe flags appear only on resources that actually have the column — contacts list has
--from/--to but no --min-amount, because contacts have no amount. Dates must be exact
YYYY-MM-DD calendar dates, and an inverted range is rejected before any request is sent
(exit 3).
bank transferkeeps its own pre-existing--from/--to(source and destination account). Where a command already owns one of these flag names, the filter of that kind is not added rather than shadowing it.
Dolibarr pages its list endpoints. --all walks every page for you:
# full export, no manual pagination
dolibarr thirdparties list --all --output csv > thirdparties.csv
# combine with server-side filters
dolibarr invoices list --all --from 2026-01-01 --to 2026-12-31 --fields id,ref,total_ttc| Flag | Meaning |
|---|---|
--all |
Fetch every page, ignoring --limit |
--max-records <n> |
Safety cap on records fetched (default 5000) |
--limitand--pagekeep working exactly as before when--allis absent.- Hitting the cap is never silent — the run says so explicitly and tells you how to
continue. Raise
--max-records, or narrow with--filter/--from/--to. - Progress and warnings go to stderr, so
--alloutput stays a clean data stream:dolibarr thirdparties list --all --output csv > out.csvwrites only CSV to the file.
--from-json accepts a JSON array, and --stdin reads records from a pipe as NDJSON:
# one call per array entry
dolibarr thirdparties create --from-json batch.json --confirm
# stream NDJSON in
cat rows.ndjson | dolibarr thirdparties create --stdin --confirm
# preview first — prints the body of every record
dolibarr thirdparties create --from-json batch.json --dry-run--stdin accepts NDJSON (one JSON object per line), a JSON array, or a single object.
A single JSON object in --from-json behaves exactly as it always has — no
confirmation, no batch report. Bulk behaviour only kicks in for more than one record, and
then it follows the same rules as every other bulk operation here: full dry-run listing,
required --confirm, per-item outcome, exit 5 on partial success.
Under --output json each result carries the command's own output, so a bulk create hands
back the new ids:
{
"batch": true, "action": "thirdparties create",
"total": 2, "succeeded": 2, "failed": 0, "exitCode": 0,
"results": [
{ "id": "#1 Acme Ltd", "ok": true, "output": 41 },
{ "id": "#2 Globex", "ok": true, "output": 42 }
]
}
supplier-orders receive --from-jsonis excluded: there an array already means the lines of one receipt, and splitting it would change what the command does.
Beyond table, json and csv, read commands support formats built for pipelines:
# one JSON object per line — feed jq, or a while-read loop
dolibarr thirdparties list --all --output ndjson > thirdparties.ndjson
# YAML
dolibarr invoices get 42 --output yaml
# a Go-style template, one line per row
dolibarr invoices list --template '{{.id}} {{.ref}}'
# headerless CSV for a downstream importer
dolibarr invoices list --output csv --no-header| Flag | Meaning |
|---|---|
--output ndjson |
One compact JSON object per line |
--output yaml |
YAML |
--field ref |
One raw value per row — no header, no quoting (xargs-friendly) |
--template '{{.ref}}' |
Render each row from a template; {{.a.b}} walks nested fields |
--no-header |
Omit the header row from table / csv |
--quiet |
Suppress headers and batch progress chatter; print data only |
These are one letter apart and do different things:
| Does | |
|---|---|
--field ref |
singular — prints one bare value per row, nothing else |
--fields id,ref |
plural — projects those columns into the chosen --output |
dolibarr invoices list --field id # 16⏎17⏎18
dolibarr invoices list --fields id,ref # a two-column tableBecause a mix-up would otherwise be silent, every confusable combination is rejected with
exit 3: a comma in --field (it suggests --fields), and pairing --field with either
--fields or --template.
# one call per id
dolibarr invoices list --all --field id | xargs -n1 dolibarr invoices validate --confirm
# or collapse to a single batch call (see Batch operations)
dolibarr invoices list --all --field id | paste -sd, - \
| xargs dolibarr invoices validate --confirmNote the -n1: a bare xargs would hand every id to one invocation, and these subcommands
take a single id (or one comma-separated list).
Notes:
--templatetakes precedence over--output— it is the output format. A missing field renders empty rather than failing the row, so one odd record never kills a stream.--fieldscomposes with all of these, so--fields id,ref --output ndjsonemits only those keys.- In YAML, every string is quoted. Unquoted, values like
1.0,007,yesor2024-01-01would be read back as a number, boolean or date — silently changing your data mid-pipeline. Quoting always is less pretty and always correct. --quietsilences the batch reporter and table headers. It never suppresses a command's actual result, so a create still prints its new id.- An unrecognised
--outputvalue still falls back totable, as it always has.
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Generic error (including a batch where every item failed for an unclassified reason) |
2 |
Authentication or permission failure (HTTP 401 / 403) |
3 |
Validation error, or a prompt was required in non-interactive mode |
4 |
Rate limited (HTTP 429) |
5 |
Partial batch failure — some items applied, some failed |
Code 5 only ever comes from a batch run. When every item of a batch fails, the batch exits
with that shared underlying code (e.g. 2 for a permission-gated module) rather than 5.
| Command | Description |
|---|---|
config |
Manage CLI configuration (init, show, set) |
status |
Check connection and show server info |
raw |
Execute raw API requests |
thirdparties |
Customers, suppliers, prospects |
invoices |
Customer invoices |
supplier-invoices |
Purchase invoices |
orders |
Customer orders |
supplier-orders |
Purchase orders |
proposals |
Quotes / commercial proposals |
bank |
Bank accounts and transactions |
accounting |
Accounting export data |
products |
Products and services |
contacts |
Contact persons |
categories |
Tags and categories |
documents |
File upload, download, listing |
users |
User management |
setup |
Modules, company info, config constants |
projects |
Projects and tasks |
tickets |
Support / help desk tickets |
contracts |
Service contracts + line activation |
shipments |
Customer shipments (expeditions) |
receptions |
Supplier receptions |
interventions |
Interventions (fichinter) + time lines |
expensereports |
Expense reports + payment tracking |
members |
Members, subscriptions, member types |
stock |
Warehouses + stock movement ledger |
supplier-proposals |
Supplier price requests |
tasks |
Project tasks + time spent |
agenda |
Calendar / agenda events |
multicurrencies |
Currencies + FX rates |
knowledge |
Knowledge-base articles |
mrp |
BOMs, manufacturing orders, workstations |
# Run in dev mode (requires bun)
bun src/cli.ts status
# Build
npm run build
# Type check
npm run typecheck
# Test
npm test
# Lint & format
npm run lint
npm run formatsrc/
cli.ts Entry point — registers all command groups
core/
api-client.ts HTTP client (native fetch, DOLAPIKEY auth, retries)
config-store.ts Config file management (~/.config/dolibarr-cli/)
errors.ts Error classes (ApiError, AuthError, ConfigError)
output.ts Table / JSON / CSV formatting
types.ts Shared TypeScript types
commands/
config.ts dolibarr config init|show|set
status.ts dolibarr status
raw.ts dolibarr raw <METHOD> <path>
thirdparties.ts dolibarr thirdparties ...
invoices.ts dolibarr invoices ...
... (one file per resource)
Conventions:
- Commands stay thin — business logic goes in
src/core/ - Native
fetchonly — no axios, no node-fetch commanderis the only runtime dependency- Same patterns as plane-cli and solidtime-cli
Tested with Dolibarr 20.x. Should work with any version that has the REST API enabled (16+).
MIT