DotsDocs

Dots CLI

Install, authenticate, and use the Dots CLI safely from a terminal or AI agent.

The Dots CLI (dots) provides friendly commands for common Dots resources and access to every operation in the documented Dots API.

Install

On macOS or Linux, install the latest release:

curl -fsSL https://github.com/Send-Dots/dots-cli/releases/latest/download/install.sh | sh

The installer places dots in $HOME/.local/bin by default and verifies the download against the release checksums. You can also install the CLI through npm on macOS, Linux, or Windows:

npm install --global @usedots/cli

The npm package requires Node.js 18 or later. Windows users can alternatively download the Windows ZIP archive from the latest GitHub release and extract dots.exe.

Verify the installation:

dots --version
dots --help

Choose an environment

The environment flag is global. Place it before the command so the destination is clear:

EnvironmentCommand prefixUse
ProductiondotsLive Dots account and funds
Sandboxdots --sandboxDevelopment and testing

Sandbox and production have separate credentials. The CLI uses production when you omit an environment flag; add --sandbox when you want to test against Sandbox.

Authenticate

Interactive login

Sign in with your Dots dashboard account:

dots login
dots auth status

The CLI opens the dashboard so you can choose the App it may access. Paste the five-minute, single-use authorization code into the terminal. The resulting session lasts 72 hours and is stored in your operating system’s credential store. Dots checks your current App membership and role on every request.

To revoke and remove the session:

dots logout

Add --sandbox before these commands to manage a separate Sandbox session.

API keys for automation

Use API keys for unattended scripts and AI agents. Supply credentials through a secret manager or environment variables:

export DOTS_CLIENT_ID='your-client-id'
export DOTS_API_KEY='your-secret-api-key'
dots doctor --check-api

When using organization credentials to act for an App, also set:

export DOTS_APP_ID='your-app-id'

In a headless environment, use explicit environment variables instead of a saved login. See API Authentication for information about App and organization keys.

Read-only API keys for agents

When an agent or automation only needs to inspect data, create a named read-only API key from API Management in the Dots dashboard. Configure the CLI with the read-only key’s client ID and API key just like any other API credentials:

export DOTS_CLIENT_ID='your-read-only-client-id'
export DOTS_API_KEY='your-read-only-api-key'
dots --json doctor --check-api

When verification succeeds, auth.api_key_mode is read_only. You can also verify access with a read request:

dots --json transfers list --query limit=1

Read-only keys are enforced by the Dots API. Requests that create, update, or delete resources are rejected with 403 Forbidden, even if a caller bypasses the CLI’s local safeguards. Use a full-access key only when the automation must perform writes.

Security

  • Never put credentials in prompts, source control, command arguments, or custom headers. Prefer environment variables supplied by your secrets manager.
  • Preview writes with --dry-run before sending them. Dry runs do not make an API request.
  • Reuse an idempotency key when retrying a write so the same operation is not performed twice.
  • Do not manually supply an Authorization header. The CLI rejects it and applies configured credentials without exposing them in output.
  • Use --json for automation. Structured output omits configured credentials, custom header values, and multipart values. Request bodies remain visible in dry-run previews, so do not include credentials or other secrets in them.

Add a local read-only safeguard

For defense in depth, set DOTS_READ_ONLY=1 in addition to using a server-enforced read-only API key. The CLI then refuses every non-GET/HEAD API request locally while still allowing dry-run previews:

export DOTS_READ_ONLY=1
dots --json transfers list
dots users create --body-file ./user.json --dry-run

If an agent needs ordinary writes but must not move money, use:

export DOTS_BLOCK_MONEY_MOVEMENT=1
dots users create --body-file ./user.json --dry-run

This guard blocks live requests involving transfers, payouts, payout links, payout batches and requests, payments, payable payments, wallet deposits and withdrawals, and organization transfers.

Configure these variables outside the agent’s control. A local guard cannot protect a full-access key if the agent can unset or override it. Use a server-enforced read-only API key when writes must never be allowed.

Use with AI agents

Install the CLI’s bundled agent skill interactively:

dots skill install

For non-interactive installation, choose the scope and agent harness explicitly:

dots skill install --project --harness all
dots skill install --global --harness .agents

