paybondpaybond
Sign in

CLI contract

Shared command tree, flags, output shapes, exit codes, and redaction rules for the paybond CLI in TypeScript and Python.

This document is the canonical contract for the paybond CLI shipped by both kits:

  • TypeScript: @paybond/kit exposes the paybond binary.
  • Python: paybond-kit exposes the paybond binary.

Both implementations must expose the same command names, global flags, JSON output keys, exit codes, error categories, and redaction behavior. Parity tests compare --help, JSON schemas, and error handling across both kits.

Legacy entry points remain as thin wrappers over this tree:

Legacy aliasCanonical command
paybond-kit-loginpaybond login
paybond-init / paybond-kit-initpaybond init guardrail
paybond-mcp-serverpaybond mcp serve

Design rules

  • Tenant scope always comes from authenticated credentials (PAYBOND_API_KEY or the configured env file). Normal tenant-scoped commands must not accept tenant IDs from unauthenticated CLI arguments.
  • Human output defaults to safe, masked values suitable for terminals and CI logs.
  • Machine output uses --format json and returns stable, documented keys. JSON mode never omits required envelope fields.
  • Destructive or live-money actions require --yes and are still subject to server-side RBAC.
  • Secrets on disk use file mode 0600. Default .env.local targets are added to .gitignore when needed. Custom env-file paths inside a git repo must already be ignored.

Global flags

These flags are accepted on every subcommand unless a command explicitly documents an exception. Global flags may appear before or after the subcommand.

FlagDefaultDescription
--gateway <url>https://api.paybond.aiGateway base URL for authenticated API calls.
--env-file <path>.env.localLocal secrets file containing PAYBOND_API_KEY. Login writes here; other commands read from here unless the key is already in the process environment.
--format table|jsontableHuman table output or stable JSON envelope (see below).
--profile <name>(unset)Named credential profile stored in the Paybond CLI config file. When set, overrides --env-file for credential resolution.
--request-id <id>(generated)Correlation ID sent to Gateway on API calls and echoed in JSON output. When omitted, the CLI generates a ULID-style identifier.
--yesfalseSkip interactive confirmation for destructive or irreversible operations.
--no-openfalseDo not open a browser for device login or other browser-assisted flows.

Commands may define additional flags. Command-specific flags must not redefine global flag names with different semantics.

Output formats

Table (default)

  • Write human-readable lines to stdout.
  • Write errors to stderr.
  • Apply redaction rules to every field before printing.
  • Do not print raw API keys, capability tokens, signing seeds, or Harbor bearer tokens.
  • Success lines should be concise and actionable (for example, masked key identity, resource IDs, and next steps).

JSON (--format json)

Every JSON response uses one envelope regardless of command:

{
  "ok": true,
  "command": "whoami",
  "data": {},
  "warnings": [],
  "request_id": "01JABY5EXAMPLE",
  "error": null
}

On failure:

{
  "ok": false,
  "command": "keys revoke",
  "data": null,
  "warnings": [],
  "request_id": "01JABY5EXAMPLE",
  "error": {
    "category": "forbidden",
    "code": "cli.rbac.denied",
    "message": "caller lacks keys:revoke permission",
    "details": {
      "gateway_status": 403,
      "gateway_code": "auth.forbidden"
    }
  }
}

Envelope fields:

FieldTypeDescription
okbooleantrue on success, false on failure.
commandstringCanonical command path (for example, login, whoami, audit exports list).
dataobject | nullCommand payload on success; null on failure.
warningsstring[]Non-fatal notices (for example, skipped browser open).
request_idstringCorrelation identifier for support and log correlation.
errorobject | nullPopulated on failure; null on success.

Error object fields:

FieldTypeDescription
categorystringStable error class (see error categories).
codestringStable machine-readable code (cli.* for local errors; Gateway error.code when proxied).
messagestringSafe, loggable summary without secrets.
detailsobjectOptional structured context (HTTP status, resource IDs, confirmation hints).

JSON mode writes the envelope to stdout only (including failures). Exit code still reflects success or failure.

Exit codes

