Sennithsennith.
Developer

CLI

Install the sennith command-line tool, manage a local key ring, and drive your workspace from the terminal.

The sennith CLI lets you drive your workspace — projects, customers, updates, webhooks, settings — straight from the terminal, or from an AI agent. It talks to the same REST API, so anything the API can do, the CLI can do too. Every command accepts --json for machine-readable output, and every error exits with a non-zero status code, so it scripts cleanly.

Install

The CLI runs on Node 18 or newer. The quickest way to try it is with npx:

npx sennith --help

Sign in

Run login once to store your API base URL and a key. Credentials are saved to ~/.sennith/config.json; your token is never printed back to you.

sennith login
# → asks for the API base URL (e.g. https://sennith.com)
#   and a workspace API key (sennith_…)

You create API keys in the web app under Settings → API keys. See Public API for how keys, levels, and scopes work.

Info

Prefer environment variables? Set SENNITH_API_URL and SENNITH_TOKEN instead of logging in. They override the config file and are never written to disk — handy for CI and agents.

The key ring

You can keep several keys side by side — for example one per workspace, or a read-only key next to a full-access one — and switch between them. Tokens are never printed by any of these commands.

Add a key

sennith key add work --token sennith_...

Leave off --token to be prompted for it with hidden input. Right after saving, Sennith verifies the key and shows its level, organization, workspace, and scopes so you can see exactly what it can do.

List your keys

sennith key ls

The active key is marked with a ★.

Switch the active key

sennith key use work

To use a different key for a single command without changing the default, add the global --key <name> flag to that command.

Remove a key

sennith key rm work
Warning

This only deletes the local entry. It does not revoke the key on the server — to actually invalidate a key, revoke it in the web app under Settings → API keys (or your organization settings).

whoami

Check the identity of the active key — its level, organization, workspace, and scopes — without ever revealing the token:

sennith whoami
  level:       workspace
  orgId:       7
  workspaceId: 12
  scopes:      projects:read, projects:write, updates:write

Working with resources

Resource commands are generated from the API contract, so they all follow the same shape:

sennith <resource> list [--limit n] [--cursor id] [--json]
sennith <resource> get <id> [--json]
sennith <resource> create --<field> <value>          # if the resource is writable
sennith <resource> update <id> --<field> <value>     # if the resource is writable
sennith <resource> delete <id> [--yes]                 # if deletable; asks to confirm unless --yes

Some examples:

# List projects as JSON
sennith projects list --json

# Create a project and a customer
sennith projects create --name "Acme relaunch"
sennith customers create --name "Acme" --email "ops@acme.com"

# Post an update to project 7 (sends emails + fires your webhooks)
sennith updates create --project 7 --title "Deployed v2" --is-important

# List a customer's contacts
sennith customer_contacts list --customer 12

Field names come straight from the resource, passed as --kebab-case flags (a field like isImportant becomes --is-important). Sub-resources — such as updates and triggers under a project, or customer_contacts under a customer — need their parent's id via a --<parent> flag. Singletons like workspace and org support only get and update (no id).

Info

Run sennith --help to see every available resource, and sennith <resource> --help to see its fields and which actions it supports.

Built for agents

A few touches make the CLI easy to hand to an automated tool:

  • --json on any command for structured output.
  • delete asks for confirmation interactively, but --yes (or -y) skips the prompt for non-interactive runs.
  • Distinct exit codes per failure type — for example a missing plan, a missing scope, or a rate limit each exit with their own code — so a script can react without parsing error text.

Where to go next

Was this helpful?

On this page