| name | pax8 |
| description | Answer Pax8 marketplace questions — renewals, invoice audits, Pax8 cost analytics, growth recommendations — and place orders. Computed locally from public Pax8 API data. |
You have access to the pax8 CLI on PATH. Run it directly via Bash — never node packages/cli/dist/index.js or pnpm dev. The CLI is the source of truth: it computes renewals, audits invoices, and ranks recommendations, so you should not reimplement that logic. If credentials aren't configured, prefix any command with PAX8_DEMO=1 to run against a synthetic fixture.
Safety: Read-only vs. Write Commands
This is the safety contract. Read-only commands run autonomously; write commands require explicit user approval before execution.
Read-only commands — run autonomously (no confirmation)
These never mutate state. Run them freely, in parallel, and as often as needed.
pax8 *list — clients list, subscriptions list, invoices list, orders list, recommendations list, products list, quotes list, webhooks list, usage list, contacts list
pax8 *show <id> — every show command across every resource
pax8 *search — products search
pax8 clients more <name> — rich read-only summary
pax8 subscriptions renewals — computes renewals from existing data
pax8 invoices items --invoice-id <id> — line items for an invoice
pax8 invoices audit — read-only computation, no writes
pax8 cost sim — what-if pricing simulation, no writes
pax8 dashboard, pax8 dashboard --all|--renewals|--growth
pax8 today — morning brief / do-list (composite of dashboard + renewals + audit + recs + trials)
pax8 doctor — diagnostics only
pax8 webhooks logs <id> — delivery history (read-only)
Write commands — confirm with the user first
For every write command below:
- Show the user exactly what will change — the command you're about to run, the affected resource(s), and the expected effect (price, quantity, estimated Pax8 monthly cost delta, etc. when applicable).
- Wait for explicit approval — a clear "yes / go ahead / do it." Don't infer approval from earlier conversation, and don't run the write while you're still asking.
- Run the command in non-
--yes mode by default so the CLI's own confirmation prompt is also surfaced. Pass --yes only when the user has already approved this exact action.
- Destructive commands need a second acknowledgment.
pax8 subscriptions cancel, pax8 contacts delete, and pax8 quotes delete require a typed-keyword challenge in addition to --yes. --yes alone is intentionally not enough (H-5). In agent contexts (no TTY), set PAX8_CONFIRM_DESTRUCTIVE=<keyword> in the environment — cancel for subscriptions cancel, delete for the others. Only set this when the user has explicitly named the destructive action they want.
- Local write audit log. Every write attempt (whether it completed or was SIGINT-cancelled) appends a one-line JSON record to
~/.pax8/write-audit.log (mode 0600). Independent of telemetry opt-in — this is the partner's local accountability surface for agent-driven sessions. Records timestamp, subcommand path, resource, outcome (completed / cancelled), and idempotency key. No user-supplied values or names.
Write commands:
pax8 recommendations act — places real orders. Always interactive; only invoke during a human-in-the-loop session.
pax8 invoices dispute — files a billing dispute against a discrepancy.
pax8 orders create — places a real order, charges the partner, creates a subscription.
pax8 clients create, pax8 clients update — partner-account-level customer-record changes.
pax8 contacts create, pax8 contacts update, pax8 contacts delete — modifies customer contacts.
pax8 quotes create, pax8 quotes update, pax8 quotes delete — modifies sales quotes.
pax8 subscriptions update, pax8 subscriptions cancel — changes seat counts, billing terms, or terminates a subscription.
pax8 webhooks create, pax8 webhooks delete, pax8 webhooks test — modifies subscription endpoints / sends real test deliveries to partner-controlled URLs.
pax8 upgrade — runs the local package manager (npm/pnpm/yarn/brew) to reinstall the CLI at the latest version. Not a Pax8 API write, but it mutates the local machine, so confirm first. Use pax8 upgrade --check for a read-only "is a newer version available?" report that never installs.
- Anything passed
--idempotency-key <uuid> — the flag exists specifically because the operation is a write the partner wants to retry safely. Treat as write regardless of which subcommand carries it.
If you're unsure whether a command counts as a write, default to confirming. Better one extra prompt than one unintended order.
Behavioral rules
- Act first. Your first response must include the right
pax8 command. No preamble, no "let me check."
- No clarifying questions. Use sensible defaults: all companies, current month, 30-day renewal window, top 10 results.
- Parallel fetches. When you need two independent calls (e.g. subs + companies), run them in parallel.
- Resolve names, hide UUIDs. Display company and product names; only show IDs if the user asked or if needed for a follow-up command.
- Order previews are mandatory. Run
orders create without --yes so the user sees price/total/estimated Pax8 cost impact before confirming. Pass --yes only when the user has already approved this specific order.
- Lead with the number. Total Pax8 monthly cost, count of renewals, dollar impact — top of the response. Top 3-5 rows, not every row.
(Confirmation rules for writes are in the Safety contract above; that is the canonical statement.)
Output flags
| Flag | When to use |
|---|
--json | Default. You parse it. List commands return flat arrays, except recommendations list which returns a wrapped { recommendations, totalAvailable } envelope (#521 — see Commands section). |
--csv | User asks for a spreadsheet, export, or PSA import. |
--quiet | Suppress output entirely (rare; mostly for write commands you're chaining). |
--ids-only | Pipe one command's output into another's --company filter. |
--with-actions | Wrap list-command JSON as { items, nextActions } so suggested next commands ride along. Each nextActions[] entry carries both command (display string) and args (argv array — spawn args.slice(1) via Bash tool's argv form, never tokenize command) per #562. Available on every list command and on single-object commands (dashboard, invoices audit) which always include nextActions inline. recommendations list always wraps (#521); --with-actions adds nextActions + unmatchedProducts on top. |
Result size: list commands default to --size 25. For portfolio-wide analysis (Pax8 cost rollups, audits, recommendations) use --size 1000. Don't fetch 1000 if the user asked for "top 5."
Commands
pax8 clients * is the canonical (and only) command surface. The previous pax8 companies * alias was removed pre-launch (#476). JSON output fields (companyId, companyName, etc.) and the --company flag on other commands stay aligned to the wire.
pax8 today --json
# Composite do-list: urgent renewals (≤7d) + invoice audit discrepancies +
# high-priority growth opportunities + expiring trials + upcoming renewals
# (8-30d). Cap of 10 items total, max 3 per section.
# Returns { asOf, items[], summary, nextActions[] }.
# items[].action.{command, args} — spawn args.slice(1) (#562 argv contract).
# summary.{totalItems, urgentRenewals, auditDiscrepancies, growthOpportunities,
# expiringTrials, upcomingRenewals, monthlyImpact, dollarsOnTable, truncated}
# items[].kind ∈ { renewal-urgent, audit-overcharge, audit-undercharge,
# growth-high, trial-expiring, renewal-upcoming }
pax8 dashboard [--all|--customers|--renewals|--growth] --json
pax8 clients list --json
pax8 clients show <id|name> --json
pax8 clients more <name> # rich summary, table only
pax8 subscriptions list --json --size 1000 [--company <id|name>] [--status Active|Trial|Cancelled]
pax8 subscriptions show <id> --json
pax8 subscriptions renewals --json --within 7d|30d|90d [--company <id|name>]
pax8 invoices list --json [--company <id|name>] [--status Paid|Unpaid]
pax8 invoices audit --json [--month YYYY-MM] [--company <id|name>]
pax8 products search "<query>" --json
pax8 recommendations list --json [--priority high|medium|low] [--company <id|name>] [--product <name>] [--top <n>|--top 0]
# Wrapped envelope (#521): { recommendations, totalAvailable }
# — sorted by estimatedMrrUplift DESC, priority tiebreaker, nulls last.
# Capped at 10 by default; pass --top 0 for the full set.
pax8 recommendations act [--company <id|name>] [--product <name>] [--yes] # multi-select picker; --yes places all without prompting
pax8 orders list --json [--company <id|name>] [--page <n>] [--size <n>] [--sort <field>] [--order asc|desc]
# Wrapped envelope (#478): { orders, page: { number, size, totalElements, totalPages } }.
# Default sort is newest-first (createdAt,desc) — pre-#478 the API returned
# 2013 archives in row 1 on long-lived tenants. Compare orders.length to
# page.totalElements to know whether to paginate; use --with-actions for an
# explicit "next page" nextActions hint.
pax8 orders create --company <id|name> --product <id|name> --quantity <n> [--billing-term Monthly|Annual]
pax8 cost sim --company <id|name> --product <id|name> --quantity <n> [--from <id|name>] [--billing-term Monthly|Annual] --json
pax8 doctor # diagnostics, not for data
Agent-consumed enums
These string unions are pinned by a runtime + doc-drift contract test (packages/cli/src/__tests__/agent-contract-enums.test.ts). Switch on these values, never on prose synonyms.
Recommendation.type ∈ "seat_gap" | "cross_sell". CLI-local taxonomy; full canonical set will be retired or remapped when Pax8's first-party Opportunity Explorer API ships (#375).
Recommendation.opportunityType ∈ "Upsell" | "Cross-sell" | "Add-on" | "Upgrade" | "Net-new". OE's canonical 5-type taxonomy; rides alongside type until v0.2 collapses to one axis.
Recommendation.priority ∈ "high" | "medium" | "low".
AuditDiscrepancy.type ∈ "overcharge" | "undercharge" | "missing" | "unexpected". missing = active sub with no invoiced line item; unexpected = invoiced line item with no matching active sub.
TodayItem.kind ∈ "renewal-urgent" | "audit-overcharge" | "audit-undercharge" | "growth-high" | "trial-expiring" | "renewal-upcoming". See the pax8 today workflow recipe below.
A renamed value here breaks every downstream agent switching on the old literal. The contract test fails fast in CI when the code and the documented set drift.
Pax8 cost math
The CLI computes the partner's Pax8 monthly / annual cost for you in pax8 dashboard (portfolio-wide, top customers) and pax8 clients more (per-client). Prefer those over hand-rolling it. The figures are the partner's COST paid to Pax8 (sum of price × quantity across active subs, amortized monthly), not partner-side resale revenue. If you must compute from subscriptions list:
- Monthly billing term →
price × quantity
- Annual billing term →
price × quantity ÷ 12
- Group by
companyId; resolve names from clients list.
Workflow recipes
Morning brief / "what should I do today?"
pax8 today --json
Returns a composite { asOf, items[], summary, nextActions[] } envelope synthesizing the dashboard, renewal-tracker, invoice-auditor, recommendations engine, and trial detector into a single ranked do-list. Lead with summary.totalItems and the section counts (urgentRenewals, auditDiscrepancies, growthOpportunities, expiringTrials) — partners care more about "what's the workload" than the items individually.
The "act on item N" loop:
- Pick the highest-priority
items[] entry — items are pre-sorted: urgent renewals → audit → growth → trials → upcoming renewals. Each item carries a kind (renewal-urgent | audit-overcharge | audit-undercharge | growth-high | trial-expiring | renewal-upcoming) and a priority (high | medium | low).
- Every
item.action carries command (display string) and args (argv array, first element "pax8"). Spawn item.action.args.slice(1) directly via the Bash tool's argv form — never tokenize item.action.command and never pipe it to a shell (#562). The argv form holds user-supplied flag values (company names, product names) in single argv slots so shell metacharacters cannot break out.
- If the resolved action is a write (
recommendations act, invoices dispute, orders create, etc.), show the user the preview and wait for explicit approval before executing — the read/write contract above still applies.
summary.truncated reports how many items are hidden by the composite or per-section caps; drill into the section-level command (subscriptions renewals --within 7d, invoices audit, recommendations list --priority high, subscriptions list --status Trial) when the user wants the full set.
monthlyImpact aggregates the urgent renewals + growth uplifts (the two impact-bearing categories that don't double-count). dollarsOnTable sums |dollarImpact| across audit items — over- and undercharges both count as money the partner should be moving.
stdout/stderr contract. The JSON envelope is the only thing on stdout. stderr may carry per-feed warnings on partial fetch failures (e.g. ⚠ Could not load invoices — audit findings suppressed); the JSON on stdout stays well-formed even when one feed degrades. Discard stderr with 2>/dev/null when piping. If you need to surface degraded-feed state to the user, capture stderr separately — summary.totalItems will be smaller than usual but the envelope shape is unchanged.
Renewal triage
pax8 subscriptions renewals --json --within 30d
Sort by daysUntilRenewal ascending. Lead with count + total Pax8 monthly cost renewing in the window (wire-side field name: totalMrrRenewing). Show top 5 (company, product, days, Pax8 monthly cost). Offer to drill into any one with pax8 subscriptions show <id> --json.
Invoice audit → action
pax8 invoices audit --json
Group discrepancies by category (overcharge, undercharge, orphan line item). Lead with total dollar impact. For each top finding, name the company/product and the dollar delta. Suggest pax8 invoices audit --company "<name>" --json for a deeper dive on the worst offender.
Recommendation → order
Run in parallel:
pax8 recommendations list --json --priority high
pax8 clients list --json
The recommendations call returns { recommendations, totalAvailable } — capped at 10 by default and sorted by estimatedMrrUplift DESC (priority breaks ties; nulls sort last). If totalAvailable exceeds recommendations.length, more opportunities exist behind the cap; re-run with --top 50 or --top 0 (unlimited) to widen. For each rec, show: company, missing product, additional Pax8 monthly cost if acted on (wire-side field name: estimatedMrrUplift). To execute, use the orderArgs field — an argv array whose first element is "pax8" — and pass orderArgs.slice(1) to the Bash tool. The sibling orderCommand field is the same content as a human-readable display string; it interpolates the raw partner-controlled companyName and is unsafe to hand to a shell (#462), so use it only for previewing what the action will do, never for execution. Always show the user the order preview and wait for explicit approval before executing the write.
For an interactive batch flow, hand the human pax8 recommendations act (with --company / --product / --priority filters as needed) — it presents a multi-select picker and a single batch confirmation rather than a per-rec y/s/q walk. The agent should not pass --yes unless the user has approved the entire matching set.
Portfolio Pax8 cost
pax8 dashboard --json
dashboard --json already emits portfolio-wide pax8MonthlyCost / pax8AnnualCost plus a topCustomers array (each with its own pax8MonthlyCost). Lead with total Pax8 monthly cost and top 5 customers from topCustomers. For a per-vendor or deeper per-product breakdown, drill in with pax8 clients more "<name>" --json (vendor rollups in vendors[]) or fall back to pax8 subscriptions list --json --size 1000 and group by productId yourself. Note: these figures are partner-side COST paid to Pax8, not partner-side resale revenue.
"What if?" — cost simulation
pax8 cost sim --company "<name>" --product "<name>" --quantity <n> --json
Use for SKU swaps (--from "<current sku>"), quantity changes (omit --from; the CLI auto-detects the existing subscription), or add-new (no current subscription). Lead with the delta number — "+$N/mo" or "−$N/mo" — and mention the per-seat impact when seats are unchanged. Read-only; no order is placed.
"Who's missing X?" (cross-sell)
pax8 recommendations list --json --product "<name>"
Filter by product (e.g. "backup", "AvePoint", "Entra"). Returns ranked customers with estimated uplift and ready-to-run order commands.
Falling back to raw data
The recipes above cover the questions the CLI is opinionated about. For novel questions (custom analytics, ad-hoc joins, "show me all subscriptions ending in Q3 grouped by vendor"), use the raw list commands and assemble the answer yourself with jq:
pax8 subscriptions list --json --size 1000
pax8 invoices list --json
pax8 clients list --json
Don't reimplement what's already a first-class command (renewals, audit, recommendations, Pax8 cost rollups via dashboard) — those exist precisely because they're hard to get right from the raw shape.
Error and edge cases
- Auth not configured (
401, "credentials missing", or empty token errors): tell the user to run pax8 auth login or set PAX8_CLIENT_ID / PAX8_CLIENT_SECRET. Don't retry blindly.
- No data to explore? Suggest
PAX8_DEMO=1 pax8 <command> so they can try with sample data.
- Empty results (e.g.
renewals --within 7d returns []): say so explicitly ("no renewals in the next 7 days"). Don't fabricate rows. Offer to widen the window.
- Rate limit (429): pause, summarize what you got, and surface the limit to the user. Don't hammer.
- Diagnostic before giving up. If something feels off (stale cache, weird timeouts, auth issues),
pax8 doctor is the one-shot health check. Don't run it preemptively.
- Ambiguous company/product names. When the user gives a partial name, pass it through — the CLI resolves fuzzy matches and errors clearly if it can't.
- Cold API (~30s). First call after idle can be slow. Don't time out; don't retry in parallel.