CodeMeaning
0Success.
1General failure: usage error, validation error, business-state conflict, or unclassified CLI error.
2Authentication failure: missing, invalid, or expired credentials.
3Authorization failure: authenticated but RBAC or entitlement denied.
4Confirmation required: destructive command run without --yes.
5Gateway or upstream unavailable (503, network failure, timeout).
6Local environment failure: unreadable env file, git-ignore refusal, filesystem permission error.

When Gateway returns a structured error, the CLI maps HTTP status to exit code:

HTTP statusExit codeError category
400, 409, 422, 4281validation
4012auth
4033forbidden
4041not_found
4101gone
4295rate_limit
500, 502, 503, 5045gateway

Error categories

CategoryWhen used
usageUnknown command, invalid flag, or missing required argument.
authCredential missing, malformed, expired, or rejected by Gateway principal lookup.
forbiddenAuthenticated caller lacks the required role or entitlement.
validationRequest rejected because of invalid input or incompatible resource state.
not_foundResource absent in the authenticated tenant scope.
goneTemporary download or export no longer available.
confirmation_requiredDestructive command attempted without --yes.
rate_limitGateway rate limit exceeded.
gatewayUpstream Gateway or dependency error.
networkTransport failure before a structured Gateway response is received.
environmentLocal filesystem, git-ignore, or permission failure.
internalUnexpected CLI bug; should be rare.

Redaction rules

Apply these rules in table output and in any human-readable log lines. JSON data fields follow the per-command schema below; secret fields are omitted or replaced with masked placeholders unless the command explicitly documents a full-value JSON field for automation.

MaterialTable outputJSON data
API key (paybond_sk_*)Mask to paybond_sk_{env}_{first8}...{last4}; fallback paybond_sk_...key_masked in list/read responses; include one-time plaintext api_key only for keys create and keys rotate when the Gateway returns a new secret; never include the raw login secret in JSON (login uses key_written instead)
Capability tokenNever printcapability_token allowed only when the command creates or returns a new token for immediate use (for example, guardrails bootstrap); otherwise omit
Harbor / Gateway bearer tokenNever printNever include
Signing seed / private key materialNever printNever include
Device codes during loginPrint user_code and verification URL (required for approval); never print device_codeInclude user_code and verification_uri; omit device_code
request_id from GatewayPrint when presentAlways echo in envelope and in proxied error details

Key masking algorithm (both kits must match):

  1. Split the key on _.
  2. When the shape is paybond_sk_{environment}_{key_id}_{secret}, emit paybond_sk_{environment}_{key_id[0:8]}...{key_id[-4:]} when len(key_id) > 12, otherwise paybond_sk_{environment}_redacted.
  3. Otherwise emit paybond_sk_....

Command tree

Top-level invocation:

paybond [--global-flags] <command> [<subcommand> ...] [args] [--command-flags]
paybond --help
paybond <command> --help

paybond login

Sandbox device login. Writes PAYBOND_API_KEY to the env file.

FlagDefaultNotes
--env sandboxsandboxOnly sandbox is supported. Live device login is rejected.
--forcefalseReplace an existing PAYBOND_API_KEY in the target env file.

Inherits global flags --gateway, --env-file, --no-open, --format.

Table output (success): verification URL, user code, env file path, masked key, target tenant, optional expiry notice.

login is the one command that intentionally performs a local secret write; it still never prints the raw key.

JSON data fields:

FieldType
env_filestring
key_maskedstring
key_writtenboolean
tenant_idstring
tenant_uuidstring
environmentstring
expires_atstring (RFC 3339, optional)
verification_uristring
user_codestring

paybond init guardrail

Scaffold a sandbox paid-tool guardrail integration file.

FlagDefault
--preset paid-tool-guardpaid-tool-guard
--framework <name>provider-agnostic
--out <path>paybond-paid-tool-guard.ts or paybond_paid_tool_guard.py
--forcefalse

Allowed --framework values: generic, provider-agnostic, openai, claude, anthropic, gemini, google-ai, vercel-ai, langgraph, mcp.

JSON data fields: out, preset, framework, bytes_written.

paybond mcp

SubcommandDescription
serveStart the stdio MCP server (replaces paybond-mcp-server).
installWrite MCP host configuration for Claude, Codex, OpenAI, or generic stdio clients.
toolsList tools exposed by the local MCP server.

mcp install flags:

