@revfleet/hscli 0.8.6 → 0.8.10
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/CHANGELOG.md +240 -0
- package/CONTRIBUTING.md +120 -0
- package/README.md +14 -6
- package/brand/readme-hero.svg +25 -0
- package/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/account/index.js +5 -6
- package/dist/commands/account/index.js.map +1 -1
- package/dist/commands/api/index.js +43 -3
- package/dist/commands/api/index.js.map +1 -1
- package/dist/commands/auth/index.js +32 -6
- package/dist/commands/auth/index.js.map +1 -1
- package/dist/commands/cms/hubdb.js +64 -1
- package/dist/commands/cms/hubdb.js.map +1 -1
- package/dist/commands/cms/index.js +27 -0
- package/dist/commands/cms/index.js.map +1 -1
- package/dist/commands/cms/source-code.js +21 -0
- package/dist/commands/cms/source-code.js.map +1 -1
- package/dist/commands/communication-preferences/index.js +11 -12
- package/dist/commands/communication-preferences/index.js.map +1 -1
- package/dist/commands/crm/shared.d.ts +1 -0
- package/dist/commands/crm/shared.js +3 -4
- package/dist/commands/crm/shared.js.map +1 -1
- package/dist/commands/events/index.js +7 -8
- package/dist/commands/events/index.js.map +1 -1
- package/dist/commands/marketing/index.js +58 -3
- package/dist/commands/marketing/index.js.map +1 -1
- package/dist/commands/settings/index.js +12 -13
- package/dist/commands/settings/index.js.map +1 -1
- package/dist/commands/workflows/index.js +43 -0
- package/dist/commands/workflows/index.js.map +1 -1
- package/dist/core/http.d.ts +27 -0
- package/dist/core/http.js +102 -18
- package/dist/core/http.js.map +1 -1
- package/dist/core/plugins.d.ts +5 -2
- package/dist/core/plugins.js +18 -1
- package/dist/core/plugins.js.map +1 -1
- package/dist/core/telemetry-context.d.ts +13 -0
- package/dist/core/telemetry-context.js +30 -0
- package/dist/core/telemetry-context.js.map +1 -0
- package/dist/mcp/hubspot-modules.d.ts +30 -0
- package/dist/mcp/hubspot-modules.js +305 -0
- package/dist/mcp/hubspot-modules.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.js +30 -26
- package/dist/mcp/server.js.map +1 -1
- package/docs/ARCHITECTURE.md +39 -0
- package/docs/CAPABILITY_LIBRARY.md +638 -0
- package/docs/CMS_SETUP.md +349 -0
- package/docs/COMMAND_COMPATIBILITY.md +24 -0
- package/docs/COMMAND_TREE.md +183 -0
- package/docs/COMMERCE_SETUP.md +400 -0
- package/docs/COMPARISON.md +146 -0
- package/docs/COOKBOOK.md +800 -0
- package/docs/INTEGRATIONS_NOTIFICATIONS_SETUP.md +352 -0
- package/docs/MARKETING_SETUP.md +503 -0
- package/docs/MCP.md +171 -0
- package/docs/OPERATIONAL_PLAYBOOKS.md +322 -0
- package/docs/OPERATIONS_SETUP.md +362 -0
- package/docs/PLUGIN_GUIDE.md +158 -0
- package/docs/POLICY_EXAMPLE.json +57 -0
- package/docs/PORTAL_SETUP.md +683 -0
- package/docs/PUBLISHING.md +154 -0
- package/docs/RELEASE_GOVERNANCE.md +34 -0
- package/docs/REPORTING_SETUP.md +310 -0
- package/docs/ROADMAP-DATE-BASED-API.md +103 -0
- package/docs/ROADMAP_PHASE1_TO_3.md +96 -0
- package/docs/SAFETY_MODEL.md +37 -0
- package/docs/SALES_SETUP.md +369 -0
- package/docs/SERVICE_SETUP.md +403 -0
- package/docs/TESTING_PLAN.md +89 -0
- package/docs/TIERS.md +320 -0
- package/docs/TUTORIALS/audit-portal-writes.md +150 -0
- package/docs/TUTORIALS/secure-agent-writes.md +177 -0
- package/docs/TUTORIALS/trace-replay-repro.md +147 -0
- package/docs/WHY_HOW_WHAT.md +81 -0
- package/package.json +7 -2
package/docs/TIERS.md
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# HubSpot Plan Tier Requirements
|
|
2
|
+
|
|
3
|
+
Every HubSpot public API endpoint is gated by a specific HubSpot plan tier. hscli
|
|
4
|
+
exposes **100% of the 1180 public endpoints** as CLI commands, but whether a
|
|
5
|
+
given command actually returns data depends on whether the portal has the
|
|
6
|
+
required tier activated.
|
|
7
|
+
|
|
8
|
+
This document maps hscli modules to the HubSpot product hubs and tiers that
|
|
9
|
+
unlock them, based on [HubSpot's official pricing page](https://www.hubspot.com/pricing)
|
|
10
|
+
and the [developer documentation](https://developers.hubspot.com/docs/api/overview)
|
|
11
|
+
as of April 2026. Tiers are cumulative — e.g. "Marketing Hub Professional+" means
|
|
12
|
+
Professional and Enterprise both unlock the endpoint.
|
|
13
|
+
|
|
14
|
+
If an endpoint returns **403 Forbidden** with a message like *"This endpoint is
|
|
15
|
+
not available on your account"* or *"This feature is part of HubSpot's [X] Hub"*,
|
|
16
|
+
it's tier-locked. Upgrade the portal to the required tier or test on a portal
|
|
17
|
+
that has it.
|
|
18
|
+
|
|
19
|
+
## Quick tier map
|
|
20
|
+
|
|
21
|
+
| Tier | Reachable endpoints (approx) |
|
|
22
|
+
|---|---:|
|
|
23
|
+
| **Free** (any account) | ~550 |
|
|
24
|
+
| **Starter** (any hub, $20-50/mo) | +~80 |
|
|
25
|
+
| **Professional** (any hub, $800-900/mo) | +~250 |
|
|
26
|
+
| **Enterprise** (any hub, $3200+/mo) | +~100 |
|
|
27
|
+
| **Commerce Hub** add-on | +~60 |
|
|
28
|
+
| **Operations Hub Pro+** | +~40 |
|
|
29
|
+
| **Developer Test Account** (free) | +~30 |
|
|
30
|
+
| **Developer App + legacy hapikey** | +~40 (zombie — see below) |
|
|
31
|
+
|
|
32
|
+
Cumulative ceiling with Marketing+Sales+Service+CMS+Ops+Commerce **all at
|
|
33
|
+
Enterprise plus a dev app**: ~1140 / 1180 reachable (96.6%). Of the remaining
|
|
34
|
+
~40, most are [zombie endpoints](#zombie-endpoints) HubSpot never migrated off
|
|
35
|
+
legacy auth.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Free (no paid plan required)
|
|
40
|
+
|
|
41
|
+
These endpoints work on any HubSpot portal, including free personal accounts
|
|
42
|
+
and Developer Test Accounts.
|
|
43
|
+
|
|
44
|
+
### CRM objects (standard)
|
|
45
|
+
- `hscli crm contacts ...` — `/crm/v3/objects/contacts` (all CRUD + search + batch)
|
|
46
|
+
- `hscli crm companies ...` — `/crm/v3/objects/companies`
|
|
47
|
+
- `hscli crm deals ...` — `/crm/v3/objects/deals`
|
|
48
|
+
- `hscli crm tickets ...` — `/crm/v3/objects/tickets`
|
|
49
|
+
- `hscli crm engagements` — notes, tasks, calls, meetings, emails
|
|
50
|
+
- `hscli crm feedback-submissions`
|
|
51
|
+
- `hscli crm communications` — SMS / WhatsApp logs
|
|
52
|
+
|
|
53
|
+
### CRM infrastructure
|
|
54
|
+
- `hscli crm properties ...` — `/crm/v3/properties/{objectType}` + groups
|
|
55
|
+
- `hscli crm pipelines ...` — `/crm/v3/pipelines/{deals|tickets}`
|
|
56
|
+
- `hscli crm owners ...` — `/crm/v3/owners`
|
|
57
|
+
- `hscli crm associations ...` — `/crm/v3/associations` + `/crm/v4/associations`
|
|
58
|
+
- `hscli crm schemas ...` (custom objects) — `/crm/v3/schemas`
|
|
59
|
+
- `hscli crm imports ...` — `/crm/v3/imports`
|
|
60
|
+
- `hscli crm exports ...` — `/crm/v3/exports`
|
|
61
|
+
- `hscli lists ...` + `lists folders` — `/crm/v3/lists`
|
|
62
|
+
|
|
63
|
+
### Settings (admin)
|
|
64
|
+
- `hscli settings users,teams,currencies` — `/settings/v3/users`, `/settings/v3/users/teams`, `/settings/v3/currencies`
|
|
65
|
+
- `hscli settings audit-logs` — `/settings/v3/audit-logs` (read-only)
|
|
66
|
+
- `hscli account info,api-usage,private-apps,audit-logs` — `/account-info/v3`
|
|
67
|
+
|
|
68
|
+
### Files + Forms
|
|
69
|
+
- `hscli files ...` + `files folders` — `/files/v3/files`, `/files/v3/folders`
|
|
70
|
+
- `hscli forms ...` — `/marketing/v3/forms` (basic CRUD)
|
|
71
|
+
- `hscli submissions ...` — `/form-integrations/v1`, `/submissions/v3`
|
|
72
|
+
|
|
73
|
+
### Webhooks
|
|
74
|
+
- `hscli webhooks ...` — `/webhooks/v3/subscriptions` (portal-side)
|
|
75
|
+
|
|
76
|
+
### OAuth + Auth
|
|
77
|
+
- `hscli auth ...` — `/oauth/v1`, `/oauth/v3`
|
|
78
|
+
|
|
79
|
+
### Communication Preferences
|
|
80
|
+
- `hscli communication-preferences ...` — `/communication-preferences/v3` + v4 batch
|
|
81
|
+
|
|
82
|
+
### Events
|
|
83
|
+
- `hscli events ...` — `/events/v3` (behavioral events + event definitions)
|
|
84
|
+
- `hscli timeline ...` — `/crm/v3/timeline/events` (emit events, not templates)
|
|
85
|
+
|
|
86
|
+
### Conversations (read)
|
|
87
|
+
- `hscli conversations threads,messages,actors` — `/conversations/v3/conversations`
|
|
88
|
+
|
|
89
|
+
### Legacy CRM v1/v2
|
|
90
|
+
All work on Free portals (backward-compatibility preserved by HubSpot):
|
|
91
|
+
- `hscli contacts-v1` — `/contacts/v1`
|
|
92
|
+
- `hscli companies-v2` — `/companies/v2`
|
|
93
|
+
- `hscli deals-v1` — `/deals/v1`
|
|
94
|
+
- `hscli owners-v2` — `/owners/v2`
|
|
95
|
+
- `hscli engagements-v1` — `/engagements/v1`
|
|
96
|
+
- `hscli properties-legacy` — `/properties/v1`, `/properties/v2`
|
|
97
|
+
|
|
98
|
+
### Analytics (basic)
|
|
99
|
+
- `hscli reporting` — `/analytics/v2/reports` (read, limited by tier)
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Marketing Hub (Starter+)
|
|
104
|
+
|
|
105
|
+
Upgrade: $20/mo and up. Unlocks email marketing + form follow-ups.
|
|
106
|
+
|
|
107
|
+
### Starter
|
|
108
|
+
- `hscli marketing emails list,get` — read `/marketing/v3/emails` (limited send volume)
|
|
109
|
+
- `hscli marketing subscriptions` — subscription types
|
|
110
|
+
- `hscli marketing-emails-v1 list,get` — read legacy emails
|
|
111
|
+
- `hscli ctas read` — CTA reporting (legacy)
|
|
112
|
+
|
|
113
|
+
### Professional+ (adds)
|
|
114
|
+
- `hscli marketing emails create,update,stats` — full editorial CRUD + analytics
|
|
115
|
+
- `hscli marketing campaigns` — `/marketing/v3/campaigns`
|
|
116
|
+
- `hscli marketing ads` — `/marketing/v3/ads/{accounts,campaigns}`
|
|
117
|
+
- `hscli marketing social` — `/marketing/v3/social/{accounts,posts}`
|
|
118
|
+
- `hscli marketing seo` — `/marketing/v3/seo` + `/cms/v3/seo/audit`
|
|
119
|
+
- `hscli marketing events` + `attendance` + `participations` — `/marketing/v3/marketing-events`
|
|
120
|
+
- `hscli marketing behavioral-events` — custom behavioral event definitions
|
|
121
|
+
- `hscli marketing transactional single-email-send,smtp-tokens` — `/marketing/v3/transactional`
|
|
122
|
+
- `hscli broadcast ...`, `broadcasts-root` — legacy social broadcast
|
|
123
|
+
- `hscli email-events list,get,campaigns` — `/email/public/v1/events` (legacy per-recipient stream)
|
|
124
|
+
- `hscli marketing-extras ads-events,legacy-email-ab-test`
|
|
125
|
+
- `hscli marketing-emails-v1 create,update,clone,publish,statistics` — full legacy CRUD
|
|
126
|
+
|
|
127
|
+
### Enterprise (adds)
|
|
128
|
+
- `hscli settings business-units ...`, `hscli business-units` — `/settings/v3/business-units`, `/business-units/v3`
|
|
129
|
+
- `marketing.campaigns.revenue.read` scope — revenue attribution endpoints
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Sales Hub (Starter+)
|
|
134
|
+
|
|
135
|
+
Upgrade: $20/mo and up. Unlocks meeting scheduler + basic deal tools.
|
|
136
|
+
|
|
137
|
+
### Starter
|
|
138
|
+
- `hscli scheduler links-list,link-get` — `/scheduler/v3/meetings/meeting-links` (basic)
|
|
139
|
+
- `hscli sales meetings ...` — `/crm/v3/objects/meetings` (create/link)
|
|
140
|
+
|
|
141
|
+
### Professional+ (adds)
|
|
142
|
+
- `hscli sales sequences list,get,enrollments,enroll,unenroll` — `/automation/v4/sequences`
|
|
143
|
+
- `hscli scheduler book,reschedule,cancel` — advanced scheduler ops
|
|
144
|
+
- `hscli sales calling` — `/crm/v3/extensions/calling/*` (calling SDK, partly zombie — see below)
|
|
145
|
+
- `hscli crm goals` — `/crm/v3/objects/goal_targets` (basic custom goals in Starter, full forecasting Pro)
|
|
146
|
+
- `hscli crm dated associations-2025-09 usage-report` — high-usage associations report
|
|
147
|
+
|
|
148
|
+
### Enterprise (adds)
|
|
149
|
+
- `crm.schemas.forecasts.read`, `crm.objects.forecasts.read` — forecast data
|
|
150
|
+
- `crm.extensions_calling_transcripts.read,write` — call transcripts
|
|
151
|
+
- `crm.dealsplits.read_write` — deal splits
|
|
152
|
+
- `sales-email-read` — email templates API
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Service Hub (Starter+)
|
|
157
|
+
|
|
158
|
+
Upgrade: $20/mo and up. Unlocks ticket automation + chatflows.
|
|
159
|
+
|
|
160
|
+
### Starter
|
|
161
|
+
- `hscli service chatflows ...` — `/conversations/v3/chatflows`
|
|
162
|
+
- `hscli service feedback` — `/crm/v3/objects/feedback_submissions`
|
|
163
|
+
- `hscli conversations inboxes,channels,channel-accounts` — `/conversations/v3/conversations/*`
|
|
164
|
+
- `hscli conversations custom-channels` — app-dev custom channels
|
|
165
|
+
|
|
166
|
+
### Professional+ (adds)
|
|
167
|
+
- `hscli service knowledge-base ...` — `/cms/v3/knowledge_base` (articles, settings)
|
|
168
|
+
- `hscli service pipelines` — `/crm/v3/pipelines/tickets` with > 1 pipeline
|
|
169
|
+
- `hscli conversations messages send` — send messages into threads
|
|
170
|
+
|
|
171
|
+
### Enterprise (adds)
|
|
172
|
+
- Custom survey types + advanced routing (endpoints read-only on Pro)
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## CMS Hub (Starter+)
|
|
177
|
+
|
|
178
|
+
Upgrade: $23/mo (CMS Hub Starter). Unlocks HubSpot-hosted website.
|
|
179
|
+
|
|
180
|
+
### Starter
|
|
181
|
+
- `hscli cms site-pages,pages,landing-pages` — basic CRUD
|
|
182
|
+
- `hscli cms url-redirects` — URL redirects
|
|
183
|
+
- `hscli cms topics` — blog topics
|
|
184
|
+
- `hscli cms audit-logs` — content audit log
|
|
185
|
+
- `hscli cms blog-posts,blogs,blog-authors,blog-tags,blog-settings` — full blog CRUD (Starter onwards)
|
|
186
|
+
- `hscli cms landing-page-folders` — landing page organization
|
|
187
|
+
|
|
188
|
+
### Professional+ (adds)
|
|
189
|
+
- `hscli cms hubdb ...` — `/cms/v3/hubdb/tables` (HubDB)
|
|
190
|
+
- `hscli cms seo-audit` — SEO audit API
|
|
191
|
+
- `hscli cms domains` — multi-domain listing
|
|
192
|
+
- `hscli cms source-code ...` — theme/module source code API
|
|
193
|
+
- `hscli cms content-v2 ...` — legacy Content API v2 (Pages, Layouts, Templates, Modules)
|
|
194
|
+
- `hscli cms pages ab-test,revisions,multi-language` — A/B testing + multi-language
|
|
195
|
+
- `hscli comments` — `/comments/v3/comments`
|
|
196
|
+
|
|
197
|
+
### Enterprise (adds)
|
|
198
|
+
- `cms.membership.access_groups.read,write` — CMS membership access groups
|
|
199
|
+
- Multi-brand (via Business Units)
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Operations Hub (Starter+)
|
|
204
|
+
|
|
205
|
+
Upgrade: $20/mo and up. Unlocks data sync + custom code.
|
|
206
|
+
|
|
207
|
+
### Starter
|
|
208
|
+
- `hscli crm imports,exports` — enhanced batch import/export
|
|
209
|
+
- `hscli integration-sync` (integrations) — basic 2-way sync
|
|
210
|
+
|
|
211
|
+
### Professional+ (adds)
|
|
212
|
+
- `hscli automation workflows` — `/automation/v4/flows` (Workflows)
|
|
213
|
+
- `hscli automation actions ...` — `/automation/v4/actions/{appId}` (custom code actions, requires OAuth dev app)
|
|
214
|
+
- `hscli crm dated *` — dated 2025-09 API with batch
|
|
215
|
+
- `hscli marketing behavioral-events` — custom event definitions (send on Ops Pro+)
|
|
216
|
+
|
|
217
|
+
### Enterprise (adds)
|
|
218
|
+
- Advanced data quality automation + team-based custom-code permissions
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Commerce Hub (Commerce add-on)
|
|
223
|
+
|
|
224
|
+
Commerce Hub is a separate add-on (not a tier). Free Commerce gives limited
|
|
225
|
+
Stripe checkout + quotes; paid unlocks the full suite.
|
|
226
|
+
|
|
227
|
+
### Commerce Hub (Free with Commerce account)
|
|
228
|
+
- `hscli crm quotes ...` — `/crm/v3/objects/quotes` (basic, requires `hs_language`)
|
|
229
|
+
- `hscli crm products ...` — `/crm/v3/objects/products`
|
|
230
|
+
- `hscli crm line-items ...` — `/crm/v3/objects/line_items`
|
|
231
|
+
|
|
232
|
+
### Commerce Hub Professional+
|
|
233
|
+
- `hscli crm invoices ...` — `/crm/v3/objects/invoices`
|
|
234
|
+
- `hscli crm subscriptions ...` — `/crm/v3/objects/subscriptions`
|
|
235
|
+
- `hscli crm payments ...` — `/crm/v3/objects/payments`
|
|
236
|
+
- `hscli crm orders,carts,discounts,fees,taxes` — commerce objects
|
|
237
|
+
- `hscli payments-subscriptions get,cancel,pause` — `/payments/subscriptions/v1`
|
|
238
|
+
- `hscli tax list,get,create,update,delete` — `/tax/v3/taxes` (tax rates)
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Developer Platform (HubSpot Developer Account, free)
|
|
243
|
+
|
|
244
|
+
These endpoints require a [HubSpot Developer Account](https://developers.hubspot.com/)
|
|
245
|
+
(free, separate from a customer portal). You build an "App" in the developer
|
|
246
|
+
account, install it via OAuth onto a test portal, and use the OAuth
|
|
247
|
+
access_token. hscli supports this via `hscli auth oauth-url` +
|
|
248
|
+
`hscli auth oauth-exchange --profile <devapp>`.
|
|
249
|
+
|
|
250
|
+
### Accessible via OAuth Developer App
|
|
251
|
+
- `hscli webhooks` — `/webhooks/v3/{appId}/subscriptions` (app developer's webhook subscriptions)
|
|
252
|
+
- `hscli automation actions` — `/automation/v4/actions/{appId}` (custom workflow actions)
|
|
253
|
+
- `hscli integrators timeline-event-templates` — `/integrators/timeline/v3/{appId}/event/templates`
|
|
254
|
+
- `hscli integrations timeline create,batch-create,update,delete` — `/integrations/v1/application/{appId}/timeline`
|
|
255
|
+
- `hscli crm cards ...` — `/crm/v3/extensions/cards/{appId}` (UI Extension cards)
|
|
256
|
+
- `hscli feature-flags ...` — `/feature/flags/v3/{appId}/flags` (app feature flags)
|
|
257
|
+
- `hscli appinstalls uninstall` — `/appinstalls/v3/external/install`
|
|
258
|
+
|
|
259
|
+
### Developer Test Account
|
|
260
|
+
- `hscli integrations me` — `/integrations/v1/me` (introspect installed app on test portal)
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Zombie endpoints
|
|
265
|
+
|
|
266
|
+
HubSpot retired the legacy **Developer API Key (`hapikey=...` query param)** for
|
|
267
|
+
new accounts in June 2023, but never migrated these endpoints to modern auth.
|
|
268
|
+
They require a legacy hapikey that only old accounts still have:
|
|
269
|
+
|
|
270
|
+
- `/crm/v3/extensions/calling/{appId}/settings/*` — Calling Extensions SDK (3 endpoints)
|
|
271
|
+
- `/crm/v3/extensions/cards/dev/{appId}` — UI Extensions dev preview (2 endpoints)
|
|
272
|
+
- `/crm/v3/extensions/videoconferencing/settings/{appId}` — Video Conf SDK (2 endpoints)
|
|
273
|
+
- `/media-bridge/v1/{appId}/properties/*` — Media Bridge (24 endpoints)
|
|
274
|
+
- `/media-bridge/v1/{appId}/schemas,settings` — Media Bridge infra (6 endpoints)
|
|
275
|
+
- `/crm/v3/timeline/event-templates` (write) — app-level templates
|
|
276
|
+
- A few others in `/integrators/timeline/v3/{appId}` write path
|
|
277
|
+
|
|
278
|
+
**Total: ~40 zombie endpoints** (3.4% of the 1180 API surface).
|
|
279
|
+
|
|
280
|
+
hscli exposes CLI commands for all of them — they're documented, typed, and
|
|
281
|
+
available — but they'll return 401/403 with
|
|
282
|
+
*"This API can't be called using an OAuth access token. A valid developer API
|
|
283
|
+
key must be provided in the `hapikey=` query param"* on any portal that no
|
|
284
|
+
longer has a legacy hapikey.
|
|
285
|
+
|
|
286
|
+
If HubSpot eventually migrates these (GitHub tracker: [HubSpot dev community](https://community.hubspot.com/)),
|
|
287
|
+
hscli will immediately work on them — the commands already exist.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Reporting an endpoint not working
|
|
292
|
+
|
|
293
|
+
If you hit an endpoint that should work on your tier but returns an unexpected
|
|
294
|
+
error, open an issue at [Luigi08001/hscli/issues](https://github.com/revfleet/hscli/issues/new)
|
|
295
|
+
with:
|
|
296
|
+
|
|
297
|
+
1. Your portal's HubSpot plan (Starter / Pro / Enterprise, which Hubs)
|
|
298
|
+
2. The exact `hscli ...` command you ran
|
|
299
|
+
3. The error output (redact tokens)
|
|
300
|
+
4. The HubSpot correlation ID from the response (helps HubSpot debug faster)
|
|
301
|
+
|
|
302
|
+
For zombie endpoints, issues will be tagged `hubspot-platform` and tracked
|
|
303
|
+
separately — they aren't fixable in hscli.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Tier reference: HubSpot official pricing
|
|
308
|
+
|
|
309
|
+
Accurate as of 2026-04-21. Prices in USD, monthly, billed annually:
|
|
310
|
+
|
|
311
|
+
| Hub | Free | Starter | Professional | Enterprise |
|
|
312
|
+
|---|---:|---:|---:|---:|
|
|
313
|
+
| Marketing Hub | ✓ | $20 | $890 | $3,600 |
|
|
314
|
+
| Sales Hub | ✓ | $20 | $90 (seat) | $150 (seat) |
|
|
315
|
+
| Service Hub | ✓ | $20 | $90 (seat) | $150 (seat) |
|
|
316
|
+
| CMS Hub | — | $23 | $400 | $1,500 |
|
|
317
|
+
| Operations Hub | ✓ | $20 | $800 | $2,000 |
|
|
318
|
+
| Commerce Hub | ✓ (limited) | — | $90 (seat) | — |
|
|
319
|
+
|
|
320
|
+
Check [hubspot.com/pricing](https://www.hubspot.com/pricing) for the latest.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Tutorial: Audit every write to your HubSpot portal
|
|
2
|
+
|
|
3
|
+
**Time:** ~10 min
|
|
4
|
+
**Prerequisites:** `hscli` installed, at least one trace file recorded (see the [trace tutorial](trace-replay-repro.md)).
|
|
5
|
+
|
|
6
|
+
You need to answer: "Which agent deleted 40 contacts on Friday?" or "Did any automation write to pipelines outside business hours last quarter?" `hscli audit` rolls up JSONL traces to give you operational auditability without a backend.
|
|
7
|
+
|
|
8
|
+
## Step 0 — ensure traces exist
|
|
9
|
+
|
|
10
|
+
If you haven't recorded yet, start one session:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
hscli trace start
|
|
14
|
+
# ... run some commands, let MCP tools run, etc ...
|
|
15
|
+
hscli trace stop
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Traces are saved as `~/.revfleet/trace-*.jsonl`. `hscli audit` auto-scans that directory by default — no configuration needed.
|
|
19
|
+
|
|
20
|
+
## Step 1 — timeline
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
hscli audit timeline --since 24h
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Chronological event list across every trace file. Useful for "what happened in the last hour / day / week".
|
|
27
|
+
|
|
28
|
+
Flags:
|
|
29
|
+
- `--since 15m | 24h | 7d` — time window (default: all time)
|
|
30
|
+
- `--limit N` — max events to show (default: 100, shown most-recent-first)
|
|
31
|
+
- `--writes-only` — filter to `POST/PUT/PATCH/DELETE`
|
|
32
|
+
- `[file-or-dir]` — positional arg overrides the default `~/.revfleet/` scan
|
|
33
|
+
|
|
34
|
+
## Step 2 — who did what
|
|
35
|
+
|
|
36
|
+
For each profile, get a breakdown by method, status, and path root:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
hscli audit who alice --since 7d
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Output shape:
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"profile": "alice",
|
|
46
|
+
"totalEvents": 412,
|
|
47
|
+
"reads": 380,
|
|
48
|
+
"writes": 32,
|
|
49
|
+
"byMethod": { "GET": 380, "POST": 20, "PATCH": 8, "DELETE": 4 },
|
|
50
|
+
"byStatus": { "200": 390, "201": 18, "400": 2, "500": 2 },
|
|
51
|
+
"byPathRoot": { "crm": 300, "marketing": 80, "cms": 32 },
|
|
52
|
+
"lastTen": [ ... ]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Great for answering "is profile X chatty or abusive?" or "did their error rate spike?".
|
|
57
|
+
|
|
58
|
+
## Step 3 — who touched this path
|
|
59
|
+
|
|
60
|
+
Inverse lookup: a given path pattern, who's been hitting it?
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
hscli audit what /crm/v3/objects/deals --since 7d
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Substring match — `/deals` catches `/crm/v3/objects/deals`, `/crm/v3/objects/deals/123`, `/crm/v3/objects/deals/batch/read`, etc.
|
|
67
|
+
|
|
68
|
+
Output buckets by profile, MCP tool (if the request came from `hscli mcp`), and method. Also lists `recentWrites` — the last 10 write operations against that path.
|
|
69
|
+
|
|
70
|
+
This is the go-to command for incident response: **"An unexpected delete happened on contacts. Who?"**
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
hscli audit what /crm/v3/objects/contacts --since 24h
|
|
74
|
+
# → byProfile: { "alice": 12, "claude-agent": 3 }
|
|
75
|
+
# → byTool: { "crm-batch-delete": 2 }
|
|
76
|
+
# → recentWrites: [ ... with profile, toolName, timestamp ... ]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Step 4 — every write, ever
|
|
80
|
+
|
|
81
|
+
The most security-relevant audit view:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
hscli audit writes --since 24h
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Returns *every* `POST/PUT/PATCH/DELETE` event in the window, counts failed vs successful, and includes a `limit`-capped list. Ideal for daily operator review.
|
|
88
|
+
|
|
89
|
+
## Step 5 — MCP tool breakdown
|
|
90
|
+
|
|
91
|
+
If you're running `hscli mcp` (exposing tools to Claude, Cursor, etc.), every request is tagged with `toolName`. Roll up per tool:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
hscli audit by-tool --since 7d
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Output:
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"totalMcpCalls": 1200,
|
|
101
|
+
"uniqueTools": 28,
|
|
102
|
+
"breakdown": [
|
|
103
|
+
{ "tool": "crm-contacts-list", "calls": 450, "writes": 0, "errors": 2, "errorRate": "0.4%", "avgMs": 180, "maxMs": 520 },
|
|
104
|
+
{ "tool": "crm-contacts-create", "calls": 120, "writes": 120, "errors": 15, "errorRate": "12.5%", "avgMs": 320, "maxMs": 1800 },
|
|
105
|
+
...
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Sorted by call count descending. Quick pattern-matching:
|
|
111
|
+
|
|
112
|
+
- Highest-call-count tool → "which tool is the chatty one"
|
|
113
|
+
- Highest error rate → "which tool is the buggy one" or "which tool is hitting a capability boundary"
|
|
114
|
+
- Highest maxMs → "which tool has tail-latency issues"
|
|
115
|
+
|
|
116
|
+
## Step 6 — combine with `jq` for custom views
|
|
117
|
+
|
|
118
|
+
Every audit command outputs JSON when you pass `--json` (or use `--format json` globally). Pipe into `jq` for ad-hoc queries:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# All 5xx writes in the last day, path + profile + ts
|
|
122
|
+
hscli --json audit writes --since 24h \
|
|
123
|
+
| jq '.data.writes[] | select(.status >= 500) | { ts, profile, method, path, status }'
|
|
124
|
+
|
|
125
|
+
# Top 5 profiles by write count
|
|
126
|
+
hscli --json audit timeline --since 7d --writes-only --limit 10000 \
|
|
127
|
+
| jq '.data.events | group_by(.profile) | map({ profile: .[0].profile, count: length }) | sort_by(-.count) | .[:5]'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Step 7 — feed into CI / Slack / PagerDuty
|
|
131
|
+
|
|
132
|
+
Because everything is JSON-in / JSON-out, you can:
|
|
133
|
+
|
|
134
|
+
- Run `hscli audit writes --since 1h` as a cron job; if any `failedWrites > 0`, POST to Slack.
|
|
135
|
+
- Gate your deploy pipeline on `hscli audit by-tool --since 1h | jq '.data.breakdown[] | select(.errorRate | rtrimstr("%") | tonumber > 5)'` — fail if any tool's error rate spiked.
|
|
136
|
+
- Archive traces to S3 daily for long-term compliance — the format is append-only JSONL, gzip-friendly.
|
|
137
|
+
|
|
138
|
+
## What you get
|
|
139
|
+
|
|
140
|
+
- Every trace file in `~/.revfleet/` becomes a queryable, structured audit log — no DB, no service to run.
|
|
141
|
+
- Five pre-built aggregations (timeline, who, what, writes, by-tool) cover 90% of operator questions.
|
|
142
|
+
- Works whether the traffic came from a human at a terminal, a cron job, or an MCP-connected agent.
|
|
143
|
+
- Combined with [policy-as-code](secure-agent-writes.md), you get "what rule fired, against which request, from which tool, at what time" — in aggregate.
|
|
144
|
+
|
|
145
|
+
## Tips
|
|
146
|
+
|
|
147
|
+
- Trace files retain the HTTP request metadata but not the auth token — safe to share between operators.
|
|
148
|
+
- If you store multiple portals in separate profiles (`hscli --profile prod ...`, `--profile staging ...`), `audit who` naturally segments by portal.
|
|
149
|
+
- For a persistent audit trail, write traces to a shared path (`--out /mnt/shared-audit/trace-$(date +%F-%H%M).jsonl`) and scan with `hscli audit --file /mnt/shared-audit/`.
|
|
150
|
+
- `audit who` and `audit what` return `0` for `totalEvents` when nothing matches — no error, just silence — so they're safe to run in pipelines.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Tutorial: Secure agent writes with policy-as-code
|
|
2
|
+
|
|
3
|
+
**Time:** ~15 min
|
|
4
|
+
**Prerequisites:** `hscli` installed, a HubSpot Private App token authenticated (`hscli auth login --token-stdin`).
|
|
5
|
+
|
|
6
|
+
Agents that write to a production HubSpot portal need guardrails beyond `--force`. This tutorial walks through setting up a policy file so that an MCP-backed agent can read freely, write only to safe paths, require change tickets for risky writes, and be prevented from destructive deletes altogether.
|
|
7
|
+
|
|
8
|
+
## The problem
|
|
9
|
+
|
|
10
|
+
You've connected Claude (or any MCP client) to `hscli mcp` and want it to operate on your live HubSpot portal. Without policy:
|
|
11
|
+
|
|
12
|
+
- The agent could `POST /crm/v3/objects/contacts/gdpr-delete` with a user-provided ID and permanently delete records.
|
|
13
|
+
- Writes are authorised by *whether `--force` was passed*, not *what the write is*.
|
|
14
|
+
- There's no auditable record of *why* a particular write was allowed.
|
|
15
|
+
|
|
16
|
+
`hscli policy` fixes all three.
|
|
17
|
+
|
|
18
|
+
## Step 1 — start from a template
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
hscli policy templates list
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
You should see five built-in templates. For an agent that needs to create and update records but must never delete, start with `no-deletes`:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
hscli policy templates extract no-deletes --to ./policy.json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Open `policy.json` — you'll see a `version: 2` schema with `profiles.default.rules` that allow `GET/POST/PATCH/PUT` and deny all `DELETE`.
|
|
31
|
+
|
|
32
|
+
## Step 2 — tighten for your environment
|
|
33
|
+
|
|
34
|
+
Say you want:
|
|
35
|
+
- Writes on CRM objects only — no CMS, no workflows.
|
|
36
|
+
- `gdpr-delete` and batch archive operations always blocked.
|
|
37
|
+
- Any write during business hours only, US/Eastern.
|
|
38
|
+
- Any PATCH or PUT requires a change ticket ID.
|
|
39
|
+
|
|
40
|
+
Edit `policy.json`:
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"version": 2,
|
|
45
|
+
"profiles": {
|
|
46
|
+
"default": {
|
|
47
|
+
"defaultAction": "deny",
|
|
48
|
+
"rules": [
|
|
49
|
+
{
|
|
50
|
+
"name": "allow-reads",
|
|
51
|
+
"match": { "method": "GET", "path": "**" },
|
|
52
|
+
"action": "allow"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "block-gdpr-delete",
|
|
56
|
+
"match": { "method": "*", "path": "**/gdpr-delete**" },
|
|
57
|
+
"action": "deny"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "block-batch-archive",
|
|
61
|
+
"match": { "method": "POST", "path": "**/batch/archive" },
|
|
62
|
+
"action": "deny"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "allow-crm-writes-with-ticket",
|
|
66
|
+
"match": { "method": "POST", "path": "/crm/v3/objects/**" },
|
|
67
|
+
"action": "allow",
|
|
68
|
+
"requireChangeTicket": true,
|
|
69
|
+
"window": { "tz": "US/Eastern", "hours": "09-17", "days": "mon-fri" }
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"name": "allow-crm-updates-with-ticket",
|
|
73
|
+
"match": { "method": "PATCH", "path": "/crm/v3/objects/**" },
|
|
74
|
+
"action": "allow",
|
|
75
|
+
"requireChangeTicket": true,
|
|
76
|
+
"window": { "tz": "US/Eastern", "hours": "09-17", "days": "mon-fri" }
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Rules are evaluated **first-match-wins**, so order matters. `defaultAction: "deny"` means any method/path not explicitly matched is blocked — safe by default.
|
|
85
|
+
|
|
86
|
+
## Step 3 — validate before shipping
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
hscli policy validate ./policy.json
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This parses the file and flags structural issues (invalid actions, malformed `window.hours`, rules with no `match` block that would match everything). If `valid: true`, you're good.
|
|
93
|
+
|
|
94
|
+
## Step 4 — dry-run rule matching
|
|
95
|
+
|
|
96
|
+
Before enforcing, confirm the right rule fires for the requests you expect:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
hscli --policy-file ./policy.json \
|
|
100
|
+
policy show-matching POST /crm/v3/objects/contacts
|
|
101
|
+
# → matched: allow-crm-writes-with-ticket, effectiveAction: allow
|
|
102
|
+
|
|
103
|
+
hscli --policy-file ./policy.json \
|
|
104
|
+
policy show-matching DELETE /crm/v3/objects/contacts/123
|
|
105
|
+
# → matched: (none), effectiveAction: deny (from defaultAction)
|
|
106
|
+
|
|
107
|
+
hscli --policy-file ./policy.json \
|
|
108
|
+
policy show-matching POST /crm/v3/objects/contacts/gdpr-delete
|
|
109
|
+
# → matched: block-gdpr-delete, effectiveAction: deny
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Step 5 — enforce
|
|
113
|
+
|
|
114
|
+
Either pass `--policy-file` on every invocation, or set it globally:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
export HSCLI_POLICY_FILE=$PWD/policy.json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
From now on, every `hscli` command (and every MCP tool call) runs through the policy. A denied write fails *before* the HTTP request is issued.
|
|
121
|
+
|
|
122
|
+
Try a denied operation:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
hscli --force crm contacts delete 123
|
|
126
|
+
# → POLICY_DEFAULT_DENY: No policy rule matched DELETE /crm/v3/objects/contacts/123
|
|
127
|
+
# and profile default action is 'deny'.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Try an allowed write without a ticket:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
hscli --force crm contacts create --data '{"properties":{"email":"jane@example.com"}}'
|
|
134
|
+
# → POLICY_CHANGE_TICKET_REQUIRED: Policy rule 'allow-crm-writes-with-ticket'
|
|
135
|
+
# requires --change-ticket for POST /crm/v3/objects/contacts.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
With a ticket:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
hscli --force --change-ticket CHG-12345 \
|
|
142
|
+
crm contacts create --data '{"properties":{"email":"jane@example.com"}}'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Step 6 — hook into MCP
|
|
146
|
+
|
|
147
|
+
For Claude Desktop / Cursor / any MCP client, set the env var in the server config so the policy binds to the agent's stdio server:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"mcpServers": {
|
|
152
|
+
"hscli": {
|
|
153
|
+
"command": "hscli",
|
|
154
|
+
"args": ["mcp"],
|
|
155
|
+
"env": {
|
|
156
|
+
"HSCLI_MCP_PROFILE": "default",
|
|
157
|
+
"HSCLI_POLICY_FILE": "/absolute/path/to/policy.json"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Now every tool call the agent makes is filtered through the same rules.
|
|
165
|
+
|
|
166
|
+
## What you get
|
|
167
|
+
|
|
168
|
+
- Every write the agent attempts is auditable against a versioned policy file.
|
|
169
|
+
- Destructive operations (`gdpr-delete`, batch archive) are *structurally* impossible.
|
|
170
|
+
- Change tickets travel with the request and are written to telemetry.
|
|
171
|
+
- Off-hours writes are rejected — no more 2am surprises.
|
|
172
|
+
|
|
173
|
+
## Going further
|
|
174
|
+
|
|
175
|
+
- Pair this with `hscli trace start` (see the [trace tutorial](trace-replay-repro.md)) to record every request + matched rule to a JSONL file.
|
|
176
|
+
- Then use [`hscli audit`](audit-portal-writes.md) to answer questions like "all deletes blocked by policy last 7 days" or "which agent tried the most denied writes".
|
|
177
|
+
- Policy error codes (`POLICY_RULE_DENY`, `POLICY_DEFAULT_DENY`, `POLICY_CHANGE_TICKET_REQUIRED`, `POLICY_APPROVAL_REQUIRED`, `POLICY_OUT_OF_WINDOW`) are machine-readable — parse them in CI to fail builds on denied operations.
|