A single-binary, cross-platform command-line tool for Pleqsa partner onboarding. Download for your OS, follow the walkthrough below, partner activated.
The walkthrough below targets the dev environment by default. Each tester should mint fresh test data to avoid colliding on the server's uniqueness constraints.
Admin username: systemadmin :: example — any sys-admin user works (password from your team's credential store) DocumentNumber: TEST-<INITIALS>-001 :: unique handle the partner will reference TaxId: 999990<your-suffix>001 :: server rejects duplicates — pick fresh Partner email: you+test1@yourdomain :: real mailbox you can read Jurisdiction: BA :: one of BA / HR / RS / EU
From "nothing installed" to "partner activated". Steps are collapsible; expand the one you need.
Windows 10 (build 1809+) or Windows 11 with network access to the dev gateway.
tar.exe ships with Windows 10+ and handles ZIPs — no extra tools needed.
Download the matching archive from the Download table.
Open PowerShell in your Downloads folder (Shift+Right-click the folder → Open in Terminal).
Install uses PowerShell because its SetEnvironmentVariable API handles user-PATH updates cleanly; the day-to-day commands in steps 5–10 work in both PowerShell and cmd.
# From your Downloads folder: $file = "pleqsa_v0.2.4_Windows_x86_64.zip" $bin = "$env:USERPROFILE\bin" # 1. Extract Expand-Archive ".\$file" -DestinationPath . -Force # 2. Install to a PATH directory New-Item -ItemType Directory -Path $bin -Force | Out-Null Copy-Item ".\$($file -replace '\.zip$','')\pleqsa.exe" "$bin\pleqsa.exe" -Force # 3. Persist on user PATH (visible in NEW shells from now on) $userPath = [Environment]::GetEnvironmentVariable('PATH', 'User') if (-not ($userPath -split ';' -contains $bin)) { [Environment]::SetEnvironmentVariable('PATH', "$userPath;$bin", 'User') } # 4. Also update THIS shell's PATH so the verify step works without a fresh window $env:PATH = "$env:PATH;$bin" # 5. Verify pleqsa version
pleqsa version
pleqsa --help
pleqsa config envs :: lists dev/test/prod and their URLs
pleqsa config init pleqsa config path :: prints %APPDATA%\pleqsa\config.yaml pleqsa config view :: merged config, secrets redacted
Run pleqsa with no arguments to open the polished menu — the easiest way to walk through the onboarding flow. Arrow keys to move, Enter to select, Esc to back out, Ctrl+C to quit, / to filter.
pleqsa
pleqsa with no arguments on a TTYEach menu option launches a small form (one field at a time) and validates input as you type — ISO-8601 for dates, enum membership for document type, real-time file existence check for the --file attachment.
The --username value is just an example — any sys-admin account works.
Whatever you type at the password prompt becomes the active user for the rest of the session.
pleqsa admin auth login --env dev --username systemadmin :: Password is prompted; characters are hidden as you type. pleqsa admin auth whoami :: confirm cached identity + expiry
%LOCALAPPDATA%\pleqsa\tokens.json when the keyring is unavailable). Your password is never stored anywhere.admin documents create) reuse the cached token automatically — no re-prompt until expiry.user: not signed in to user: systemadmin.pleqsa admin auth whoami --env dev.pleqsa admin auth logout --env dev --username systemadmin.Pick a unique DocumentNumber and TaxId — the server enforces uniqueness.
set DOC_NUMBER=TEST-MYINIT-001 set TAX_ID=999990123001 pleqsa admin documents create ^ --env dev ^ --document-number "%DOC_NUMBER%" ^ --tax-id "%TAX_ID%" ^ --document-type BusinessRegistration ^ --valid-until "2027-12-31T23:59:59Z"
Expected: a 201 result with verificationDocumentId, status: ISSUED, and a location header. On a TTY you get a rounded-border table; piped, you get JSON.
DocumentNumber you just created. The partner must reference the exact same value in the next step. If they type the wrong number, the CLI shows:
The document number you entered is not valid. Please contact Pleqsa partner support.
This step is public — no admin token is attached. Save the YAML below as demo.yaml with Notepad, editing the four lines marked CHANGE.
# demo.yaml CompanyName: "Demo Partner Pleqsa d.o.o." Email: "you+test1@yourdomain" # CHANGE: real mailbox TaxId: "999990123001" # CHANGE: must match step 7's tax-id CountryCode: "BA" Jurisdiction: "BA" UserName: "demo.test1.admin" # CHANGE: unique per test Password: "<CHANGE-ME-strong-passphrase>" # CHANGE: 12+ chars, mixed case, digit, symbol UserEmail: "you+test1@yourdomain" # CHANGE: real mailbox Name: "Demo" Surname: "Owner" PhoneNumber: "+38761000000" Address: "Demo street 1, Sarajevo" WebsiteUrl: "https://demo.example.com"
pleqsa partner register ^ --env dev ^ --from-file demo.yaml ^ --document-number "%DOC_NUMBER%"
Expected: success — server returns 204 with no partner id (the CLI prints "look up by taxId or email if needed"). An activation email lands at the Email address.
The document number you entered is not valid. Please contact Pleqsa partner support.Re-check the value you used in step 7 and run partner register again with the exact match.
Optional — requires access to the partner inbox you used in step 8. If you don't have that mailbox handy you can skip this step; the partner stays in PENDING status until verified.
When you do have the email: open it, copy the single-use token (typically 32 hex/base-64 chars), then:
:: Via flag: pleqsa partner verify-email --env dev --token PASTE-32-CHAR-TOKEN-HERE :: Or via env var (cleaner — no shell history leak): set PLEQSA_PARTNER_TOKEN=PASTE-32-CHAR-TOKEN-HERE pleqsa partner verify-email --env dev set PLEQSA_PARTNER_TOKEN=
Expected: "Verified. Partner status flipped to ACTIVE." Replaying a used token returns exit 6 with "Token already used or expired".
pleqsa admin auth logout --env dev --username systemadmin del /Q "%APPDATA%\pleqsa\config.yaml" 2>nul del /Q "%LOCALAPPDATA%\pleqsa\tokens.json" 2>nul del /Q "%LOCALAPPDATA%\pleqsa\tokens-index.json" 2>nul
To uninstall: delete %USERPROFILE%\bin\pleqsa.exe and remove %USERPROFILE%\bin from your user PATH via System Properties → Environment Variables.
Modern Linux with glibc 2.31+ or musl (Alpine works). Optional: a running Secret Service daemon (GNOME Keyring, KWallet, or pass) — headless installs use a 0600 file fallback automatically.
Download the archive matching your CPU from the Download table. Then in a terminal in the same directory:
Check your CPU first with uname -m, then run one of the two snippets below. Both define $FILE and $DIR used by the remaining steps.
For x86_64 (most servers and PCs — uname -m prints x86_64):
FILE=pleqsa_v0.2.4_Linux_x86_64.tar.gz DIR=pleqsa_v0.2.4_Linux_x86_64
For arm64 (Raspberry Pi 4+, AWS Graviton — uname -m prints aarch64 or arm64):
FILE=pleqsa_v0.2.4_Linux_arm64.tar.gz DIR=pleqsa_v0.2.4_Linux_arm64
Creates a folder called $DIR next to the .tar.gz, containing pleqsa, Readme.md, and the design spec.
tar -xzf "$FILE"
Copies pleqsa to /usr/local/bin with mode 0755. Requires sudo. Available to every user on the machine. No sudo? See the user-only alternative below.
sudo install -m 755 "$DIR/pleqsa" /usr/local/bin/
Should print something like pleqsa v0.2.4 (commit local, built …, go1.26.3).
pleqsa version
Replace step c with the three commands below. Steps a, b, and d stay the same.
mkdir -p ~/.local/bin install -m 755 "$DIR/pleqsa" ~/.local/bin/
~/.local/bin to PATH for future shells (idempotent)grep -qxF checks whether the export line is already in .bashrc; echo >> appends it only if missing.
LINE='export PATH="$HOME/.local/bin:$PATH"' grep -qxF "$LINE" ~/.bashrc 2>/dev/null || echo "$LINE" >> ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"
pleqsa version pleqsa --help pleqsa config envs
pleqsa config init
pleqsa config path # ~/.config/pleqsa/config.yaml
pleqsa config view
pleqsa
# Interactive (prompts for password; chars are hidden): pleqsa admin auth login --env dev --username systemadmin # CI-friendly — read the password from stdin so it never appears in shell history # or process listings. Source it from your team's credential store, e.g.: # pass show pleqsa/dev/systemadmin | pleqsa admin auth login --env dev --username systemadmin --password-stdin pleqsa admin auth whoami
pass) when available, or in a 0600-permissioned file at ~/.cache/pleqsa/tokens.json on headless boxes. Your password is never stored anywhere.user: not signed in to user: systemadmin.pleqsa admin auth whoami --env dev.pleqsa admin auth logout --env dev --username systemadmin.DOC_NUMBER="TEST-MYINIT-001" TAX_ID="999990123001" pleqsa admin documents create \ --env dev \ --document-number "$DOC_NUMBER" \ --tax-id "$TAX_ID" \ --document-type BusinessRegistration \ --valid-until "2027-12-31T23:59:59Z"
Save the YAML as demo.yaml, editing the CHANGE lines:
# demo.yaml CompanyName: "Demo Partner Pleqsa d.o.o." Email: "you+test1@yourdomain" # CHANGE TaxId: "999990123001" # CHANGE CountryCode: "BA" Jurisdiction: "BA" UserName: "demo.test1.admin" # CHANGE Password: "<CHANGE-ME-strong-passphrase>" # CHANGE: 12+ chars, mixed case, digit, symbol UserEmail: "you+test1@yourdomain" # CHANGE Name: "Demo" Surname: "Owner" PhoneNumber: "+38761000000" Address: "Demo street 1, Sarajevo" WebsiteUrl: "https://demo.example.com"
pleqsa partner register \ --env dev \ --from-file ./demo.yaml \ --document-number "$DOC_NUMBER"
TOKEN="paste-32-char-token-here"
pleqsa partner verify-email --env dev --token "$TOKEN"
# Or via env var:
export PLEQSA_PARTNER_TOKEN="paste-32-char-token-here"
pleqsa partner verify-email --env dev
unset PLEQSA_PARTNER_TOKEN
pleqsa admin auth logout --env dev --username systemadmin
rm -f ~/.config/pleqsa/config.yaml
rm -f ~/.cache/pleqsa/tokens.json ~/.cache/pleqsa/tokens-index.json
sudo rm -f /usr/local/bin/pleqsa # if installed system-wide
macOS 13 (Ventura) or newer. Network access to the dev gateway. Keychain unlocked for an interactively-logged-in user (the default).
ARCH=$(uname -m) case "$ARCH" in arm64) FILE=pleqsa_v0.2.4_Darwin_arm64.tar.gz ; DIR=pleqsa_v0.2.4_Darwin_arm64 ;; x86_64) FILE=pleqsa_v0.2.4_Darwin_x86_64.tar.gz ; DIR=pleqsa_v0.2.4_Darwin_x86_64 ;; esac tar -xzf "$FILE" # Strip Gatekeeper quarantine (v0.2 binaries are NOT yet notarized) xattr -d com.apple.quarantine "$DIR/pleqsa" 2>/dev/null || true # System-wide: sudo install -m 755 "$DIR/pleqsa" /usr/local/bin/ # OR user-only: mkdir -p ~/.local/bin install -m 755 "$DIR/pleqsa" ~/.local/bin/ # Add ~/.local/bin to your shell's PATH on future shells (idempotent) LINE='export PATH="$HOME/.local/bin:$PATH"' grep -qxF "$LINE" ~/.zshrc 2>/dev/null || echo "$LINE" >> ~/.zshrc # And update THIS shell's PATH so the verify step works without a new shell export PATH="$HOME/.local/bin:$PATH" pleqsa version
xattr -d com.apple.quarantine step bypasses this. Notarization is on the v0.3 roadmap.pleqsa version pleqsa --help pleqsa config envs
pleqsa config init
pleqsa config path # ~/Library/Application Support/pleqsa/config.yaml
pleqsa config view
pleqsa
# Interactive (prompts for password; chars are hidden): pleqsa admin auth login --env dev --username systemadmin # CI-friendly — read the password from stdin so it never appears in shell history. # Source it from your team's credential store (1Password CLI, security CLI, etc.): # security find-generic-password -s pleqsa-admin -a systemadmin -w | \ # pleqsa admin auth login --env dev --username systemadmin --password-stdin pleqsa admin auth whoami
On first use macOS Keychain may prompt to allow access — accept once and pleqsa stores the token under the pleqsa service. View it in Keychain Access if you want to verify.
pleqsa service (or in a 0600-permissioned file at ~/Library/Caches/pleqsa/tokens.json when Keychain refuses). Your password is never stored anywhere.user: not signed in to user: systemadmin.pleqsa admin auth whoami --env dev.pleqsa admin auth logout --env dev --username systemadmin. To also wipe the Keychain entry directly: security delete-generic-password -s pleqsa.DOC_NUMBER="TEST-MYINIT-001" TAX_ID="999990123001" pleqsa admin documents create \ --env dev \ --document-number "$DOC_NUMBER" \ --tax-id "$TAX_ID" \ --document-type BusinessRegistration \ --valid-until "2027-12-31T23:59:59Z"
Same demo.yaml as the other OSes (see the Linux tab for the full YAML). Then:
pleqsa partner register \ --env dev \ --from-file ./demo.yaml \ --document-number "$DOC_NUMBER"
pleqsa partner verify-email --env dev --token PASTE-TOKEN
# Or via env var:
export PLEQSA_PARTNER_TOKEN=PASTE-TOKEN
pleqsa partner verify-email --env dev
unset PLEQSA_PARTNER_TOKEN
pleqsa admin auth logout --env dev --username systemadmin
rm -f ~/Library/Application\ Support/pleqsa/config.yaml
rm -rf ~/Library/Caches/pleqsa
security delete-generic-password -s pleqsa 2>/dev/null || true
sudo rm -f /usr/local/bin/pleqsa # if installed system-wide
pleqsa ├── admin # sys-admin operations │ ├── auth login | logout | whoami │ └── documents (alias: docs) │ └── create ├── partner # public self-service │ ├── register │ └── verify-email ├── config │ ├── init | path | view │ ├── set <key> <value> │ ├── get <key> │ └── envs ├── interactive # open the menu explicitly ├── completion bash|zsh|fish|powershell └── version
Run pleqsa <cmd> --help for per-command details.
dev https://dev-portal-document-nx.apps.okd-dev.qssbh.com test https://dev-portal-document-nx.apps.okd-dev.qssbh.com :: same as dev until a distinct gateway lands prod https://dev-portal-document-nx.apps.okd-dev.qssbh.com :: same as dev until a distinct gateway lands
Select via --env <name>, PLEQSA_ENV, or activeEnvironment in the config file. URL changes ship as a versioned release — never at runtime.
--output auto | table | json | yaml | plain. auto picks table on a TTY (rounded-border lipgloss panel) and JSON when stdout is piped. --no-color and the standard NO_COLOR env var both strip ANSI styling.
0 Success 1 Generic error 2 Usage error :: bad flags / unknown command / missing required 3 Auth error :: 401/403, missing or expired token 4 Network error :: DNS/TCP/TLS/timeout after retries 5 Server error :: persistent 5xx after retries 6 Client error :: 4xx other than 401/403 7 Config error :: missing file, bad YAML, unknown env 8 Secret error :: keyring + file-fallback both failed 130 Interrupted :: Ctrl+C
--insecure warns every call.http:// base URLs rejected unless --insecure is also set.[]byte and zeroed after use. The --password=<value> flag warns each invocation — it leaks into the OS process list.X-Request-Id UUID for server-side correlation.--header "X-Foo: bar" is a hidden advanced flag — CRLF and other control characters rejected; Authorization / Cookie / Set-Cookie cannot be overridden.audit.enabled: true in config to append one JSON line per mutating call.Requires Go 1.22+ (we ship with 1.26.3). Module path: pleqsa.com/clis. From the project root:
# Linux / macOS: go build -trimpath -buildvcs=false \ -ldflags "-s -w -X main.version=v0.2.4" \ -o pleqsa ./cmd/pleqsa-onboarding :: Windows (cmd): go build -trimpath -buildvcs=false -ldflags "-s -w -X main.version=v0.2.4" -o pleqsa.exe .\cmd\pleqsa-onboarding
Tests + lint + vuln scan:
go vet ./... go test ./... -race -count=1 go run github.com/golangci/golangci-lint/cmd/golangci-lint@latest run go run golang.org/x/vuln/cmd/govulncheck@latest ./...
The shared infrastructure under internal/ is reusable by any future CLI talking to the Pleqsa API gateway. To add pleqsa-<name>:
cmd/pleqsa-<name>/main.go. Use cmd/pleqsa-onboarding/main.go as the template.internal/cli/, or factor them into a dedicated subpackage internal/<name>/cli/ once they outgrow flat files.builds: entry in .goreleaser.yaml pointing at ./cmd/pleqsa-<name> with binary: pleqsa-<name>..azure-pipelines/pleqsa-<name>.yml with path-filtered triggers so only relevant changes rebuild it.<name>/vX.Y.Z — e.g. if you add a "billing" CLI, its first tag would be billing/v0.1.0, independent of onboarding/'s version line. Release pipelines filter by tag prefix.Each CLI versions independently. Shared changes that affect multiple CLIs go in internal/ and trigger every pipeline.
pleqsa-clis/ ├── cmd/ │ └── pleqsa-onboarding/ Entry point for the onboarding CLI │ └── main.go ├── internal/ Shared packages — every CLI imports from here │ ├── api/ HTTP client, environment URL table, DTOs │ ├── cli/ Cobra commands (auth, partner, config, root) │ ├── config/ Viper wrapper, env-based config layering │ ├── secret/ OS keyring with 0600 file fallback │ ├── output/ Table / JSON / YAML / plain renderers │ ├── errs/ Typed errors + exit-code mapping │ ├── tui/ Bubble Tea spinner + interactive primitives │ ├── logging/ Audit log (opt-in) │ └── version/ Build-time version info (ldflag-injected) ├── docs/ Auto-generated and design docs ├── Release/ Pre-built archives per OS/arch (+ checksums.txt) ├── screenshots/ CLI usage screenshots, organized by <cli>/<version>/ ├── .azure-pipelines/ CI / release pipelines (one per CLI) ├── .goreleaser.yaml Cross-compile + sign + package pipeline ├── go.mod Module: pleqsa.com/clis └── getting-started.html End-user download & walkthrough page (this file)
Version history for the Pleqsa Onboarding CLI. Newest first.
Verification document not found for DocumentNumber: X → "The document number you entered is not valid. Please contact Pleqsa partner support."internal/api/dto.go (regex-based, case-insensitive). New entries take ~5 lines each.TestServerError_FriendlyDocumentNumber with three sub-cases (key with space, PascalCase key, varied casing in message). Other validation errors still list per-field as before.ServerError.HumanMessage now parses ASP.NET's ValidationProblemDetails.errors map and prints per-field messages instead of the generic "One or more validation errors occurred." title.- TaxId: must be 12 digits) rather than a vague summary.TestServerError_ValidationProblemDetails regression test.resolveActiveUsername fallback — if no environments.<env>.auth.username is set in config, falls back to whichever identity is cached for that env.Time.UnmarshalJSON: input is not a JSON string when the server returns expiresAt as a Unix epoch integer or ISO-8601 without timezone.LoginResponse.UnmarshalJSON tolerates 8 time formats: RFC3339, RFC3339Nano, RFC3339 with offset, ISO-8601 without TZ, ISO with space separator, Unix seconds, Unix milliseconds, null/missing.charmbracelet/huh) — running pleqsa with no args on a TTY opens a guided menu with prompts, validators, password masking, and a live header banner.zalando/go-keyring — Windows Credential Manager, macOS Keychain, Linux Secret Service. File fallback (0600) when keyring is unavailable.lipgloss-styled table renderer with rounded borders and adaptive light/dark palette.audit.enabled: true in config) and hidden --header flag with CRLF/control-char + reserved-name (Authorization, Cookie, Set-Cookie) rejection..goreleaser.yaml + CI workflows (govulncheck, golangci-lint, multi-OS test matrix).--help output.admin auth login, admin documents create, partner register, partner verify-email.dev/test/prod) with --base-url escape hatch.httptest mock covering happy paths + auth failure + replay-of-used-token.