Project scope installs into the current Git repository. Global scope makes the skill available across projects. The .agents harness supports Codex, OpenCode, and OpenClaw; claude and hermes are also available. Current Hermes releases require global scope.

For reliable agent use:

  1. Give the agent only the environment it needs and keep the guard variable outside its control.
  2. Select the intended environment explicitly and use --json when reading command output.
  3. Require --dry-run for every write.
  4. Review the preview before allowing a live write. All money-moving requests, including payouts and payout batches, require --confirm in JSON or non-interactive mode.

Run as an MCP server

Agents that support the Model Context Protocol (MCP) can use the CLI as a local MCP server. dots --mcp communicates over stdio and does not open a network port. Add it to your MCP client’s configuration:

{
  "mcpServers": {
    "dots": {
      "command": "dots",
      "args": ["--sandbox", "--mcp"],
      "env": {
        "DOTS_READ_ONLY": "1"
      }
    }
  }
}

In Claude Code, the equivalent command is:

claude mcp add dots -e DOTS_READ_ONLY=1 -- dots --sandbox --mcp

Remove --sandbox for production, and remove DOTS_READ_ONLY only when the agent needs to write. The environment, credentials, App, and safety variables are fixed when the server starts. Tool arguments cannot change them.

The server provides two tools:

  • search_tools finds CLI operations by keyword, such as send payout or list users, and returns each operation’s name, description, and input schema. An empty query matches every operation. Results are capped by limit, which defaults to 10 and accepts up to 100.
  • execute_tool runs an operation by name with arguments that match its schema:
{
  "name": "dots_users_list",
  "arguments": { "query": ["limit=10"] }
}

Because execute_tool can run writes, MCP clients treat it as a write tool. If your client asks for approval before writes, it will ask for every call, including reads.

Operations cover the same commands as the CLI, including dots_call and dots_request for any documented API operation. Skill installation, configuration, and doctor are not available over MCP.

To sign in without API keys, have the agent run dots_login_start, open the returned URL, authorize an App, and pass the copied code to dots_login_exchange. The session is saved in your operating system’s credential store and is never returned to the agent. In headless environments, set DOTS_CLIENT_ID and DOTS_API_KEY in the server’s env instead.

MCP applies the same write rules as the CLI. Money-moving operations require confirm: true for live requests; use dry_run: true to preview first. Live dots_call and dots_request writes other than GET or HEAD always require confirm: true and are refused when DOTS_READ_ONLY or DOTS_BLOCK_MONEY_MOVEMENT is set.

File inputs such as body_file are disabled by default. To allow them, set DOTS_MCP_FILE_ROOT in the server’s env to an absolute directory path. The server rejects any file outside that directory.

Each operation times out after 120 seconds. A timed-out or cancelled payout may still have been submitted. Check its status before retrying, and supply your own idempotency_key so a retry cannot send the payout twice.

Common workflows

Check configuration

dots doctor --check-api
dots config show

config show reports only non-secret settings.

Discover commands

Use the CLI’s current help and API catalog instead of relying on memorized syntax:

dots users --help
dots operations list --tag users
dots operations show get-user

List and retrieve resources

Friendly commands cover users, transfers, transactions, vendors, flows, payout links, payouts, payout batches, and apps:

dots --json users list --query limit=10
dots --json users get USER_UUID
dots --json transfers get TRANSFER_UUID
dots --json transactions list --query limit=10
dots --json transactions get TRANSACTION_ID
dots --json flows get FLOW_UUID
dots --json apps list

Use transfers to inspect a transfer and transactions to inspect the ledger entries created by transfers and other money movement.

Manage payout batches

List a batch, inspect its processing state, and retrieve its item-level results:

dots --json payout-batches list --query limit=10
dots --json payout-batches get PAYOUT_BATCH_UUID
dots --json payout-batches results PAYOUT_BATCH_UUID

Preview batch creation from a JSON file before submitting it:

dots payout-batches create --body-file ./payout-batch.json --dry-run

The batch preview includes a generated body.idempotency_key. Reuse it with --idempotency-key on the confirmed command. In JSON or non-interactive mode, the create command requires --confirm; call and request enforce the same gate for money-moving endpoints.

Manage vendors and payment methods

