SignEnvoy docs

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

FlagWhat it does
--accept-eulaaccept the EULA non-interactively (or set SENV_ACCEPT_EULA=1)
--api-urlAPI origin (default: SENV_API_URL, the profile, then https://api.signenvoy.com)
--jsonprint the API response as JSON
--no-colordisable colour (NO_COLOR is also honoured)
--no-keychainstore credentials in the config file instead of the OS keychain
--profileprofile to use (default: SENV_PROFILE or the configured default)

Commands

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.

FlagWhat it does
--dispatchsend the batch after creating it
--yesdo not ask for confirmation before dispatching

senv bulk dispatch <id>

Send a batch that was created without --dispatch

FlagWhat it does
--yesdo not ask for confirmation

senv bulk list

List batches

FlagWhat it does
--limitpage size (default: 50)
--offsetpage offset (default: 0)

senv bulk status <id>

Show a batch's progress and its rows (--failed to narrow, --watch to follow)

FlagWhat it does
--failedshow only failed rows
--watchrefresh 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.

FlagWhat it does
--approverrecipient who approves before signers (repeatable) (default: [])
--ccrecipient who receives a copy (repeatable) (default: [])
--expires-atexpiry (RFC 3339, e.g. 2026-09-30T00:00:00Z)
--fieldfield placement TYPE[@RECIPIENT]:PAGE:X,Y[,W,H] (repeatable) (default: [])
--filePDF to send (required)
--messagemessage included in the invitation email
--redirect-urlhttps URL recipients land on after signing
--reminder-daysautomatic reminder cadence in days (0 = none) (default: 0)
--sendsend immediately after creating
--sequentialsigners sign one after another in the given order
--signerrecipient who signs: "Name <email>" or an email (repeatable, in order) (default: [])
--titledocument title (default: the file name)

senv doc download <id>

Download the sealed PDF, the original, or the certificate

FlagWhat it does
--forceoverwrite an existing file
--output, -ooutput path, or - for stdout (default: the server's file name)
--variantsigned|original|certificate (default: signed)

senv doc duplicate <id>

Start a new draft from a document (same PDF, people, and fields; nothing is sent)

FlagWhat it does
--titletitle for the new draft (default: the original's)

senv doc get <id>

Show a document

FlagWhat it does
--eventsinclude the audit event history

senv doc list

List documents (filter by status, folder, search text, or bulk send)

FlagWhat it does
--allfetch every page
--batchonly the member documents of this bulk send (hidden otherwise)
--folderonly documents in this folder (a folder id; see senv folder list)
--limitpage size (1..200) (default: 50)
--offsetpage offset (default: 0)
--qsearch title, recipient names and emails, and the source template's name
--sortcreated (default) or activity
--statusfilter: draft|sent|partially_signed|completed|voided|rejected|expired or pending (= sent,partially_signed)

senv doc send <id>

Send a document to its recipients

FlagWhat it does
--messagemessage included in the invitation email

senv doc void <id>

Void a document that is in progress

FlagWhat it does
--reasonwhy 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)

FlagWhat it does
--parentparent 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

FlagWhat it does
--parentnew 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

FlagWhat it does
--yesdo not ask for confirmation

senv keys

Manage API keys

senv keys create

Create an API key (the key is shown once)

FlagWhat it does
--modelive or test (test keys never count and capture email) (default: live)
--namea 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 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.

FlagWhat it does
--api-keystore this key instead of signing in through the browser
--modeask for a live or test key (live|test)
--namename for the key the dashboard creates (default cli:<hostname>)
--no-browserprint the verification URL instead of opening a browser

senv logout

Forget the stored API key for this profile

FlagWhat it does
--revokealso 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

FlagWhat it does
--namename for the copy (default: "<name> (copy)")

senv template list

List templates

FlagWhat it does
--limitpage size (default: 50)
--offsetpage offset (default: 0)

senv template pull <id>

Write a template's definition as YAML (every field setting included)

FlagWhat it does
--output, -owrite 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)

FlagWhat it does
--yesdo 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.

FlagWhat it does
--signerrecipient bound to the next placeholder: "Name <email>" (repeatable, in order) (default: [])
--titledocument title (default: the template's)
--varprefill 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.

FlagWhat it does
--checkonly report whether a newer release exists
--versioninstall this version instead of the latest
--yesdo 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)

FlagWhat it does
--eventsevent types to deliver, comma-separated or repeated (default: all) (default: [])

senv webhook deliveries <id>

List delivery attempts for an endpoint

FlagWhat it does
--limitrows (1..200) (default: 50)
--statusfilter: 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

FlagWhat it does
--yesdo 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.

FlagWhat it does
--eventsonly these event types (comma-separated or repeated) (default: [])
--forwardPOST each event to this local URL with production headers
--max-retriesconsecutive connection failures before giving up (default: 10)
--secretwebhook signing secret for --forward (or SENV_WEBHOOK_SECRET)
--sinceresume 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)

FlagWhat it does
--activetrue to re-enable a disabled endpoint, false to pause it
--eventsevent types to deliver, comma-separated or repeated (empty = all) (default: [])
--urlnew 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.