close-crm-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +566 -0
- package/CLAUDE.md +148 -0
- package/README.md +242 -0
- package/dist/index.js +4560 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.js +4262 -0
- package/dist/mcp.js.map +1 -0
- package/package.json +52 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
# AI Agent Guide — Close CRM CLI
|
|
2
|
+
|
|
3
|
+
> This file helps AI agents (Claude, GPT, Gemini, open-source models) install, authenticate, and use the Close CRM CLI to manage leads, contacts, opportunities, activities, pipelines, sequences, and the full Close CRM API.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install globally
|
|
9
|
+
npm install -g close-crm-cli
|
|
10
|
+
|
|
11
|
+
# Authenticate (non-interactive — best for agents)
|
|
12
|
+
export CLOSE_API_KEY="your-api-key-here"
|
|
13
|
+
|
|
14
|
+
# Verify it works
|
|
15
|
+
close users me
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Requirements:** Node.js 18+
|
|
19
|
+
|
|
20
|
+
## Authentication
|
|
21
|
+
|
|
22
|
+
Close CRM uses API key auth (HTTP Basic Auth under the hood). Provide your key via:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# 1. Environment variable (recommended for agents)
|
|
26
|
+
export CLOSE_API_KEY="your-api-key-here"
|
|
27
|
+
|
|
28
|
+
# 2. Per-command flag
|
|
29
|
+
close leads list --api-key "your-api-key-here"
|
|
30
|
+
|
|
31
|
+
# 3. Interactive login (stores in ~/.close/config.json)
|
|
32
|
+
close login
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Get your API key: https://app.close.com/settings/api
|
|
36
|
+
|
|
37
|
+
## Output Format
|
|
38
|
+
|
|
39
|
+
All commands output **JSON to stdout** by default:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Default: compact JSON
|
|
43
|
+
close leads list
|
|
44
|
+
|
|
45
|
+
# Pretty-printed JSON
|
|
46
|
+
close leads list --pretty
|
|
47
|
+
|
|
48
|
+
# Select specific fields
|
|
49
|
+
close leads list --fields id,display_name,status_label
|
|
50
|
+
|
|
51
|
+
# Suppress output (exit code only)
|
|
52
|
+
close leads list --quiet
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Exit codes:** 0 = success, 1 = error. Errors go to stderr as JSON:
|
|
56
|
+
```json
|
|
57
|
+
{"error":"No API key found.","code":"AUTH_ERROR"}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Discovering Commands
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# List all command groups
|
|
64
|
+
close --help
|
|
65
|
+
|
|
66
|
+
# List subcommands in a group
|
|
67
|
+
close leads --help
|
|
68
|
+
|
|
69
|
+
# Get help for a specific subcommand
|
|
70
|
+
close leads create --help
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## All Command Groups & Subcommands
|
|
74
|
+
|
|
75
|
+
### leads
|
|
76
|
+
Manage CRM leads (companies/prospects).
|
|
77
|
+
```
|
|
78
|
+
list List leads (with query support)
|
|
79
|
+
get Get a lead by ID
|
|
80
|
+
create Create a new lead (with optional contacts/opportunities)
|
|
81
|
+
update Update a lead
|
|
82
|
+
delete Delete a lead
|
|
83
|
+
merge Merge two leads (source → destination)
|
|
84
|
+
search Advanced search using Close query DSL
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### contacts
|
|
88
|
+
Manage contacts (people) within leads.
|
|
89
|
+
```
|
|
90
|
+
list List contacts (filter by --lead-id)
|
|
91
|
+
get Get a contact by ID
|
|
92
|
+
create Create a contact on a lead
|
|
93
|
+
update Update a contact
|
|
94
|
+
delete Delete a contact
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### opportunities
|
|
98
|
+
Manage sales opportunities in pipelines.
|
|
99
|
+
```
|
|
100
|
+
list List opportunities (filter by lead, pipeline, status, user)
|
|
101
|
+
get Get an opportunity by ID
|
|
102
|
+
create Create an opportunity on a lead
|
|
103
|
+
update Update an opportunity (move stages, update value, set close date)
|
|
104
|
+
delete Delete an opportunity
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### tasks
|
|
108
|
+
Manage tasks and follow-ups.
|
|
109
|
+
```
|
|
110
|
+
list List tasks (filter by lead, assignee, type, completion)
|
|
111
|
+
get Get a task by ID
|
|
112
|
+
create Create a task on a lead
|
|
113
|
+
update Update a task
|
|
114
|
+
delete Delete a task
|
|
115
|
+
bulk-update Bulk update tasks (e.g. mark multiple complete)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### activities
|
|
119
|
+
Unified activity stream.
|
|
120
|
+
```
|
|
121
|
+
list List all activity types (Call, Email, Note, SMS, Meeting, etc.)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### calls
|
|
125
|
+
Log and manage call activities.
|
|
126
|
+
```
|
|
127
|
+
list List call activities
|
|
128
|
+
get Get a call by ID
|
|
129
|
+
create Log a call
|
|
130
|
+
update Update a call
|
|
131
|
+
delete Delete a call
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### notes
|
|
135
|
+
Manage note activities.
|
|
136
|
+
```
|
|
137
|
+
list List notes
|
|
138
|
+
get Get a note by ID
|
|
139
|
+
create Create a note on a lead
|
|
140
|
+
update Update a note
|
|
141
|
+
delete Delete a note
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### emails
|
|
145
|
+
Manage email activities (send/log emails).
|
|
146
|
+
```
|
|
147
|
+
list List email activities
|
|
148
|
+
get Get an email by ID
|
|
149
|
+
create Send or log an email
|
|
150
|
+
update Update an email
|
|
151
|
+
delete Delete an email
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### sms
|
|
155
|
+
Manage SMS activities.
|
|
156
|
+
```
|
|
157
|
+
list List SMS activities
|
|
158
|
+
get Get an SMS by ID
|
|
159
|
+
create Send or log an SMS
|
|
160
|
+
delete Delete an SMS
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### meetings
|
|
164
|
+
Manage meeting activities.
|
|
165
|
+
```
|
|
166
|
+
list List meetings
|
|
167
|
+
get Get a meeting by ID
|
|
168
|
+
update Update a meeting
|
|
169
|
+
delete Delete a meeting
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### users
|
|
173
|
+
Manage users.
|
|
174
|
+
```
|
|
175
|
+
me Get current authenticated user
|
|
176
|
+
list List all users
|
|
177
|
+
get Get a user by ID
|
|
178
|
+
availability Get dialer availability status for all users
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### pipelines
|
|
182
|
+
Manage sales pipelines.
|
|
183
|
+
```
|
|
184
|
+
list List pipelines
|
|
185
|
+
get Get a pipeline by ID
|
|
186
|
+
create Create a pipeline
|
|
187
|
+
update Update a pipeline
|
|
188
|
+
delete Delete a pipeline
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### lead-statuses
|
|
192
|
+
Manage lead status labels.
|
|
193
|
+
```
|
|
194
|
+
list List lead statuses
|
|
195
|
+
get Get a lead status by ID
|
|
196
|
+
create Create a lead status
|
|
197
|
+
update Update a lead status
|
|
198
|
+
delete Delete a lead status
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### opportunity-statuses
|
|
202
|
+
Manage opportunity status stages.
|
|
203
|
+
```
|
|
204
|
+
list List opportunity statuses
|
|
205
|
+
get Get an opportunity status by ID
|
|
206
|
+
create Create an opportunity status (tied to a pipeline)
|
|
207
|
+
update Update an opportunity status
|
|
208
|
+
delete Delete an opportunity status
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### custom-fields
|
|
212
|
+
Manage custom fields for all object types.
|
|
213
|
+
```
|
|
214
|
+
list-lead List custom fields for leads
|
|
215
|
+
get-lead Get a lead custom field by ID
|
|
216
|
+
create-lead Create a lead custom field
|
|
217
|
+
update-lead Update a lead custom field
|
|
218
|
+
delete-lead Delete a lead custom field
|
|
219
|
+
|
|
220
|
+
list-contact (same pattern for contact)
|
|
221
|
+
get-contact
|
|
222
|
+
create-contact
|
|
223
|
+
update-contact
|
|
224
|
+
delete-contact
|
|
225
|
+
|
|
226
|
+
list-opportunity (same for opportunity)
|
|
227
|
+
get-opportunity
|
|
228
|
+
create-opportunity
|
|
229
|
+
update-opportunity
|
|
230
|
+
delete-opportunity
|
|
231
|
+
|
|
232
|
+
list-activity (same for activity)
|
|
233
|
+
get-activity
|
|
234
|
+
create-activity
|
|
235
|
+
update-activity
|
|
236
|
+
delete-activity
|
|
237
|
+
|
|
238
|
+
list-shared (same for shared fields)
|
|
239
|
+
get-shared
|
|
240
|
+
create-shared
|
|
241
|
+
update-shared
|
|
242
|
+
delete-shared
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### webhooks
|
|
246
|
+
Subscribe to real-time events.
|
|
247
|
+
```
|
|
248
|
+
list List webhook subscriptions
|
|
249
|
+
get Get a webhook by ID
|
|
250
|
+
create Create a webhook (specify events array)
|
|
251
|
+
update Update a webhook
|
|
252
|
+
delete Delete a webhook
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Available webhook events:** `created.lead`, `updated.lead`, `deleted.lead`, `created.contact`, `updated.contact`, `deleted.contact`, `created.opportunity`, `updated.opportunity`, `deleted.opportunity`, `created.note`, `created.call`, `completed.call`, `created.email`, `created.sms`, `created.task`, `completed.task`
|
|
256
|
+
|
|
257
|
+
### sequences
|
|
258
|
+
Manage automated outreach sequences.
|
|
259
|
+
```
|
|
260
|
+
list List sequences
|
|
261
|
+
get Get a sequence by ID
|
|
262
|
+
create Create a sequence
|
|
263
|
+
update Update a sequence
|
|
264
|
+
delete Delete a sequence
|
|
265
|
+
subscribe Subscribe a contact to a sequence
|
|
266
|
+
list-subscriptions List sequence subscriptions
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### email-templates
|
|
270
|
+
Manage reusable email templates.
|
|
271
|
+
```
|
|
272
|
+
list List email templates
|
|
273
|
+
get Get a template by ID
|
|
274
|
+
create Create an email template
|
|
275
|
+
update Update a template
|
|
276
|
+
delete Delete a template
|
|
277
|
+
render Render a template with lead/contact variable substitution
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### sms-templates
|
|
281
|
+
Manage SMS templates.
|
|
282
|
+
```
|
|
283
|
+
list List SMS templates
|
|
284
|
+
get Get a template by ID
|
|
285
|
+
create Create an SMS template
|
|
286
|
+
update Update a template
|
|
287
|
+
delete Delete a template
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### smart-views
|
|
291
|
+
Manage smart views (saved filtered views).
|
|
292
|
+
```
|
|
293
|
+
list List smart views
|
|
294
|
+
get Get a smart view by ID
|
|
295
|
+
create Create a smart view
|
|
296
|
+
update Update a smart view
|
|
297
|
+
delete Delete a smart view
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### reports
|
|
301
|
+
Sales analytics and reporting.
|
|
302
|
+
```
|
|
303
|
+
activity-metrics Get activity metrics for a date range
|
|
304
|
+
activity-report Get detailed activity report (POST)
|
|
305
|
+
funnel Get pipeline funnel totals
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### phone-numbers
|
|
309
|
+
Manage provisioned phone numbers.
|
|
310
|
+
```
|
|
311
|
+
list List phone numbers
|
|
312
|
+
get Get a phone number by ID
|
|
313
|
+
update Update a phone number
|
|
314
|
+
delete Delete a phone number
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### connected-accounts
|
|
318
|
+
Manage connected email accounts.
|
|
319
|
+
```
|
|
320
|
+
list List connected accounts
|
|
321
|
+
get Get a connected account by ID
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### organizations
|
|
325
|
+
Manage the organization (top-level account).
|
|
326
|
+
```
|
|
327
|
+
get Get organization by ID
|
|
328
|
+
update Update organization settings
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### groups
|
|
332
|
+
Manage user groups (teams).
|
|
333
|
+
```
|
|
334
|
+
list List groups
|
|
335
|
+
get Get a group by ID
|
|
336
|
+
create Create a group
|
|
337
|
+
update Update a group
|
|
338
|
+
delete Delete a group
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### roles
|
|
342
|
+
Manage user roles.
|
|
343
|
+
```
|
|
344
|
+
list List roles
|
|
345
|
+
get Get a role by ID
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### exports
|
|
349
|
+
Async data exports.
|
|
350
|
+
```
|
|
351
|
+
list List exports
|
|
352
|
+
get Get export status and download URL
|
|
353
|
+
create-lead Start a lead export
|
|
354
|
+
create-opportunity Start an opportunity export
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### unsubscribe
|
|
358
|
+
Manage email unsubscribe list.
|
|
359
|
+
```
|
|
360
|
+
list List unsubscribed emails
|
|
361
|
+
add Add an email to the unsubscribe list
|
|
362
|
+
delete Remove an email from the unsubscribe list
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Common Workflows for Agents
|
|
368
|
+
|
|
369
|
+
### Create and qualify a lead
|
|
370
|
+
```bash
|
|
371
|
+
# 1. Create the lead
|
|
372
|
+
close leads create --name "Acme Corp" --url "https://acme.com"
|
|
373
|
+
# → {"id":"lead_abc123","display_name":"Acme Corp",...}
|
|
374
|
+
|
|
375
|
+
# 2. Add a contact
|
|
376
|
+
close contacts create --lead-id lead_abc123 --name "Jane Doe" \
|
|
377
|
+
--emails '[{"email":"jane@acme.com","type":"office"}]' \
|
|
378
|
+
--phones '[{"phone":"+14155551234","type":"mobile"}]'
|
|
379
|
+
|
|
380
|
+
# 3. Create an opportunity
|
|
381
|
+
close opportunities create --lead-id lead_abc123 \
|
|
382
|
+
--note "Enterprise deal" --value 50000 --value-period one_time \
|
|
383
|
+
--confidence 40 --close-date "2025-06-30"
|
|
384
|
+
|
|
385
|
+
# 4. Add a note
|
|
386
|
+
close notes create --lead-id lead_abc123 --note "Intro call went well, demo scheduled"
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Log a call and create follow-up task
|
|
390
|
+
```bash
|
|
391
|
+
# Log the call
|
|
392
|
+
close calls create --lead-id lead_abc123 --direction outbound \
|
|
393
|
+
--duration 1800 --note "Discussed pricing and timeline"
|
|
394
|
+
|
|
395
|
+
# Create follow-up task
|
|
396
|
+
close tasks create --lead-id lead_abc123 \
|
|
397
|
+
--text "Send proposal" --type email \
|
|
398
|
+
--due-date "2025-04-07T09:00:00"
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Move a deal through the pipeline
|
|
402
|
+
```bash
|
|
403
|
+
# Check current pipeline stages
|
|
404
|
+
close opportunity-statuses list
|
|
405
|
+
|
|
406
|
+
# Move opportunity to next stage
|
|
407
|
+
close opportunities update oppo_abc123 --status-id "stat_demo_scheduled"
|
|
408
|
+
|
|
409
|
+
# Won it!
|
|
410
|
+
close opportunities update oppo_abc123 --status-id "stat_won" --confidence 100
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Set up a webhook for real-time events
|
|
414
|
+
```bash
|
|
415
|
+
# Create webhook
|
|
416
|
+
close webhooks create \
|
|
417
|
+
--url "https://your-endpoint.com/close-hook" \
|
|
418
|
+
--events '["created.lead","updated.opportunity","created.call"]'
|
|
419
|
+
|
|
420
|
+
# List active webhooks
|
|
421
|
+
close webhooks list
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Enroll a contact in a sequence
|
|
425
|
+
```bash
|
|
426
|
+
# List available sequences
|
|
427
|
+
close sequences list
|
|
428
|
+
|
|
429
|
+
# Subscribe the contact
|
|
430
|
+
close sequences subscribe \
|
|
431
|
+
--sequence-id seq_abc123 \
|
|
432
|
+
--contact-id cont_abc123
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Advanced lead search
|
|
436
|
+
```bash
|
|
437
|
+
# Find all leads with status "Potential"
|
|
438
|
+
close leads list --query "status:Potential" --limit 100
|
|
439
|
+
|
|
440
|
+
# Advanced search with full query DSL
|
|
441
|
+
close leads search --query '{
|
|
442
|
+
"type": "and",
|
|
443
|
+
"queries": [
|
|
444
|
+
{
|
|
445
|
+
"type": "field",
|
|
446
|
+
"field": {"type": "regular", "field_name": "status_label"},
|
|
447
|
+
"negate": false,
|
|
448
|
+
"condition": {"type": "text", "mode": "equals", "value": "Potential"}
|
|
449
|
+
}
|
|
450
|
+
]
|
|
451
|
+
}'
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Export leads to CSV
|
|
455
|
+
```bash
|
|
456
|
+
# Start the export
|
|
457
|
+
close exports create-lead --format csv
|
|
458
|
+
# → {"id":"export_abc123","status":"pending",...}
|
|
459
|
+
|
|
460
|
+
# Poll until ready
|
|
461
|
+
close exports get export_abc123
|
|
462
|
+
# → {"id":"export_abc123","status":"completed","download_url":"https://..."}
|
|
463
|
+
|
|
464
|
+
# Download
|
|
465
|
+
curl -o leads.csv "https://..."
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Check pipeline health
|
|
469
|
+
```bash
|
|
470
|
+
# Get funnel report
|
|
471
|
+
close reports funnel --pipeline-id pipe_abc123 --date-range this_month
|
|
472
|
+
|
|
473
|
+
# Get activity metrics for the team
|
|
474
|
+
close reports activity-metrics --date-range this_week
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Pagination
|
|
480
|
+
|
|
481
|
+
List commands support offset-based pagination:
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
# First page (25 items)
|
|
485
|
+
close leads list --limit 25
|
|
486
|
+
|
|
487
|
+
# Next page
|
|
488
|
+
close leads list --limit 25 --skip 25
|
|
489
|
+
|
|
490
|
+
# Third page
|
|
491
|
+
close leads list --limit 25 --skip 50
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Custom Fields
|
|
497
|
+
|
|
498
|
+
Close CRM supports per-object custom fields. Set them using the `--custom` option with a JSON object where keys are custom field IDs:
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
# Set custom fields on create
|
|
502
|
+
close leads create --name "Acme Corp" --custom '{"cf_budget":"500000","cf_industry":"SaaS"}'
|
|
503
|
+
|
|
504
|
+
# Update custom fields
|
|
505
|
+
close leads update lead_abc123 --custom '{"cf_budget":"750000"}'
|
|
506
|
+
|
|
507
|
+
# List available custom fields to find their IDs
|
|
508
|
+
close custom-fields list-lead
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## MCP Server (for Claude, Cursor, VS Code)
|
|
514
|
+
|
|
515
|
+
The CLI includes a built-in MCP server exposing all commands as tools:
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
close mcp
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
MCP config for Claude Desktop / Cursor:
|
|
522
|
+
```json
|
|
523
|
+
{
|
|
524
|
+
"mcpServers": {
|
|
525
|
+
"close": {
|
|
526
|
+
"command": "npx",
|
|
527
|
+
"args": ["close-crm-cli", "mcp"],
|
|
528
|
+
"env": {
|
|
529
|
+
"CLOSE_API_KEY": "your-api-key"
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
Or if installed globally:
|
|
537
|
+
```json
|
|
538
|
+
{
|
|
539
|
+
"mcpServers": {
|
|
540
|
+
"close": {
|
|
541
|
+
"command": "close",
|
|
542
|
+
"args": ["mcp"],
|
|
543
|
+
"env": {
|
|
544
|
+
"CLOSE_API_KEY": "your-api-key"
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
|
|
553
|
+
## Tips for AI Agents
|
|
554
|
+
|
|
555
|
+
1. **Always use `--help`** on a group before guessing subcommand names
|
|
556
|
+
2. **Parse JSON output** directly — it's machine-readable by default
|
|
557
|
+
3. **Check exit codes** — 0 means success, 1 means error
|
|
558
|
+
4. **Use `--fields`** to reduce output size (e.g. `--fields id,display_name`)
|
|
559
|
+
5. **Use `--quiet`** when you only care about success/failure
|
|
560
|
+
6. **Use `--pretty`** for human-readable JSON
|
|
561
|
+
7. **Lead IDs** look like `lead_abc123`, contact IDs like `cont_abc123`, etc.
|
|
562
|
+
8. **Custom field values** are set using `--custom '{"cf_fieldid":"value"}'`
|
|
563
|
+
9. **Rate limits** are handled automatically with exponential backoff
|
|
564
|
+
10. **All activity commands** share the same endpoint patterns: `/activity/call/`, `/activity/note/`, `/activity/email/`, `/activity/sms/`, `/activity/meeting/`
|
|
565
|
+
11. **Sequence subscriptions** connect a contact to a sequence; check status with `sequences list-subscriptions --contact-id <id>`
|
|
566
|
+
12. **Exports are async** — poll `exports get <id>` until `status === "completed"`, then download from `download_url`
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# CLAUDE.md — Developer Guide for close-crm-cli
|
|
2
|
+
|
|
3
|
+
## Architecture Overview
|
|
4
|
+
|
|
5
|
+
This project follows the **CommandDefinition** pattern used across all bcharleson CLI tools:
|
|
6
|
+
|
|
7
|
+
- **One `CommandDefinition` object** = one CLI subcommand + one MCP tool
|
|
8
|
+
- All commands live in `src/commands/` grouped by resource
|
|
9
|
+
- `src/commands/index.ts` is the single registry — add commands here
|
|
10
|
+
- The MCP server (`src/mcp/server.ts`) auto-registers all commands from `allCommands[]`
|
|
11
|
+
- CLI registration (`registerAllCommands()`) also loops over `allCommands[]`
|
|
12
|
+
|
|
13
|
+
## Adding a New Command
|
|
14
|
+
|
|
15
|
+
1. Create `src/commands/{group}/{subcommand}.ts`
|
|
16
|
+
2. Export a `CommandDefinition` object
|
|
17
|
+
3. Import and add it to `allCommands[]` in `src/commands/index.ts`
|
|
18
|
+
|
|
19
|
+
That's it — the command automatically appears in both the CLI and the MCP server.
|
|
20
|
+
|
|
21
|
+
### Command Template
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { z } from 'zod';
|
|
25
|
+
import type { CommandDefinition } from '../../core/types.js';
|
|
26
|
+
import { executeCommand } from '../../core/handler.js';
|
|
27
|
+
|
|
28
|
+
export const resourceActionCommand: CommandDefinition = {
|
|
29
|
+
name: 'resource_action', // snake_case, unique MCP tool name
|
|
30
|
+
group: 'resource', // CLI group name (kebab-case)
|
|
31
|
+
subcommand: 'action', // CLI subcommand name
|
|
32
|
+
description: 'What this does.', // Used in --help and MCP
|
|
33
|
+
|
|
34
|
+
inputSchema: z.object({
|
|
35
|
+
id: z.string().describe('Resource ID'),
|
|
36
|
+
name: z.string().optional().describe('Name'),
|
|
37
|
+
}),
|
|
38
|
+
|
|
39
|
+
cliMappings: {
|
|
40
|
+
args: [{ field: 'id', name: 'id', required: true }], // positional args
|
|
41
|
+
options: [
|
|
42
|
+
{ field: 'name', flags: '--name <name>', description: 'Name' },
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
endpoint: { method: 'PUT', path: '/resource/{id}/' },
|
|
47
|
+
|
|
48
|
+
fieldMappings: {
|
|
49
|
+
id: 'path', // goes in URL path
|
|
50
|
+
name: 'body', // goes in request body
|
|
51
|
+
// 'query' → goes in query string
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
handler: (input, client) => executeCommand(resourceActionCommand, input, client),
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For handlers with complex logic (like applying defaults), use an async function directly:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
handler: async (input, client) => {
|
|
62
|
+
const body: Record<string, any> = { required_field: input.required_field };
|
|
63
|
+
if (input.optional) body.optional = input.optional;
|
|
64
|
+
return client.post('/resource/', body);
|
|
65
|
+
},
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Close CRM API Specifics
|
|
69
|
+
|
|
70
|
+
- **Base URL:** `https://api.close.com/api/v1`
|
|
71
|
+
- **Auth:** HTTP Basic Auth — `Authorization: Basic base64("apikey:")` (implemented in `CloseClient`)
|
|
72
|
+
- **HTTP methods:** GET, POST, PUT, DELETE (no PATCH)
|
|
73
|
+
- **Pagination:** `_limit` + `_skip` params, response has `data[]` + `has_more`
|
|
74
|
+
- **Rate limits:** 429 → read `rate_reset` header (Unix timestamp), sleep until reset
|
|
75
|
+
- **Custom fields:** Set as `custom.{FIELD_ID}` in request body
|
|
76
|
+
|
|
77
|
+
## Project Structure
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
src/
|
|
81
|
+
index.ts CLI entry point (Commander.js)
|
|
82
|
+
mcp.ts MCP server entry point
|
|
83
|
+
core/
|
|
84
|
+
types.ts CommandDefinition, CloseClient, GlobalOptions interfaces
|
|
85
|
+
client.ts HTTP client (Basic Auth, retry, rate limiting)
|
|
86
|
+
config.ts ~/.close/config.json management
|
|
87
|
+
auth.ts API key resolution (flag > env > config)
|
|
88
|
+
errors.ts Typed error classes
|
|
89
|
+
output.ts JSON output formatting
|
|
90
|
+
handler.ts executeCommand() — builds HTTP requests from CommandDefinitions
|
|
91
|
+
mcp/
|
|
92
|
+
server.ts MCP server (loops allCommands[], registers as MCP tools)
|
|
93
|
+
commands/
|
|
94
|
+
index.ts allCommands[] registry + registerAllCommands()
|
|
95
|
+
auth/ login, logout (special — no API client)
|
|
96
|
+
mcp/ mcp command registration
|
|
97
|
+
leads/ list, get, create, update, delete, merge, search
|
|
98
|
+
contacts/ list, get, create, update, delete
|
|
99
|
+
opportunities/ list, get, create, update, delete
|
|
100
|
+
tasks/ list, get, create, update, delete, bulk-update
|
|
101
|
+
activities/ list (unified stream)
|
|
102
|
+
calls/ list, get, create, update, delete
|
|
103
|
+
notes/ list, get, create, update, delete
|
|
104
|
+
emails/ list, get, create, update, delete
|
|
105
|
+
sms/ list, get, create, delete
|
|
106
|
+
meetings/ list, get, update, delete
|
|
107
|
+
users/ me, list, get, availability
|
|
108
|
+
pipelines/ list, get, create, update, delete
|
|
109
|
+
lead-statuses/ list, get, create, update, delete
|
|
110
|
+
opportunity-statuses/ list, get, create, update, delete
|
|
111
|
+
custom-fields/ index.ts (factory-generated, 25 commands)
|
|
112
|
+
webhooks/ list, get, create, update, delete
|
|
113
|
+
sequences/ list, get, create, update, delete, subscribe, list-subscriptions
|
|
114
|
+
email-templates/ list, get, create, update, delete, render
|
|
115
|
+
sms-templates/ list, get, create, update, delete
|
|
116
|
+
smart-views/ list, get, create, update, delete
|
|
117
|
+
reports/ activity-metrics, activity-report, funnel
|
|
118
|
+
phone-numbers/ list, get, update, delete
|
|
119
|
+
connected-accounts/ list, get
|
|
120
|
+
organizations/ get, update
|
|
121
|
+
groups/ list, get, create, update, delete
|
|
122
|
+
roles/ list, get
|
|
123
|
+
exports/ list, get, create-lead, create-opportunity
|
|
124
|
+
unsubscribe/ list, add, delete
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Build & Dev
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npm install
|
|
131
|
+
npm run dev -- leads list # Run CLI in dev mode
|
|
132
|
+
npm run dev:mcp # Run MCP server in dev mode
|
|
133
|
+
npm run build # Build to dist/
|
|
134
|
+
npm run typecheck # TypeScript type check
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Zod Version Note
|
|
138
|
+
|
|
139
|
+
This project uses Zod v3 (`"zod": "^3.24.0"`). The `inputSchema.shape` property is used in the MCP server to extract the Zod shape for tool registration. Do not upgrade to Zod v4 without testing the MCP server registration.
|
|
140
|
+
|
|
141
|
+
## Conventions
|
|
142
|
+
|
|
143
|
+
- Use `z.preprocess()` for JSON array/object fields (handles both string-encoded and parsed values)
|
|
144
|
+
- Use `z.coerce.number()` for numeric CLI options (Commander.js passes everything as strings)
|
|
145
|
+
- Boolean CLI flags: use `z.preprocess()` with `v === 'true'` → `true` pattern
|
|
146
|
+
- All `handler` functions must return `Promise<unknown>`
|
|
147
|
+
- Use `encodeURIComponent()` for path parameters in custom handlers
|
|
148
|
+
- Keep command descriptions concise but complete — they appear in MCP tool descriptions seen by AI models
|