npm.io
0.2.0 • Published 3d agoCLI

@dhisana-ai/cli

Licence
ISC
Version
0.2.0
Deps
0
Size
75 kB
Vulns
0
Weekly
0

Dhisana CLI

Agent-friendly command line access to Dhisana lead, account, campaign, signal monitoring, and Agentic Flow workflow APIs. The CLI is intentionally dependency-light so tools such as OpenClaw, Codex, or other agent harnesses can shell out to deterministic JSON commands.

Install locally

cd dhisana-cli
npm link

Or run without linking:

node bin/dhisana.js --help

Requires Node.js 18+ for built-in fetch.

Configuration

Every command accepts flags or environment variables:

Flag Environment variable Default
--base-url DHISANA_API_BASE_URL https://api-agent.dhisana.ai
--api-key DHISANA_API_KEY none
--token DHISANA_API_TOKEN none
--agent-instance-id DHISANA_AGENT_INSTANCE_ID none
--agent-instance-name DHISANA_AGENT_INSTANCE_NAME none

API key auth is preferred and is sent as X-API-Key: <key>. --token is still supported for legacy bearer-token flows and is sent as Authorization: Bearer <token>.

The API key can be supplied in raw or pasted-header formats:

dhisana lead lookup --api-key dhisana_key_id.secret --agent-instance-id <uuid> --email buyer@example.com
dhisana lead lookup --api-key "X-API-Key: dhisana_key_id.secret" --agent-instance-id <uuid> --email buyer@example.com
dhisana lead lookup --api-key "Authorization: ApiKey dhisana_key_id.secret" --agent-instance-id <uuid> --email buyer@example.com

Agent instance selection can use an id or an exact name:

dhisana signal review-inbox --agent-instance-id <uuid>
dhisana signal review-inbox --agent-instance-name "Service Cloud RFP"

If neither is provided, the CLI calls GET /v1/agent-instances and automatically uses the only available agent instance. If the API key can access multiple agent instances, pass --agent-instance-id or --agent-instance-name.

Environment variable aliases are also accepted for agent harnesses:

  • DHISANA_API_KEY
  • DHISANA_CLI_API_KEY
  • AGENTOPS_API_KEY

Bearer-token aliases remain:

  • DHISANA_API_TOKEN
  • DHISANA_ACCESS_TOKEN
  • AGENTOPS_API_TOKEN

Commands

Lookup leads
dhisana lead lookup --agent-instance-id <uuid> --id <lead_uuid>
dhisana lead lookup --agent-instance-id <uuid> --email buyer@example.com
dhisana lead lookup --agent-instance-id <uuid> --linkedin-url https://www.linkedin.com/in/example
dhisana lead lookup --agent-instance-id <uuid> --lead-list-id <list_uuid> --search "Jane"

This maps to AgentOps endpoints:

  • GET /v1/agent-instances/{agent_instance_id}/leads/{lead_id}
  • GET /v1/agent-instances/{agent_instance_id}/leads
  • GET /v1/agent-instances/{agent_instance_id}/lead-lists/{lead_list_id}/leads
Add leads to a list

Add existing leads:

dhisana lead add-to-list --agent-instance-id <uuid> --lead-list-id <list_uuid> --lead-ids <lead1>,<lead2>

Create new leads in the list:

dhisana lead add-to-list \
  --agent-instance-id <uuid> \
  --lead-list-id <list_uuid> \
  --name "Jane Buyer" \
  --email jane@example.com \
  --linkedin-url https://www.linkedin.com/in/jane-buyer \
  --title "VP Sales" \
  --company "Acme"

Bulk import from a JSON file:

dhisana lead add-to-list --agent-instance-id <uuid> --lead-list-id <list_uuid> --file leads.json --ignore-duplicates

This maps to:

  • POST /v1/agent-instances/{agent_instance_id}/lead-lists/{lead_list_id}/add-leads
  • POST /v1/agent-instances/{agent_instance_id}/lead-lists/{lead_list_id}/leads/bulk
  • Optional --from-extension uses /leads/bulk_from_extension
Update leads

Update selected lead fields:

dhisana lead update \
  --agent-instance-id <uuid> \
  --id <lead_uuid> \
  --name "Jane Buyer" \
  --title "VP Sales" \
  --company "Acme"

Update from JSON, without overwriting populated fields:

dhisana lead update --agent-instance-id <uuid> --id <lead_uuid> --file lead-update.json --only-if-empty

This maps to:

  • PUT /v1/agent-instances/{agent_instance_id}/leads/{lead_id}
Manage lead tags and notes
dhisana lead add-tag --agent-instance-id <uuid> --id <lead_uuid> --tags hot,enterprise
dhisana lead remove-tag --agent-instance-id <uuid> --lead-ids <lead1>,<lead2> --tags stale

