senv, the command-line client
Closed source, freely downloadable under the EULA, and an API client only:
it talks to the SignEnvoy API and nothing else, and sends no telemetry.
Every read command takes --json; exit codes are 0 (ok),
1 (your input, or a 4xx), 2 (the API or the network).
NO_COLOR is honoured.
Install
# Homebrew (macOS and Linux)
brew tap signenvoy/signenvoy
brew install --cask senv
# npm
npm install -g @signenvoy/cli
# install script (macOS and Linux): downloads, verifies the signed checksum, installs to ~/.local/bin
curl -fsSL https://get.signenvoy.com/install.sh | sh
Direct downloads, checksums, and how to verify them:
signenvoy.com/downloads.
senv upgrade installs later releases after verifying their
signature against the key embedded in the binary.
Sign in
senv login # opens the dashboard's approval page; the key lands in your keychain
senv login --mode test
senv whoami
senv status # workspace, allowance, fair-use limits senv login uses the device flow:
the terminal prints a code, you approve it in the dashboard (which shows
what it is about to create), and the key is minted on collection. In CI,
set SENV_API_KEY instead; --profile keeps several
workspaces apart.
Global flags
| Flag | What it does |
|---|---|
--accept-eula | accept the EULA non-interactively (or set SENV_ACCEPT_EULA=1) |
--api-url | API origin (default: SENV_API_URL, the profile, then https://api.signenvoy.com) |
--json | print the API response as JSON |
--no-color | disable colour (NO_COLOR is also honoured) |
--no-keychain | store credentials in the config file instead of the OS keychain |
--profile | profile to use (default: SENV_PROFILE or the configured default) |
Commands
senv bulk: Send one document per CSV row from a templatesenv doc: Create, send, watch, and download documentssenv folder: Organize documents into folders (organization only)senv keys: Manage API keyssenv legal: Show the license and third-party noticessenv login: Sign in through the browser and store an API key for this profilesenv logout: Forget the stored API key for this profilesenv status: Show the workspace, allowance, fair-use limits, and this clientsenv template: Templates as code: push, pull, update, list, and usesenv upgrade: Install the latest release after verifying its signaturesenv version: Print the senv versionsenv webhook: Manage webhook endpoints and stream eventssenv whoami: Show the workspace and key the current profile uses
senv bulk
Send one document per CSV row from a template
senv bulk cancel <id>
Stop a batch: rows not yet sent are canceled and refunded; sent documents stay sent
senv bulk create <template-id> <rows.csv>
create parses the CSV locally and posts its rows. Columns: recipient{n}_name and recipient{n}_email for each template role (n = 1-based signing position), then one column per field name (or 0-based index) to prefill. UTF-8, header row required; an unknown column is an error, not dropped. Every row is validated before anything is created; if any row is invalid the batch is not sent and the problems are listed per row. With --dispatch the batch is sent after the consequence is confirmed (--yes skips the prompt); without it, dispatch later with: senv bulk status / dispatch.
| Flag | What it does |
|---|---|
--dispatch | send the batch after creating it |
--yes | do not ask for confirmation before dispatching |
senv bulk dispatch <id>
Send a batch that was created without --dispatch
| Flag | What it does |
|---|---|
--yes | do not ask for confirmation |
senv bulk list
List batches
| Flag | What it does |
|---|---|
--limit | page size (default: 50) |
--offset | page offset (default: 0) |
senv bulk status <id>
Show a batch's progress and its rows (--failed to narrow, --watch to follow)
| Flag | What it does |
|---|---|
--failed | show only failed rows |
--watch | refresh every 3 s until the batch finishes |
senv doc
Create, send, watch, and download documents
senv doc create
create uploads a PDF and registers its recipients and fields. Fields use TYPE[@RECIPIENT]:PAGE:X,Y[,W,H] with coordinates as fractions of the page (0..1, top-left origin), for example sig:1:0.12,0.54. RECIPIENT is the 1-based --signer position or a signer's email; the default is the first.
| Flag | What it does |
|---|---|
--approver | recipient who approves before signers (repeatable) (default: []) |
--cc | recipient who receives a copy (repeatable) (default: []) |
--expires-at | expiry (RFC 3339, e.g. 2026-09-30T00:00:00Z) |
--field | field placement TYPE[@RECIPIENT]:PAGE:X,Y[,W,H] (repeatable) (default: []) |
--file | PDF to send (required) |
--message | message included in the invitation email |
--redirect-url | https URL recipients land on after signing |
--reminder-days | automatic reminder cadence in days (0 = none) (default: 0) |
--send | send immediately after creating |
--sequential | signers sign one after another in the given order |
--signer | recipient who signs: "Name <email>" or an email (repeatable, in order) (default: []) |
--title | document title (default: the file name) |
senv doc download <id>
Download the sealed PDF, the original, or the certificate
| Flag | What it does |
|---|---|
--force | overwrite an existing file |
--output, -o | output path, or - for stdout (default: the server's file name) |
--variant | signed|original|certificate (default: signed) |
senv doc duplicate <id>
Start a new draft from a document (same PDF, people, and fields; nothing is sent)
| Flag | What it does |
|---|---|
--title | title for the new draft (default: the original's) |
senv doc get <id>
Show a document
| Flag | What it does |
|---|---|
--events | include the audit event history |
senv doc list
List documents (filter by status, folder, search text, or bulk send)
| Flag | What it does |
|---|---|
--all | fetch every page |
--batch | only the member documents of this bulk send (hidden otherwise) |
--folder | only documents in this folder (a folder id; see senv folder list) |
--limit | page size (1..200) (default: 50) |
--offset | page offset (default: 0) |
--q | search title, recipient names and emails, and the source template's name |
--sort | created (default) or activity |
--status | filter: draft|sent|partially_signed|completed|voided|rejected|expired or pending (= sent,partially_signed) |
senv doc send <id>
Send a document to its recipients
| Flag | What it does |
|---|---|
--message | message included in the invitation email |
senv doc void <id>
Void a document that is in progress
| Flag | What it does |
|---|---|
--reason | why the document is being voided (recipients are told) |
senv folder
Organize documents into folders (organization only)
senv folder create <name>
Create a folder (at the root, or under --parent)
| Flag | What it does |
|---|---|
--parent | parent folder id (default: the root) |
senv folder list
List folders as a tree
senv folder move <id>
Move a folder under another folder, or to the root
| Flag | What it does |
|---|---|
--parent | new parent folder id (omit to move to the root) |
senv folder rename <id> <name>
Rename a folder
senv folder rm <id>
Delete a folder; its documents and subfolders move up one level
| Flag | What it does |
|---|---|
--yes | do not ask for confirmation |
senv keys
Manage API keys
senv keys create
Create an API key (the key is shown once)
| Flag | What it does |
|---|---|
--mode | live or test (test keys never count and capture email) (default: live) |
--name | a label for the key, e.g. ci |
senv keys list
List API keys (prefix and last four only)
senv keys revoke <id>
Revoke an API key immediately
senv legal
Show the license and third-party notices
senv legal eula
Print the end-user license agreement
senv legal notices
Print third-party license notices
senv login
login starts a browser sign-in: it prints a code, opens the SignEnvoy dashboard, and waits for you to approve. The dashboard mints an API key for the workspace you approve in, and senv stores it in the OS keychain (or the config file with mode 0600 when no keychain is available). --api-key skips the browser and stores a key you already have.
| Flag | What it does |
|---|---|
--api-key | store this key instead of signing in through the browser |
--mode | ask for a live or test key (live|test) |
--name | name for the key the dashboard creates (default cli:<hostname>) |
--no-browser | print the verification URL instead of opening a browser |
senv logout
Forget the stored API key for this profile
| Flag | What it does |
|---|---|
--revoke | also revoke the key on the server |
senv status
Show the workspace, allowance, fair-use limits, and this client
senv template
Templates as code: push, pull, update, list, and use
senv template duplicate <id>
Copy a template (same PDF, roles, and fields) under a new id
| Flag | What it does |
|---|---|
--name | name for the copy (default: "<name> (copy)") |
senv template list
List templates
| Flag | What it does |
|---|---|
--limit | page size (default: 50) |
--offset | page offset (default: 0) |
senv template pull <id>
Write a template's definition as YAML (every field setting included)
| Flag | What it does |
|---|---|
--output, -o | write YAML here instead of stdout |
senv template push <template.yaml>
push creates a new template from a definition file and the PDF it names. Fields carry everything the dashboard editor can express (name, read_only, prefill, max_length, pattern, min_value/max_value, input_modes, options); unknown keys are refused rather than dropped. To change an existing template, use update.
senv template rm <id>
Delete a template (documents already created from it are unaffected)
| Flag | What it does |
|---|---|
--yes | do not ask for confirmation |
senv template update <id> <template.yaml>
update replaces the template's name, roles, and fields with the definition file (the PDF line is ignored: the document itself does not change). Every update is a new version. Documents already created from the template keep the definition they were made with; the next use takes the new one.
senv template use <id>
use binds real recipients to the template's placeholders by position (--signer in the template's order) and prefills fields with --var. Keys are field names ("--var po_number=PO-1"); a field's 0-based index as a string ("--var 0=Ada") still works. A key that matches no field is refused by the API (422 validation-failed naming the key); nothing is dropped silently.
| Flag | What it does |
|---|---|
--signer | recipient bound to the next placeholder: "Name <email>" (repeatable, in order) (default: []) |
--title | document title (default: the template's) |
--var | prefill a field by name (or index): NAME=VALUE (repeatable) (default: []) |
senv upgrade
upgrade fetches the release manifest and its minisign signature from get.signenvoy.com, verifies both against the keys built into this binary, downloads this platform's build, checks its SHA-256 against the manifest and the separately signed checksums.txt, and replaces the running binary. Homebrew and npm installs are pointed at their package manager instead.
| Flag | What it does |
|---|---|
--check | only report whether a newer release exists |
--version | install this version instead of the latest |
--yes | do not ask for confirmation (required for downgrades) |
senv version
Print the senv version
senv webhook
Manage webhook endpoints and stream events
senv webhook add <https-url>
Register an endpoint (the signing secret is shown once)
| Flag | What it does |
|---|---|
--events | event types to deliver, comma-separated or repeated (default: all) (default: []) |
senv webhook deliveries <id>
List delivery attempts for an endpoint
| Flag | What it does |
|---|---|
--limit | rows (1..200) (default: 50) |
--status | filter: queued|delivering|delivered|dead |
senv webhook disable <id>
Stop deliveries to an endpoint without deleting it
senv webhook list
List endpoints
senv webhook ping <id>
Queue a test delivery (type "ping", signed like any event)
senv webhook redeliver <id> <delivery-id>
Queue a dead or delivered attempt again
senv webhook rm <id>
Delete an endpoint and its delivery history
| Flag | What it does |
|---|---|
--yes | do not ask for confirmation |
senv webhook rotate-secret <id>
Mint a new signing secret (shown once); the old one keeps signing for 24 hours
senv webhook tail
tail opens the gateway's event stream and prints each canonical event as it happens. With --forward it POSTs every event to a local URL with the production headers, signing with --secret (or SENV_WEBHOOK_SECRET) exactly as real deliveries are signed, so a handler can be developed without a tunnel. The stream resumes from the last event id after a drop and follows the server's periodic reconnect.
| Flag | What it does |
|---|---|
--events | only these event types (comma-separated or repeated) (default: []) |
--forward | POST each event to this local URL with production headers |
--max-retries | consecutive connection failures before giving up (default: 10) |
--secret | webhook signing secret for --forward (or SENV_WEBHOOK_SECRET) |
--since | resume after this event id (evt_outbox_N); default: live from now |
senv webhook update <id>
Change an endpoint's URL or events, or re-enable it (--active=true)
| Flag | What it does |
|---|---|
--active | true to re-enable a disabled endpoint, false to pause it |
--events | event types to deliver, comma-separated or repeated (empty = all) (default: []) |
--url | new https URL |
senv whoami
Show the workspace and key the current profile uses
Local webhook development
senv webhook tail --forward http://localhost:3000/hooks --secret sewh_...
Streams your workspace's events over the event stream
and, with --forward, posts each one to a local handler with the
same X-SignEnvoy-Signature a production delivery carries, so
your verification code runs unchanged. --status pending on
senv doc list is client-side shorthand for
sent,partially_signed; the API only ever sees real statuses.