Use the accounts-payable vendor commands to list or retrieve vendors and to preview create or delete requests:

dots --json vendors list --query limit=10
dots --json vendors get VENDOR_UUID
dots vendors create --body-file ./vendor.json --dry-run
dots vendors delete VENDOR_UUID --dry-run

Payment-method commands are nested under their vendor. Both the vendor ID and payment-method ID are positional arguments where required:

dots --json vendors payment-methods list VENDOR_UUID
dots --json vendors payment-methods get VENDOR_UUID PAYMENT_METHOD_UUID
dots vendors payment-methods create VENDOR_UUID \
  --body-file ./payment-method.json \
  --dry-run
dots vendors payment-methods delete VENDOR_UUID PAYMENT_METHOD_UUID --dry-run

Payment-method previews replace account_number and routing_number values with [REDACTED]. The CLI does not offer idempotency keys for vendor writes because these API routes do not support idempotent retries.

Manage payables

List and retrieve payables, or preview creation from JSON:

dots --json payables list --query limit=10
dots --json payables get PAYABLE_UUID
dots payables create --body-file ./payable.json --dry-run
dots payables update PAYABLE_UUID --body-file ./payable-update.json --dry-run

Create a payable directly from a PDF by providing the acting user and file. The CLI constructs the required multipart fields:

dots payables create-from-file \
  --acting-user-id ACTING_USER_UUID \
  --file ./invoice.pdf \
  --dry-run

The payable file endpoint accepts a base64-encoded file in a JSON body. You can also remove the current file:

dots payables upload-file PAYABLE_UUID --body-file ./payable-file.json --dry-run
dots payables delete-file PAYABLE_UUID --dry-run

Lifecycle actions require a JSON body containing acting_user_id; cancel, submit, approve, and reject may also include a comment:

dots payables cancel PAYABLE_UUID --body '{"acting_user_id":"ACTING_USER_UUID"}' --dry-run
dots payables submit PAYABLE_UUID --body '{"acting_user_id":"ACTING_USER_UUID"}' --dry-run
dots payables approve PAYABLE_UUID --body '{"acting_user_id":"ACTING_USER_UUID"}' --dry-run
dots payables reject PAYABLE_UUID --body '{"acting_user_id":"ACTING_USER_UUID"}' --dry-run
dots payables pay PAYABLE_UUID --body '{"acting_user_id":"ACTING_USER_UUID"}' --dry-run

Paying an approved payable moves money and is blocked when DOTS_BLOCK_MONEY_MOVEMENT=1. Always review the dry-run preview before sending a lifecycle write.

Preview a write

Pass request JSON inline or read it from a file:

dots users create --body-file ./user.json --dry-run
dots transfers create --body-file ./transfer.json --dry-run

After reviewing the preview, remove --dry-run to send the request. For a money-moving request such as transfers create, also pass --confirm. Scripts and --json mode cannot submit money-moving requests without it.

Call any documented API operation

When a friendly resource command is not available, discover and call the OpenAPI operation:

dots operations show get-user
dots --json call get-user --path user_id=USER_UUID
dots call create-transfer \
  --body-file ./transfer.json \
  --dry-run

Use --path NAME=VALUE for path parameters, --query NAME=VALUE for query parameters, and --body or --body-file for JSON request bodies.

Send a payout

Amounts are expressed in cents. First preview the payout:

dots --json payouts send \
  --amount-cents 100 \
  --user USER_UUID \
  --memo "CLI payout" \
  --dry-run

The preview includes an automatically generated idempotency key. Copy that key into the approved request:

dots --json payouts send \
  --amount-cents 100 \
  --user USER_UUID \
  --memo "CLI payout" \
  --idempotency-key IDEMPOTENCY_UUID \
  --confirm

--amount-cents 100 sends $1.00. Never add --confirm until the dry-run preview has been reviewed.

Troubleshooting

dots auth status
dots doctor --check-api
dots payouts send --help
  • If authentication expired, run dots login again.
  • If doctor cannot reach the API, confirm the environment and network.
  • If an argument is rejected, inspect that exact command with --help.
  • If an agent write is refused, check whether DOTS_READ_ONLY or DOTS_BLOCK_MONEY_MOVEMENT was intentionally enabled. Do not disable a guard to bypass the refusal.