feat(hubspot): add 27 CRM tools and fix OAuth scope mismatch#3765
feat(hubspot): add 27 CRM tools and fix OAuth scope mismatch#3765waleedlatif1 merged 10 commits intostagingfrom
Conversation
PR SummaryMedium Risk Overview Adds the corresponding HubSpot tool implementations and types. New tools issue the appropriate HubSpot API requests (including pagination and optional associations/properties), extend Fixes OAuth scope mismatches for tickets and improves small API ergonomics. Ticket scope is switched to legacy Written by Cursor Bugbot for commit 0bcdc49. Configure here. |
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Greptile SummaryThis PR adds 27 new HubSpot CRM tools (deals, tickets, line items, quotes, appointments, carts, owners, marketing events, lists) and fixes a critical OAuth scope mismatch that was causing "Authorization failed" errors by removing unregistered Key changes:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[HubSpot Block\noperation param] --> B{Switch on operation}
B --> C[Contacts\nget/create/update/search]
B --> D[Companies\nget/create/update/search/list]
B --> E{get_deals\ndealId?}
B --> F[create_deal / update_deal / search_deals]
B --> G{get_tickets\nticketId?}
B --> H[create_ticket / update_ticket / search_tickets]
B --> I{get_line_items\nlineItemId?}
B --> J[create_line_item / update_line_item]
B --> K{get_quotes\nquoteId?}
B --> L{get_appointments\nappointmentId?}
B --> M[create_appointment / update_appointment]
B --> N{get_carts\ncartId?}
B --> O[list_owners]
B --> P{get_marketing_events\neventId?}
B --> Q{get_lists\nlistId?}
B --> R[create_list]
B --> S[get_users]
E -->|yes| E1[hubspot_get_deal\nGET /crm/v3/objects/deals/:id]
E -->|no| E2[hubspot_list_deals\nGET /crm/v3/objects/deals]
G -->|yes| G1[hubspot_get_ticket\nGET /crm/v3/objects/tickets/:id]
G -->|no| G2[hubspot_list_tickets\nGET /crm/v3/objects/tickets]
I -->|yes| I1[hubspot_get_line_item]
I -->|no| I2[hubspot_list_line_items]
K -->|yes| K1[hubspot_get_quote]
K -->|no| K2[hubspot_list_quotes]
L -->|yes| L1[hubspot_get_appointment]
L -->|no| L2[hubspot_list_appointments]
N -->|yes| N1[hubspot_get_cart]
N -->|no| N2[hubspot_list_carts]
P -->|yes| P1[hubspot_get_marketing_event\nGET /marketing/v3/marketing-events/:id]
P -->|no| P2[hubspot_list_marketing_events\nGET /marketing/v3/marketing-events]
Q -->|yes| Q1[hubspot_get_list\nGET /crm/v3/lists/:id]
Q -->|no| Q2[hubspot_list_lists\nPOST /crm/v3/lists/search]
Reviews (4): Last reviewed commit: "fix(hubspot): return paging in get_users..." | Re-trigger Greptile |
…potCrmObject base type
|
Addressed both review findings: P1 (Marketing Events P2 (Type aliases): Introduced Both fixed in cbc42a3. |
|
@greptile |
|
@cursor review |
…trim, descriptions - Switch marketing event outputs to CRM envelope structure (id, properties, createdAt, updatedAt, archived) matching CRM Objects API - Fix list_lists pagination: add offset param, map offset-based response to paging structure - Add .trim() to contactId/companyId in pre-existing get/update tools - Fix default limit descriptions (100 → 10) in list_contacts/list_companies - Fix operator examples (CONTAINS → CONTAINS_TOKEN) in search_contacts/search_companies - Remove unused params arg in get_users transformResponse Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… per API docs
Marketing Events:
- Revert from /crm/v3/objects/marketing_events back to /marketing/v3/marketing-events
- The Marketing Events API does NOT require appId for GET /marketing-events/{objectId}
- appId is only needed for the /events/{externalEventId} endpoint (which we don't use)
- Restore flat response schema (objectId, eventName, etc. at top level, not CRM envelope)
Lists:
- POST /crm/v3/lists/search uses offset-based pagination (not cursor-based)
- Response shape: { lists, hasMore, offset, total } — not { results, paging }
- Map offset → paging.next.after for consistent block interface
- Fix default count: 20 (not 25), max 500
- GET /crm/v3/lists/{listId} wraps response in { list: { ... } }
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Revert list_contacts/list_companies default limit back to 100 (confirmed by API docs) - Add idProperty param to get_appointment.ts (was missing, inconsistent with update_appointment) - Remove get_carts from idProperty block condition (carts don't support idProperty) - Add get_lists to after block condition (pagination was inaccessible from UI) - Add after pagination param to get_users.ts (was missing, users beyond first page unreachable) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@greptile |
|
@cursor review |
…tion - Add paging output to get_users transformResponse and outputs - Add get_users to block after subBlock condition so cursor is accessible from UI Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@greptile |
|
@cursor review |
Use `?? 0` instead of `?? null` for search tools where the type declares `total: number`. Also declare `total` in list_lists metadata output schema. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(hubspot): add 27 CRM tools and fix OAuth scope mismatch
* lint
* fix(hubspot): switch marketing events to CRM Objects API and add HubSpotCrmObject base type
* chore(docs): fix import ordering and formatting lint errors
* feat(hubspot): wire all 27 new tools into block definition
* fix(hubspot): address review comments - schema mismatch, pagination, trim, descriptions
- Switch marketing event outputs to CRM envelope structure (id, properties, createdAt, updatedAt, archived) matching CRM Objects API
- Fix list_lists pagination: add offset param, map offset-based response to paging structure
- Add .trim() to contactId/companyId in pre-existing get/update tools
- Fix default limit descriptions (100 → 10) in list_contacts/list_companies
- Fix operator examples (CONTAINS → CONTAINS_TOKEN) in search_contacts/search_companies
- Remove unused params arg in get_users transformResponse
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(hubspot): revert to Marketing Events API and fix Lists pagination per API docs
Marketing Events:
- Revert from /crm/v3/objects/marketing_events back to /marketing/v3/marketing-events
- The Marketing Events API does NOT require appId for GET /marketing-events/{objectId}
- appId is only needed for the /events/{externalEventId} endpoint (which we don't use)
- Restore flat response schema (objectId, eventName, etc. at top level, not CRM envelope)
Lists:
- POST /crm/v3/lists/search uses offset-based pagination (not cursor-based)
- Response shape: { lists, hasMore, offset, total } — not { results, paging }
- Map offset → paging.next.after for consistent block interface
- Fix default count: 20 (not 25), max 500
- GET /crm/v3/lists/{listId} wraps response in { list: { ... } }
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(hubspot): final audit fixes verified against API docs
- Revert list_contacts/list_companies default limit back to 100 (confirmed by API docs)
- Add idProperty param to get_appointment.ts (was missing, inconsistent with update_appointment)
- Remove get_carts from idProperty block condition (carts don't support idProperty)
- Add get_lists to after block condition (pagination was inaccessible from UI)
- Add after pagination param to get_users.ts (was missing, users beyond first page unreachable)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(hubspot): return paging in get_users and add to block after condition
- Add paging output to get_users transformResponse and outputs
- Add get_users to block after subBlock condition so cursor is accessible from UI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(hubspot): align total fallback with type definitions in search tools
Use `?? 0` instead of `?? null` for search tools where the type declares
`total: number`. Also declare `total` in list_lists metadata output schema.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
crm.objects.tickets.readandcrm.objects.tickets.write(not registered in HubSpot app config), kept legacyticketsscoperequiredScopesto useticketsinstead ofcrm.objects.tickets.readType of Change
Testing
Tested manually
Checklist