The CLI separates machine output from diagnostics: JSON and requested content use stdout; warnings, errors, and enabled client logs use stderr. This keeps pipelines valid even when a malformed DK Plus record is excluded or verbose logging is enabled.
devop-dk sales order list --take 25 --json | jq '.[].number'
DKPLUS_LOG_LEVEL=Warning devop-dk customer list --json > customers.json
devop-dk customer list --all --yes --json > all-customers.json
With --all --json the array is streamed record by record. A failure or Ctrl+C after the first page leaves a truncated array on stdout together with a non-zero exit code, so a pipeline must check the exit code before it uses the file.
Ordinary create and update commands execute directly. Explicit confirmation with --yes remains required for destructive deletes, outbound email or webhook test delivery, synchronization, inventory posting, approvals, and comparable safety-sensitive operations.
--all on a list command is the one read that takes --yes: it confirms fetching every record (data volume), not a change, and it never applies to create or update. --take accepts 1 to 1000 on the list commands (0.4.2 allowed up to 10,000); a larger value exits with code 2 before any request, so a script that needs more records uses --all --yes.
| Operation | --yes |
|---|---|
Ordinary create and update commands, including customer contact|receiver create|update, table create and table update, warehouse update-product, sales invoice create without --post, and sales order\|quote\|recurring create, update, and lines create\|update |
not needed |
sales invoice create --post (posting is irreversible; without --post the invoice is created unposted) |
required |
Every delete command, including customer contact delete, customer receiver delete, table delete, and project delete |
required |
sales invoice|order|quote email, token report email, webhook test |
required |
webhook create and webhook update (they carry authorization values) |
required |
company sync, company action |
required |
inventory journal, inventory transfer, inventory count |
required |
purchase invoice create, purchase invoice approval |
required |
--all on a list command, and the always-unbounded reads customer transaction list-for, project all, and project work-request list-for |
required in scripts (interactively the command asks [y/N] on stderr) |
devop-dk company sync --reset-from 2026-10-01T00:00:00Z --yes
devop-dk sales invoice email INV-100 --to [email protected] --yes
devop-dk sales invoice create -c C-100 -i ABCD -q 4 -p 1000 --post --yes
devop-dk customer contact delete C-100 1 --yes
devop-dk table delete ARCUST --key Number --value C-100 --yes
devop-dk project delete P-100 --yes
devop-dk inventory transfer --file ./transfers.json --description "Move stock" --post --yes
devop-dk purchase invoice approval 123 --file ./approval.json --yes
devop-dk customer list --all --yes --json > customers.json
sales invoice create --post without --yes stops with exit code 2 before any request, and --yes without --post has no effect. --all without --yes asks on stderr; when stdin, stdout, or stderr is redirected it stops with exit code 2 naming --yes before any request.
Remote mutations are not retried automatically. Eligible safe requests use bounded retries, jitter, Retry-After, attempt and total timeouts, and circuit breaking.
Commands that take --file read the public create and sparse update request types (for example CustomerCreateRequest and ProductUpdateRequest); update documents do not contain the identity. --file input is strict for every command that reads a file, including inventory, general-ledger, warehouse, and work-entry documents. A document type without an AdditionalData escape hatch accepts only its own properties: any other key is rejected with a message naming the key, its JSON path, and the type. A type with AdditionalData still forwards unknown keys to DK Plus, except keys an earlier release used and the current type renamed, moved, or made read-only, and the identity in an update document (Number, ItemCode, UId, ...); those are rejected with the replacement named. The error is written to stderr as Error: ... with exit code 2 before any token lookup or network request, and stdout stays empty.
Since 0.4.0 nested product and memo rows, warehouse-product settings, and General Ledger create documents have their own request types, and read-only members such as stock quantities, Modified, and ObjectDate are rejected with their JSON path. A document saved from a get --json read therefore needs those members removed before it is sent back. Pipelines that generate documents should use the current member names; see Upgrading to 0.4 and Upgrading to 0.3.
Expected API and configuration failures are written to stderr without a .NET stack trace. Recognized DK Plus error details are bounded to one line, email addresses are redacted, credential-related messages are suppressed, and raw response bodies are never printed.
Every request carries an X-Correlation-Id. Rejected requests report the effective ID so it can be supplied to support even if the response omitted the header.
Generic-table HTTP 400 responses identify unknown requested fields when possible:
Error: Field(s) not found in table 'ARCUST': ItemCode, Description. Run 'devop-dk table fields ARCUST' to list valid fields.
Response-contract mismatches report the operation, expected type, JSON path, and safe endpoint without printing returned data. A page and --count whose product exceeds the DK Plus limit of 50,000 records are rejected with exit code 2 before any request is sent; narrow the query with a modified-after/modified-before window and start again from page 1. Expected failures return a nonzero exit code, and cancellation returns 130. Set DEVOP_DK_DEBUG=1 only while investigating an unexpected local exception.
API tokens and webhook authorization values are redacted from normal table and JSON output. token create reads the DK Plus password from an attached terminal without echoing it and uses request-scoped Basic authentication; passwords are not accepted as command-line arguments or redirected stdin.
Keep tokens in the hidden login store, DKPLUS_API_TOKEN, or DKPLUS_API_TOKEN_FILE. Never place them in committed scripts or configuration.
Explicit output paths create missing parent directories automatically. Existing files are not replaced unless --force is supplied. On every OS, a saved file name that is a Windows device name (CON, NUL, COM1, ...) gets a _ prefix, so an attachment named con.pdf is saved as _con.pdf on Linux too. See Output, columns, and files for examples.