FlagDefault
--host claude|codex|openai|generic(required)
--scope local|project|userproject
--env-file <path>.env.local

Generated MCP configs must reference PAYBOND_ENV_FILE by default, not embed raw API keys.

JSON data fields (install): host, scope, config_path, server_command, printed. When printed is true (local scope) and --format json is set, payload contains the generated config text.

paybond doctor

Validate local runtime, package version, env file, key shape, principal lookup, and optional agent/MCP setup.

FlagDefault
--agentfalse — when set, also validate MCP server startup and tool listing.

JSON data fields: checks[] with { name, ok, message, details? }, summary (pass | fail).

paybond config

SubcommandDescription
get <key>Read a config value (sensitive values are redacted using the same rules as list).
set <key> <value>Write a config value.
unset <key>Remove a config value.
listList all config entries (values redacted when sensitive).

Config is profile-scoped when --profile is set.

paybond whoami

Resolve the authenticated principal and tenant realm.

JSON data fields: tenant_id, tenant_uuid, environment, service_account_role, principal (Gateway principal payload, secrets stripped).

paybond keys

SubcommandDescriptionDestructive
listList service-account keys for the tenant.
createCreate a new key.
rotate <key_id>Rotate an existing key.yes — requires --yes
revoke <key_id>Revoke a key.yes — requires --yes

JSON data fields (list): keys[] with key_id, key_masked, role, created_at, expires_at, status.

JSON data fields (create, rotate): key_id, key_masked, plus one-time plaintext api_key when the Gateway returns a newly minted secret.

paybond intents

SubcommandDescription
listList intents.
get <intent_id>Fetch one intent.
createCreate an intent.
fund <intent_id>Request funding.
evidence <intent_id>Submit evidence.
settlement-confirm <intent_id>Confirm settlement.

Subcommands accept Gateway-aligned flags for amounts, rails, and idempotency keys. --request-id is forwarded as a correlation header.

paybond guardrails

SubcommandDescription
bootstrapBootstrap a sandbox guardrail intent and capability.
evidenceSubmit sandbox guardrail evidence.

JSON data fields (bootstrap): tenant_id, intent_id, capability_token, operation, requested_spend_cents, sandbox_lifecycle_status.

paybond spend authorize

Authorize delegated spend for a tool call.

JSON data fields: authorized, intent_id, operation, requested_spend_cents, deny_reason (when not authorized).

paybond signal

SubcommandDescription
reputationRead reputation summaries.
portfolioRead portfolio summaries.
fraudRead fraud signals.

Each subcommand accepts resource selectors documented in the SDK references.

paybond receipts

SubcommandDescription
get <receipt_id>Fetch a receipt.
verify <receipt_id>Verify receipt signatures and binding.

paybond mandates

SubcommandDescription
verifyVerify a mandate artifact.
importImport a mandate into the tenant.

paybond a2a

SubcommandDescription
cardAgent card discovery and validation.
contractsContract listing and inspection.

paybond audit exports

SubcommandDescriptionDestructive
listList compliance audit export jobs.
get <job_id>Fetch export job status and download pointers.
verify <path>Verify a downloaded export bundle locally.
delete <job_id>Delete an export job.yes — requires --yes

JSON data fields (list): exports[] with job_id, status, created_at, expires_at, scope.

Security invariants

Both kits must enforce:

  1. No live device login — reject --env live and hidden live flags.
  2. Git-ignore gate — refuse to write secret files that are not ignored inside a git repository (except when adding the default .env.local to .gitignore).
  3. 0600 secret files — env files containing API keys are written with owner-read/write only.
  4. No tenant override — reject --tenant-id and similar unauthenticated tenant selectors on normal commands.
  5. Confirmation gate — refuse destructive subcommands without --yes.
  6. Operator key expectation for login — reject device-login tokens whose role is not operator.

Parity and testing

Both kits must maintain:

  • Snapshot parity for paybond --help and each subcommand --help.
  • JSON shape parity for whoami, doctor, keys list, guardrails bootstrap, and representative error cases.
  • Identical exit codes and error categories for the same failure inputs.
  • Identical key masking output for the same raw key material.

Run kit tests from the repository root:

cd kit/ts && npm run test
cd kit/python && uv run pytest