dhisana lead add-note --agent-instance-id <uuid> --id <lead_uuid> --content "Follow up next week"
dhisana lead update-note --agent-instance-id <uuid> --id <lead_uuid> --note-id <note_uuid> --content "Updated note"
dhisana lead remove-note --agent-instance-id <uuid> --id <lead_uuid> --note-id <note_uuid>

Note content can also be supplied with --file <path> or --stdin.

This maps to:

  • POST /v1/agent-instances/{agent_instance_id}/leads/bulk-tags
  • POST /v1/agent-instances/{agent_instance_id}/leads/{lead_id}/notes
  • PUT /v1/agent-instances/{agent_instance_id}/leads/{lead_id}/notes/{note_id}
  • DELETE /v1/agent-instances/{agent_instance_id}/leads/{lead_id}/notes/{note_id}
Lookup accounts
dhisana account lookup --agent-instance-id <uuid> --id <account_uuid>
dhisana account lookup --agent-instance-id <uuid> --domain snowflake.com
dhisana account lookup --agent-instance-id <uuid> --name "Snowflake"
dhisana account lookup --agent-instance-id <uuid> --ai --prompt "the cloud data platform company that IPO'd in 2020"

This maps to:

  • GET /v1/agent-instances/{agent_instance_id}/accounts/{account_id}
  • GET /v1/agent-instances/{agent_instance_id}/accounts/search
  • POST /v1/agent-instances/{agent_instance_id}/accounts/ai-lookup
Add accounts
dhisana account add \
  --agent-instance-id <uuid> \
  --name "Acme" \
  --domain acme.com \
  --website https://www.acme.com \
  --industry "Software"

Bulk import:

dhisana account add --agent-instance-id <uuid> --file accounts.json --bulk --ignore-duplicates

This maps to:

  • POST /v1/agent-instances/{agent_instance_id}/accounts
  • POST /v1/agent-instances/{agent_instance_id}/accounts/bulk
Update accounts

Update selected account fields:

dhisana account update \
  --agent-instance-id <uuid> \
  --id <account_uuid> \
  --name "Acme" \
  --domain acme.com \
  --industry "Software"

Update from JSON, without overwriting populated fields:

dhisana account update --agent-instance-id <uuid> --id <account_uuid> --file account-update.json --only-if-empty

This maps to:

  • PUT /v1/agent-instances/{agent_instance_id}/accounts/{account_id}
Manage account tags and notes
dhisana account add-tag --agent-instance-id <uuid> --id <account_uuid> --tags target,enterprise
dhisana account remove-tag --agent-instance-id <uuid> --account-ids <account1>,<account2> --tags stale

dhisana account add-note --agent-instance-id <uuid> --id <account_uuid> --content "Procurement team owns this account"
dhisana account update-note --agent-instance-id <uuid> --id <account_uuid> --note-id <note_uuid> --content "Updated note"
dhisana account remove-note --agent-instance-id <uuid> --id <account_uuid> --note-id <note_uuid>

Note content can also be supplied with --file <path> or --stdin.

This maps to:

  • POST /v1/agent-instances/{agent_instance_id}/accounts/bulk-tags
  • POST /v1/agent-instances/{agent_instance_id}/accounts/{account_id}/notes
  • PUT /v1/agent-instances/{agent_instance_id}/accounts/{account_id}/notes/{note_id}
  • DELETE /v1/agent-instances/{agent_instance_id}/accounts/{account_id}/notes/{note_id}
Add tasks

Create a task for selected leads:

dhisana task add \
  --agent-instance-id <uuid> \
  --name "Validate emails" \
  --task-type validate_email \
  --lead-ids <lead1>,<lead2>

Create a task for a filtered selection:

dhisana task add \
  --agent-instance-id <uuid> \
  --name "Research target accounts" \
  --task-type research \
  --select-all \
  --filter '{"status":"new"}' \
  --lead-list-id <list_uuid>

Look up tasks:

dhisana task lookup --agent-instance-id <uuid> --id <task_uuid>
dhisana task lookup --agent-instance-id <uuid> --limit 25

This maps to:

  • POST /v1/agent-instances/{agent_instance_id}/tasks/
  • GET /v1/agent-instances/{agent_instance_id}/tasks/
  • GET /v1/agent-instances/{agent_instance_id}/tasks/{task_id}
List campaigns
dhisana campaign list --agent-instance-id <uuid>
dhisana campaign list --agent-instance-id <uuid> --active
dhisana campaign list --agent-instance-id <uuid> --status PAUSED --limit 100

This maps to:

  • GET /v1/agent-instances/{agent_instance_id}/campaigns/

The AgentOps campaign list API is paginated and does not currently expose a server-side status filter, so --active and --status filter the returned page locally. Increase --limit when an agent needs to scan more campaigns.

Get campaign performance

Fetch one campaign by ID:

dhisana campaign performance --agent-instance-id <uuid> --campaign-id <campaign_uuid>

Fetch performance for active campaigns in the current page:

dhisana campaign performance --agent-instance-id <uuid> --active --limit 100

The response includes:

  • summary: compact campaign health for agent harnesses, including send counts, unique leads contacted, engagement KPIs, link click rates, and historical daily rows
  • campaign: raw campaign metadata
  • counter: raw campaign counter from AgentOps
  • link_tracking: raw link tracking summary, unless --skip-link-tracking is provided

Useful options:

dhisana campaign performance --agent-instance-id <uuid> --campaign-id <campaign_uuid> --include-bots
dhisana campaign performance --agent-instance-id <uuid> --active --skip-link-tracking

This maps to:

  • GET /v1/agent-instances/{agent_instance_id}/campaigns/{campaign_id}
  • GET /v1/agent-instances/{agent_instance_id}/campaigns/{campaign_id}/counter
  • GET /v1/agent-instances/{agent_instance_id}/campaigns/{campaign_id}/link-tracking/summary
Invoke an Agentic Flow workflow

Run a workflow once by ID:

dhisana workflow run --agent-instance-id <uuid> --workflow-id <workflow_uuid>

Run a workflow once by exact name, with parameters:

dhisana workflow run \
  --agent-instance-id <uuid> \
  --workflow-name "Test Workflow" \
  --parameters '{"company":"Acme"}'

Start from scratch instead of resuming saved offsets:

dhisana workflow run --agent-instance-id <uuid> --workflow-name "Test Workflow" --from-scratch

Useful options:

dhisana workflow run --agent-instance-id <uuid> --workflow-name "Test Workflow" --record-limit 10
dhisana workflow run --agent-instance-id <uuid> --workflow-name "Test Workflow" --run-as-user-id <user_uuid>
dhisana workflow run --agent-instance-id <uuid> --workflow-id <workflow_uuid> --parameters-file params.json
dhisana workflow run --agent-instance-id <uuid> --workflow-id <workflow_uuid> --offset-overrides '{"apollo-source":0}'

The response includes:

  • summary: workflow id, name, returned status, whether the start was accepted, from-scratch flag, record limit, run-as user, and whether parameters/offset overrides were sent
  • workflow: raw Agentic Flow payload returned by AgentOps

This maps to:

  • GET /v1/agent-instances/{agent_instance_id}/smart-lists/{workflow_id}
  • GET /v1/agent-instances/{agent_instance_id}/smart-lists/ when resolving by name
  • PUT /v1/agent-instances/{agent_instance_id}/smart-lists/{workflow_id} when persisting --record-limit or --run-as-user-id
  • POST /v1/agent-instances/{agent_instance_id}/smart-lists/{workflow_id}/start?clear_offset=<true|false>
List Signal Monitoring Review inbox items
dhisana signal review-inbox --agent-instance-id <uuid>
dhisana signal review-inbox --agent-instance-id <uuid> --limit 100 --sort-by priority_score
dhisana signal review-inbox --agent-instance-id <uuid> --item-type candidate --review-status OPEN --routing-status OPEN
dhisana signal review-inbox --agent-instance-id <uuid> --assigned-scope my_groups --reviewer-group-id <group_uuid>

Common filters:

dhisana signal review-inbox --agent-instance-id <uuid> --signal-type rfp_watch --object-type account
dhisana signal review-inbox --agent-instance-id <uuid> --policy-id <policy_uuid>
dhisana signal review-inbox --agent-instance-id <uuid> --source-provider opengov --rfp-status active

The response includes:

  • summary: compact Review inbox counts and item summaries for agent harnesses
  • raw items, by_review_status, by_routing_status, and by_policy from AgentOps
Get one Signal Monitoring Review inbox item
dhisana signal review-item --agent-instance-id <uuid> --item-id <item_uuid> --item-type candidate
dhisana signal review-item --agent-instance-id <uuid> --review-assignment-id <assignment_uuid>

Use --item-type signal, --item-type candidate, or --item-type opportunity_rollup when the item type is known. If omitted, the backend searches all Review inbox item types.

This maps to:

  • GET /v1/agent-instances/{agent_instance_id}/signal-review-queue

Extending

Add a command by creating a module under src/commands/ and registering it in src/cli.js.

Each command receives:

{
  (options, config, fetchImpl);
}

Use DhisanaApiClient from src/apiClient.js so auth, base URL normalization, JSON parsing, and errors stay consistent.